Add 1 đoạn code vào tất cả sub

Liên hệ QC

phuoclocvl

Thành viên thường trực
Tham gia
28/3/12
Bài viết
220
Được thích
32
Dạ Chào Các Anh/ Chị Diến Đàn,

em có 1 câu hỏi mong các Anh/ Chị giúp.

Có cách nào add 1 đoạn code vào tất cả cá Sub trong 1 workbook không ạ?

ví dụ 1 workbook có 5 sub .

Sub 1, 2, ..... 5

add vào mỗi sub đoạn mã như dưới, giả sử vậy

dim Uname as string
Uname ="Doan mau"


xin cảm ơn các Anh/ Chị
 
Chưa hẳn xong đâu.
Còn phải tìm xem các sub's kia. Cái nào có chứa Dim Uname thì xoá đi.
Nhưng nếu muốn gán giá trị của một cell vào thì sao? nó báo lỗi , có cách nào không bác

giả dụ như vầy:

Public Const Uname = Worksheets("User").Range("A2")

xin cảm ơn,
 
Upvote 0
Bạn nên tạo một Hàm như thế này đề gán một Đối tượng hoặc biểu thức.

Function Uname() As Variant
On Error Resume Next​
Uname = Worksheets("User").Range("A2")​
End Function
 
Upvote 0
...
Đúng là dốt tức thiệt , gì cũng không làm được
Bạn đâu có dốt. Chỉ là bạn chủ quan, không chịu nói rõ mục đích của mình từ đầu.
Bạn mở đầu bằng ý định có một đống subs nào đó và nhét các đoạn code in hệt nhau vào. Trong khi thực ra, mục đích của bạn là lấy một giá trị.
Tức là bạn đã in chắc giải thuật vào đầu, và hỏi cách thực hiện. Thay vì nếu nêu rõ mục đích thì ngừoi ta đã nách cho giải thuật.

Cái dốt có thể khắc phục dễ dàng bằng cách chăm học. Cái chủ quan khó chữa lắm.
 
Upvote 0
Bạn đâu có dốt. Chỉ là bạn chủ quan, không chịu nói rõ mục đích của mình từ đầu.
Cũng có thể không phải là chủ quan mà là thiếu kỹ năng. Nhiều người không biết diễn đạt ý của mình sao cho người khác có thể hiểu được.
Tôi cho rằng đã đến lúc cần phải đòi hỏi chứng chỉ. Tất nhiên không phải chứng chỉ 'tiền hôn nhân' :D
Khi đăng ký thì phải có bản photo chứng chỉ. Rằng đã qua một khóa học về cách mô tả vấn đề, có kỹ năng giao tiếp tối thiểu. Nếu không có chứng chỉ thì chỉ được đọc, không được hỏi. :D
 
Upvote 0
Bạn đâu có dốt. Chỉ là bạn chủ quan, không chịu nói rõ mục đích của mình từ đầu.
Bạn mở đầu bằng ý định có một đống subs nào đó và nhét các đoạn code in hệt nhau vào. Trong khi thực ra, mục đích của bạn là lấy một giá trị.
Tức là bạn đã in chắc giải thuật vào đầu, và hỏi cách thực hiện. Thay vì nếu nêu rõ mục đích thì ngừoi ta đã nách cho giải thuật.

Cái dốt có thể khắc phục dễ dàng bằng cách chăm học. Cái chủ quan khó chữa lắm.
Hi bạn, cảm ơn bạn nhiều lắm, thực sự mình không biết diễn đạt sao á chứ, vì mình có nhiều sub mà chúng lại dùng lại 1 thứ nên muốn chỉ cần viết 1 lần và áp dụng cho tất cả các sub, nhưng không biết cách nào nên hỏi vậy, vì hiện tại mình cứ copy vào tất cả các sub câu giống như vậy á. Thiệt là tệ hại mà hic hic
 
Upvote 0
...Khi đăng ký thì phải có bản photo chứng chỉ. Rằng đã qua một khóa học về cách mô tả vấn đề, có kỹ năng giao tiếp tối thiểu. Nếu không có chứng chỉ thì chỉ được đọc, không được hỏi. :D
Hổng dám đâu bác ơi.
Thứ nhất, giá trị của diễn đàn có liên hệ tuyến tính alpha dương với số lượt truy cập và số bài. Mọt vấn đề cần cả chục bài mới giải quyết xong thfi chỉ có lợi cho đàn chủ chứ không có hại.
Thứ hai, diễn đàn cũng được đánh giá qua lượng thành viên.
Thứ ba, hổng cho đăng ký thì ngừoi ta nhờ hỏi giùm hoặc mượn nít. Cái vụ "hỏi giùm thằng em..." và thành viên kỳ cựu chục năm ngớ ngẩn như trẻ con ở đây nhiều như quân Nguyên.
 
Upvote 0
Hổng dám đâu bác ơi.
Thứ nhất, giá trị của diễn đàn có liên hệ tuyến tính alpha dương với số lượt truy cập và số bài. Mọt vấn đề cần cả chục bài mới giải quyết xong thfi chỉ có lợi cho đàn chủ chứ không có hại.
Thứ hai, diễn đàn cũng được đánh giá qua lượng thành viên.
Thứ ba, hổng cho đăng ký thì ngừoi ta nhờ hỏi giùm hoặc mượn nít. Cái vụ "hỏi giùm thằng em..." và thành viên kỳ cựu chục năm ngớ ngẩn như trẻ con ở đây nhiều như quân Nguyên.
Ừ nhỉ. Bác nói có lý. Tóm lại, lợi ích của diễn đàn và lợi ích của một nhóm thành viên nào đấy có thể xung đột nhau.
Về chuyện lách luật thì dân ta là bậc thầy rồi. :D
 
Upvote 0
Bạn nên tạo một Hàm như thế này đề gán một Đối tượng hoặc biểu thức.

Function Uname() As Variant
On Error Resume Next​
Uname = Worksheets("User").Range("A2")​
End Function
Dạ khi mình viết như vậy, ở mỗi sub có cần thêm gì ở mỗi sub nữa không ạ?
Xin cảm ơn
 
Upvote 0
Như thế này nó hiểu không Anh ơi

Set Db = New Connection
Db.CursorLocation = adUseClient

If Db.State = 1 Then Db.Close
On Error GoTo loi
Db.Open "Provider =IBMDASQL.DataSource.1" & _
";Catalog Library List=JDETSTDTA" & _
";Persist Security Info=True" & _
";Force Translate=0" & _
";Data Source = WFVNPROD" & _
";User ID =" & Uname & "" & _
";Password =" & Upass
 
Upvote 0
Như thế này nó hiểu không Anh ơi

Set Db = New Connection
Db.CursorLocation = adUseClient

If Db.State = 1 Then Db.Close
On Error GoTo loi
Db.Open "Provider =IBMDASQL.DataSource.1" & _
";Catalog Library List=JDETSTDTA" & _
";Persist Security Info=True" & _
";Force Translate=0" & _
";Data Source = WFVNPROD" & _
";User ID =" & Uname & "" & _
";Password =" & Upass
Cứ thử sẽ biết ngay: thường thì người ta viết Uname()
 
Upvote 0
Như thế này nó hiểu không Anh ơi

Set Db = New Connection
Db.CursorLocation = adUseClient

If Db.State = 1 Then Db.Close
On Error GoTo loi
Db.Open "Provider =IBMDASQL.DataSource.1" & _
";Catalog Library List=JDETSTDTA" & _
";Persist Security Info=True" & _
";Force Translate=0" & _
";Data Source = WFVNPROD" & _
";User ID =" & Uname & "" & _
";Password =" & Upass

Tôi nghĩ là bạn đang bị luẩn quẩn giữa biến với hàm.
Cách thông thường tôi hay làm đối với việc tham chiếu Username và Password là:
- Mở một module (vd: modUserPass), khai báo biến toàn cục cho User, Pass, Level. Sau đó viết hàm để lấy User/Pass/Level như bạn Hesanbi đã hướng dẫn.

Mã:
Public UserName As String
Public UserID As String
Public UserLevel As String
Public UserPass As String

Option Explicit

Function GetUserName()
    GetUserName = UserName
End Function

Function GetUserID()
    GetUserID = UserID
End Function

Function GetUserLevel()
    GetUserLevel = UserLevel
End Function

Function GetUserPass()
    GetUserPass = UserPass
End Function

- Ở Form đăng nhập sẽ gán thông tin User/Pass cho biến toàn cục đã khai báo là: UserName, UserPass, UserLevel (nếu có phân quyền). Ở trường hợp của bạn là lấy từ Sheet thì cũng làm tương tự.
Ví dụ: khi bấm nút [Kết nối]
Mã:
Private Sub cmdKetNoi_Click()
   UserName = Worksheets("Users").Range("A2").Value2
   UserPass = Worksheets("Users").Range("B2").Value2
   UserLevel = Worksheets("Users").Range(C2").Value2
   ...

End Sub

- Sau đó nếu các thủ tục, hàm nào cần tham chiếu đến User/Pass thì dùng hàm GetUserName(), GetUserPass() để lấy hoặc có thể dùng luôn biến toàn cục này (có trường hợp chỉ có thể dùng hàm câu lệnh mới hiểu) .
Ví dụ:

Mã:
Global oCnn As Object
Dim blnNewConnect As Boolean

blnNewConnect = True
If Not oCnn Is Nothing Then   'Kiem tra xem có Connection chua, có rôi thi dung ket noi cu
   If oCnn.State And adStateOpen = 1 Then  '-> Da có ket noi
      blnNewConnect = False
   End If
End If

If blnNewConnect Then
Set oCnn = New ADODB.Connection
oCnn.CursorLocation = adUseClient
oCnn.Open "Provider =IBMDASQL.DataSource.1" & _
                                     ";Catalog Library List=JDETSTDTA" & _
                                     ";Persist Security Info=True" & _
                                     ";Force Translate=0" & _
                                     ";Data Source = WFVNPROD" & _
                                     ";User ID =" & UserName & "" & _
                                     ";Password =" & UserPass
...
...
 
Upvote 0
Không hẳn đúng. Nói là bớt thì đúng hơn.
Trong các Sub/Function cần sử dụng Uname thì phải xoá cái dòng Dim Uname đi.

Cứ thử sẽ biết ngay: thường thì người ta viết Uname()
Hầu hết các phiên bản BASIC đều cho phép gọi tên hàm/sub mà không cần dấu ngoặc.
Người ta sẽ veiets Uname và không viết Uname() nếu người ta muốn tự giữ trường hợp về sau này đổi ý, dùng Uname theo biến nội trong Sub.
Thường thì lúc đó, người ta sẽ viết thêm một hàm Private để gọi hàm Uname() kia. Trường hợp này tôi đã đề cập trước đây; tức là tuỳ theo mức độ "hằng" của thông số uname. (nếu hàm Uname luôn luôn trả về 1 trị thì nó coi như hằng, nếu nó có thay đổi, ví dụ nó đọc trị từ đâu đó, thì đương nhiên phải coi nó là biến)

Tôi nghĩ là bạn đang bị luẩn quẩn giữa biến với hàm.
...
Không hẳn thớt bị lẩn quẩn biến với hàm. Theo tôi thì thớt bị lẫn lộn do một tính chất đặc biệt của ngôn ngữ BASIC: cho phép gọi hàm bằng tên, hiểu ngầm hai dấu ngoặc. Người đề nghị dùng Uname như hàm đã lợi dụng tính chất này để đơn giản hoá ách áp dụng vào code có sẵn của thớt. Chỉ là:

Yêu cầu của thớt "giảm thiểu những dòng code lặp lại trong các sub's" đòi hỏi phải có hiểu biết căn bản về tầm vực của các tên gọi (scope of identifiers).
Để có thể dùng Uname mà không phải lặp lại code khai báo và gán trị trong các sub's thì bắt buộc Uname phải có tầm vực toàn cục (global). Và có ba cách để thực hiện:
1. khai báo nó là hằng (const) toàn cục. Cách này chỉ thực hiện được khi nó là hằng.
2. cách khai báo nó như một biến toàn cục. Và dùng một mô đun chung nào đó để gán trị. Cách này hơi rắc rối ở chỗ gán trị.
3. cách dụng nó thành một hàm để tự lấy trị.
Tôi đã từng giải thích việc lợi hại của từng cách rồi. Nhắc lại ở đây chỉ thừa.

...Cách thông thường tôi hay làm đối với việc tham chiếu Username và Password là:
- Mở một module (vd: modUserPass), khai báo biến toàn cục cho User, Pass, Level. Sau đó viết hàm để lấy User/Pass/Level như bạn Hesanbi đã hướng dẫn.
...
1. mở riêng một mô đun cho biến toàn cục là mọt cách quản lý tầm vực biến/hằng rất hay. Nhưng nó chỉ hay khi người dùng luôn luôn tiền tố các biến/hằng với tên mô đun. Ví dụ: ModuleX.Uname. Rất tiếc là trong VBA, biến toàn cục luôn luôn là toàn cục. Bạn không có cách nào buộc ngừoi viết code phải tiền tố như vậy. Cách người ta khuyên dùng là tự tiền tố các biến ấy. Ví dụ:
Trong Module GLOBAL_1:
Public G1_Uname As String
Đại khái, khi ở mô đun khác, nhìn vào tên thì có thể đoán nó được khai báo trong Mô đun có tên G*1*...

2. Nếu các biến có cùng nhóm, có phận sự gần nhau thì nên nhóm chúng lại. Và trường hợp nhóm thì cách quản lý tốt nhất là dùng class module.

Trong trường hợp bạn có một nhóm hàm ở bài trên thì cũng nên bỏ chút thì giờ suy nghĩ "có nên dùng class module hay không?"
 
Lần chỉnh sửa cuối:
Upvote 0
Không hẳn đúng. Nói là bớt thì đúng hơn.
Trong các Sub/Function cần sử dụng Uname thì phải xoá cái dòng Dim Uname đi.


Hầu hết các phiên bản BASIC đều cho phép gọi tên hàm/sub mà không cần dấu ngoặc.
Người ta sẽ veiets Uname và không viết Uname() nếu người ta muốn tự giữ trường hợp về sau này đổi ý, dùng Uname theo biến nội trong Sub.
Thường thì lúc đó, người ta sẽ viết thêm một hàm Private để gọi hàm Uname() kia. Trường hợp này tôi đã đề cập trước đây; tức là tuỳ theo mức độ "hằng" của thông số uname. (nếu hàm Uname luôn luôn trả về 1 trị thì nó coi như hằng, nếu nó có thay đổi, ví dụ nó đọc trị từ đâu đó, thì đương nhiên phải coi nó là biến)


Không hẳn thớt bị lẩn quẩn biến với hàm. Theo tôi thì thớt bị lẫn lộn do một tính chất đặc biệt của ngôn ngữ BASIC: cho phép gọi hàm bằng tên, hiểu ngầm hai dấu ngoặc. Người đề nghị dùng Uname như hàm đã lợi dụng tính chất này để đơn giản hoá ách áp dụng vào code có sẵn của thớt. Chỉ là:

Yêu cầu của thớt "giảm thiểu những dòng code lặp lại trong các sub's" đòi hỏi phải có hiểu biết căn bản về tầm vực của các tên gọi (scope of identifiers).
Để có thể dùng Uname mà không phải lặp lại code khai báo và gán trị trong các sub's thì bắt buộc Uname phải có tầm vực toàn cục (global). Và có ba cách để thực hiện:
1. khai báo nó là hằng (const) toàn cục. Cách này chỉ thực hiện được khi nó là hằng.
2. cách khai báo nó như một biến toàn cục. Và dùng một mô đun chung nào đó để gán trị. Cách này hơi rắc rối ở chỗ gán trị.
3. cách dụng nó thành một hàm để tự lấy trị.
Tôi đã từng giải thích việc lợi hại của từng cách rồi. Nhắc lại ở đây chỉ thừa.


1. mở riêng một mô đun cho biến toàn cục là mọt cách quản lý tầm vực biến/hằng rất hay. Nhưng nó chỉ hay khi người dùng luôn luôn tiền tố các biến/hằng với tên mô đun. Ví dụ: ModuleX.Uname. Rất tiếc là trong VBA, biến toàn cục luôn luôn là toàn cục. Bạn không có cách nào buộc ngừoi viết code phải tiền tố như vậy. Cách người ta khuyên dùng là tự tiền tố các biến ấy. Ví dụ:
Trong Module GLOBAL_1:
Public G1_Uname As String
Đại khái, khi ở mô đun khác, nhìn vào tên thì có thể đoán nó được khai báo trong Mô đun có tên G*1*...

2. Nếu các biến có cùng nhóm, có phận sự gần nhau thì nên nhóm chúng lại. Và trường hợp nhóm thì cách quản lý tốt nhất là dùng class module.

Trong trường hợp bạn có một nhóm hàm ở bài trên thì cũng nên bỏ chút thì giờ suy nghĩ "có nên dùng class module hay không?"
Vâng cảm ơn bác nhiều,
Nhưng thật ra em vẫn chưa hiểu được hết :(
 
Upvote 0
2. Nếu các biến có cùng nhóm, có phận sự gần nhau thì nên nhóm chúng lại. Và trường hợp nhóm thì cách quản lý tốt nhất là dùng class module.
Trong trường hợp bạn có một nhóm hàm ở bài trên thì cũng nên bỏ chút thì giờ suy nghĩ "có nên dùng class module hay không?"

Chính xác là vậy bác. Bên Access thì phần lớn các ứng dụng điều phải có quản lý User, nên em dùng class để quản lý nó gọn.
Cũng khai báo class trong module, khi khởi động ứng dụng là gọi luôn.
Public oUser As New clsUser

Với các phương thức, thuộc tính như:

Mã:
oUser.Username
oUser.Password
oUser.Level
oUser.Authenticated
oUser.Add
...

Dùng class vì có nhiều thuộc tính liên quan tới đối tượng User. Bên Excel thì ít thấy các bạn dùng nên cũng chỉ demo cách dùng đơn giản của công tác quản lý đăng nhập thôi đó anh.
 
Upvote 0
Vâng cảm ơn bác nhiều,
Nhưng thật ra em vẫn chưa hiểu được hết :(
Nói ngắn như vậy không đủ để bạn hiểu đâu.
Ở diễn đàn này có một bài, của bạn nào tôi quên mất rồi, viết về tầm vực của biến. Bạn tìm bài ấy mà đọc thử. Hy vọng bài ấy viết khá đầy đủ.

Hiện tại thì bạn chỉ cần làm hai việc:
- Viết hai cái Function Uname và Upass gì đó.
- Xoá tất cả các chỗ Dim Uname, Upass (*) trong các Sub's
Hết

Chú thích: tìm đọc thử trong quyển "Lập Trình VBA..." của ông bạn bên BlueSoft.
Nếu không thấy phần "tầm vực của các tên đặt (biến, hàm, ...) thì là sách thiếu sót. Quý vị nên đề nghị tác giả phổ cập.

(*) đọc cái tên Upass sao nghe rờn rợn. "passing urine" có nghĩa là đi tiểu.
 
Upvote 0
Web KT
Back
Top Bottom