Thiết lập tiêu đề cho Listbox bằng VBA ? (1 người xem)

Người dùng đang xem chủ đề này

sealand

Thành viên gạo cội
Tham gia
16/5/08
Bài viết
4,882
Được thích
7,687
Giới tính
Nam
Nghề nghiệp
Kế Toán
Mình loay hoay mãi mà không được nên đưa lên đây mọi người hỗ trợ:

Giả sử trên Form có Listbox1. Listbox1 có 2 cột là MaVT và TenVT.

Các lệnh thiết lập listbox như sau:
1/ Lệnh AddItems và List để tạo các dòng trên Listbox1
2/Lệnh cho hiện tiêu đề cột của Listbox là: Listbox1.ColumnHeads=True

Giờ để Listbox có dòng tiêu đề cột 1 là Mã VT và tiêu đề cột 2 là Tên VT ta làm thế nào ?
 
Mình loay hoay mãi mà không được nên đưa lên đây mọi người hỗ trợ:

Giả sử trên Form có Listbox1. Listbox1 có 2 cột là MaVT và TenVT.

Các lệnh thiết lập listbox như sau:
1/ Lệnh AddItems và List để tạo các dòng trên Listbox1
2/Lệnh cho hiện tiêu đề cột của Listbox là: Listbox1.ColumnHeads=True

Giờ để Listbox có dòng tiêu đề cột 1 là Mã VT và tiêu đề cột 2 là Tên VT ta làm thế nào ?

Em đã nhiều lần thí nghiệm thì không thành, nhưng em làm như sau:

Giả sử A1:B1 là hàng tiêu đề

Từ A2:B10 là các giá trị

Chỉ có chọn thuộc tính ROWSOURCE mới có thể có tiêu đề hiện lên thôi.

Với RowSource = A2:B10

Thuộc tính ColumnHead = True (tự động nó hiểu A1:B1 là tiêu đề)
 
Upvote 0
Làm như vậy cũng bất tiện, trên data sheet ta thường đặt tên cột có tính gợi ý và thật gọn. Việc này ảnh hưởng rất lớn như câu lệnh SQL chẳng hạn. Mình muốn khi tạo Form mình có thể tuỳ ngữ cảnh cơ. Ví dụ : Trên form cho phiếu xuất là Mã hàng xuất còn khi nhập lại là Mã hàng nhập
 
Upvote 0
Làm như vậy cũng bất tiện, trên data sheet ta thường đặt tên cột có tính gợi ý và thật gọn. Việc này ảnh hưởng rất lớn như câu lệnh SQL chẳng hạn. Mình muốn khi tạo Form mình có thể tuỳ ngữ cảnh cơ. Ví dụ : Trên form cho phiếu xuất là Mã hàng xuất còn khi nhập lại là Mã hàng nhập

Đành phải chịu thôi chứ thuộc tính của nó là như vậy rồi! Thôi thì Anh làm trên ListView sẽ tốt hơn ạ (chỉ khó chịu là convert chữ Việt).

Em không thích ListBox ở chỗ tự điều chỉnh độ cao của nó, lúc lên lúc xuống; còn chọn thuộc tính ListBox1.IntegralHeight = False thì khi mình dùng Scroll sẽ không hết hàng, rất khó chịu chỗ đó.
 
Lần chỉnh sửa cuối:
Upvote 0
Đây là 1 cách mình đã lợi dụng cách dùng Rowsource, nhưng không hiểu tại sao nó lại cố tình không hiểu mà lại thiết lập tiêu đề thành Column 1

[GPECODE=vb]Private Sub Reset_MaTK()
Dim Sh As Worksheet
Me.ListBox1.ColumnHeads = True
Application.DisplayAlerts = False
Set Sh = ThisWorkbook.Worksheets.Add
Sh.[A1] = "Ma TK"
Sheet1.[E2:E10].Copy Sh.[A2]
Me.ListBox1.RowSource = Sh.Name & "!A1:A10"
Sh.Delete
Application.DisplayAlerts = True
End Sub[/GPECODE]

Không hiểu sao với code này mình chỉ thêm tạm 1 sheet chép dữ liệu vào làm rowsource cho Listbox xong rồi xoá đi mà máy báo thiếu bộ nhớ ?
 
Lần chỉnh sửa cuối:
Upvote 0
Đây là 1 cách mình đã lợi dụng cách dùng Rowsource, nhưng không hiểu tại sao nó lại cố tình không hiểu mà lại thiết lập tiêu đề thành Column 1

[GPECODE=vb]Private Sub Reset_MaTK()
Dim Sh As Worksheet
Me.ListBox1.ColumnHeads = True
Application.DisplayAlerts = False
Set Sh = ThisWorkbook.Worksheets.Add
Sh.[A1] = "Ma TK"
Sheet1.[E2:E10].Copy Sh.[A2]
Me.ListBox1.RowSource = Sh.Name & "!A1:A10"
Sh.Delete
Application.DisplayAlerts = True
End Sub[/GPECODE]

Không hiểu sao với code này mình chỉ thêm tạm 1 sheet chép dữ liệu vào làm rowsource cho Listbox xong rồi xoá đi mà máy báo thiếu bộ nhớ ?

Chổ này:
Me.ListBox1.RowSource = Sh.Name & "!A1:A10"
Anh sửa thành:
Me.ListBox1.RowSource = Sh.Name & "!A2:A10"
nhé
 
Upvote 0
Chổ này:
Me.ListBox1.RowSource = Sh.Name & "!A1:A10"
Anh sửa thành:
Me.ListBox1.RowSource = Sh.Name & "!A2:A10"
nhé

Không phải Ndu ơi, A1 là mình đặt tiêu đề còn từ A2 dến A10 là các dòng của Listbox, hay là nó tự nhạn tiêu đề nhỉ để mình test lại đã

P/S:
Ồ, lẩm cẩm thật. Được rồi Ndu ơi, nhưng còn vấn đề tổn bộ nhớ là sao nhỉ.
 
Lần chỉnh sửa cuối:
Upvote 0
Chổ này:
Me.ListBox1.RowSource = Sh.Name & "!A1:A10"
Anh sửa thành:
Me.ListBox1.RowSource = Sh.Name & "!A2:A10"
nhé

Thì đó, như em đã nói tại bài này:

Em đã nhiều lần thí nghiệm thì không thành, nhưng em làm như sau:

Giả sử A1:B1 là hàng tiêu đề

Từ A2:B10 là các giá trị

Chỉ có chọn thuộc tính ROWSOURCE mới có thể có tiêu đề hiện lên thôi.

Với RowSource = A2:B10

Thuộc tính ColumnHead = True (tự động nó hiểu A1:B1 là tiêu đề)

Có thể Anh Sealand muốn tạo một chương trình gì đó mới mẽ bằng ListBox đây!

Còn em thì em thích với ListView, nó thật đa dạng!
 
Lần chỉnh sửa cuối:
Upvote 0
Không phải Ndu ơi, A1 là mình đặt tiêu đề còn từ A2 dến A10 là các dòng của Listbox, hay là nó tự nhạn tiêu đề nhỉ để mình test lại đã

P/S:
Ồ, lẩm cẩm thật. Được rồi Ndu ơi, nhưng còn vấn đề tổn bộ nhớ là sao nhỉ.

Sao em test thử lại không báo thiếu bộ nhớ vậy anh?

----------------------------------------------------------------
Phần thêm:

Em kiểm tra rồi, khi bấm nút lần 2 sẽ thông báo bộ nhớ không đủ.

Cách khắc phục như sau:

Mã:
Private Sub Reset_MaTK()
    Dim Sh As Worksheet
    Me.ListBox1.ColumnHeads = True
    Application.DisplayAlerts = False
    Set Sh = ThisWorkbook.Worksheets.Add
    Sh.[A1] = "Ma TK"
    Sheet1.[E2:E10].Copy Sh.[A2]
    Me.ListBox1.RowSource = Sh.Name & "!A2:A10"
    Sh.Delete
    [COLOR=#ff0000][B]Set Sh = Nothing[/B][/COLOR]
    Application.DisplayAlerts = True
End Sub

Thêm dòng màu đỏ sẽ hết bị tình trạng đó.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Sao em test thử lại không báo thiếu bộ nhớ vậy anh?

----------------------------------------------------------------
Phần thêm:

Em kiểm tra rồi, khi bấm nút lần 2 sẽ thông báo bộ nhớ không đủ.

Cách khắc phục như sau:

Mã:
Private Sub Reset_MaTK()
    Dim Sh As Worksheet
    Me.ListBox1.ColumnHeads = True
    Application.DisplayAlerts = False
    Set Sh = ThisWorkbook.Worksheets.Add
    Sh.[A1] = "Ma TK"
    Sheet1.[E2:E10].Copy Sh.[A2]
    Me.ListBox1.RowSource = Sh.Name & "!A2:A10"
    Sh.Delete
    [COLOR=#ff0000][B]Set Sh = Nothing[/B][/COLOR]
    Application.DisplayAlerts = True
End Sub

Thêm dòng màu đỏ sẽ hết bị tình trạng đó.
Trên máy tôi, bấm đúng 100 lần cũng chẳng có thông báo gì cả
Chắc tại BỘ NHỚ của Nghĩa và anh sealand bị.. LÃO HÓA rồi cũng không chừng
Ẹc... Ẹc...
 
Upvote 0
Upvote 0
Hi em,
Đúng là cũng hay, nhưng nếu em phát triển ứng dụng, một khi có nâng cấp gì bộ office là coi như... em ngồi khóc luôn.
Chính vì vậy sau này anh không dùng ListView đó nữa.

Lê Văn Duyệt

Xin được các bạn giải thích cụ thể hạn chế của ListView khi nâng cấp office? Mình thích dùng ListView vì sử dụng được chuột phải khi danh sách dài
 
Upvote 0
Trên máy tôi, bấm đúng 100 lần cũng chẳng có thông báo gì cả
Chắc tại BỘ NHỚ của Nghĩa và anh sealand bị.. LÃO HÓA rồi cũng không chừng
Ẹc... Ẹc...

Em thử trên Excel 2003 và chắc máy của anh Sealand cũng vậy nên mới có trường hợp bị lỗi trên!

Vậy mới biết được rằng phải thử code trên nhiều phiên bản để khắc phục lỗi từ những phiên bản trước.

Đồng thời, giải phóng bộ nhớ cũng rất quan trọng!

Hi em,
Đúng là cũng hay, nhưng nếu em phát triển ứng dụng, một khi có nâng cấp gì bộ office là coi như... em ngồi khóc luôn.
Chính vì vậy sau này anh không dùng ListView đó nữa.

Lê Văn Duyệt

Em cũng muốn biết nó bị lỗi gì sau khi nâng cấp, em đã xài ListView trên 2003 và 2007 vẫn ổn định. Anh cho em biết bị lỗi gì anh nhé. Cám ơn Anh.
 
Upvote 0
Em thử trên Excel 2003 và chắc máy của anh Sealand cũng vậy nên mới có trường hợp bị lỗi trên!

Vậy mới biết được rằng phải thử code trên nhiều phiên bản để khắc phục lỗi từ những phiên bản trước.

Đồng thời, giải phóng bộ nhớ cũng rất quan trọng!



Em cũng muốn biết nó bị lỗi gì sau khi nâng cấp, em đã xài ListView trên 2003 và 2007 vẫn ổn định. Anh cho em biết bị lỗi gì anh nhé. Cám ơn Anh.

Đại khái ý là nếu dùng ListView từ 2003 lên 2007 thì nó vẫn xài được anh. Nhưng mà file đã chạy từ máy 2007 (dù là file xls) nhưng khi chuyển qua máy 2003 thì máy đó sẽ không xài được ListView.
 
Upvote 0
Đại khái ý là nếu dùng ListView từ 2003 lên 2007 thì nó vẫn xài được anh. Nhưng mà file đã chạy từ máy 2007 (dù là file xls) nhưng khi chuyển qua máy 2003 thì máy đó sẽ không xài được ListView.

Kỳ vậy ta? Anh thường thiết kế trên máy 2007 khi save lại ở dạng 97-2003, rồi thực hiện trên cả 2 loại 2003-2007 vẫn không có một dấu hiệu nào khác thường.

Anh sử dụng ListView trong thư viện Microsoft Windows Common Controls 6.0 (SP6).
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    53.9 KB · Đọc: 275
Upvote 0
Kỳ vậy ta? Anh thường thiết kế trên máy 2007 khi save lại ở dạng 97-2003, rồi thực hiện trên cả 2 loại 2003-2007 vẫn không có một dấu hiệu nào khác thường.

Anh sử dụng ListView trong thư viện Microsoft Windows Common Controls 6.0 (SP6).
Không phải đâu anh, tức là anh thiết kế file trên máy có Office 2003 và Office 2007 (hoặc 07 thôi) rồi anh save ở định dạng xls thì anh mở file đó trên máy anh, dù là 03 hay 07 đều không sao. Tuy nhiên, nếu anh đem file đó qua máy chỉ cài Office 03 thôi, thì nó sẽ không chạy được ListView.
 
Upvote 0
Em thử trên Excel 2003 và chắc máy của anh Sealand cũng vậy nên mới có trường hợp bị lỗi trên!

Vậy mới biết được rằng phải thử code trên nhiều phiên bản để khắc phục lỗi từ những phiên bản trước.

Đồng thời, giải phóng bộ nhớ cũng rất quan trọng!
.

Nghĩa thử lại code này xem còn lỗi không
Mã:
Private Sub Reset_MaTK()
  Me.ListBox1.ColumnHeads = True
  Application.DisplayAlerts = False
  With ThisWorkbook.Worksheets.Add
    .Range("A1") = "Ma TK"
    Sheet1.Range("E2:E10").Copy .Range("A2")
    Me.ListBox1.RowSource = .Name & "!A2:A10"
    .Delete
  End With
  Application.DisplayAlerts = True
End Sub
Tôi cũng không chắc nhưng cứ thí nghiệm xem thế nào
 
Upvote 0
Vẫn lỗi Ndu à, khi load lên thì khôn sao nhưng khi chọn 1 item nào đó là sinh chuyện
 
Upvote 0
Không phải đâu anh, tức là anh thiết kế file trên máy có Office 2003 và Office 2007 (hoặc 07 thôi) rồi anh save ở định dạng xls thì anh mở file đó trên máy anh, dù là 03 hay 07 đều không sao. Tuy nhiên, nếu anh đem file đó qua máy chỉ cài Office 03 thôi, thì nó sẽ không chạy được ListView.

Không biết các máy khác như thế nào, máy anh thiết kế chỉ dùng 1 office 2007 và save as thành 2003, đem file này qua máy chỉ có 2003 vẫn xài listview được, không những thế, anh đã thử trên nhiều máy 2003 ở cơ quan qua mạng nội bộ, máy 2003 nào cũng xài không bị lỗi gì!
 
Upvote 0
Bây giờ mình làm thử một UserForm có ListView tại máy chỉ có Excel 2007, mình Save As về định dạng 97-2003 (.xls), các bạn có máy sử dụng Excel 2003 tải về và chạy thử xem có lỗi gì không làm ơn chụp hình lỗi lại cho mình xem nhé!

Nhân tiện với ListView khi Add tiêu đề cột, có thể sẽ bực mình vì chuyện độ rộng của từng cột, mình muốn chia sẽ một kinh nghiệm Add nhanh cho nó như sau:

Thông thường mình Add tiêu đề dựa trên một bảng dữ liệu tại sheet nào đó, mình chia độ rộng tại đây đã chuẩn, vì vậy ta lợi dụng điểm này để dùng vòng lặp Add tiêu đề cho nhanh.

Đồng thời cũng nên chú trọng đến Font Size mà chia tỷ lệ cho nó hợp lý:

Thay vì:

[GPECODE=vb] With Sheet1.Range("A1")
ListView1.ColumnHeaders.Add , , .Value, 120
ListView1.ColumnHeaders.Add , , .Offset(, 1).Value, 100
ListView1.ColumnHeaders.Add , , .Offset(, 2).Value, 70
ListView1.ColumnHeaders.Add , , .Offset(, 3).Value, 120
ListView1.ColumnHeaders.Add , , .Offset(, 4).Value, 110
ListView1.ColumnHeaders.Add , , .Offset(, 5).Value, 115
ListView1.ColumnHeaders.Add , , .Offset(, 6).Value, 120
End With
[/GPECODE]

Thì ta chỉ dùng vòng lặp và độ rộng sẳn có của cột làm độ rộng của ListView luôn:

[GPECODE=vb] With Sheet1.Range("A1")
SizeRate = ListView1.Font.Size / .Font.Size
For c = 0 To 6
With .Offset(, c)
ListView1.ColumnHeaders.Add , , .Value, .Width * SizeRate
End With
Next
End With
[/GPECODE]
 

File đính kèm

Upvote 0
Bây giờ mình làm thử một UserForm có ListView tại máy chỉ có Excel 2007, mình Save As về định dạng 97-2003 (.xls), các bạn có máy sử dụng Excel 2003 tải về và chạy thử xem có lỗi gì không làm ơn chụp hình lỗi lại cho mình xem nhé!

Nhân tiện với ListView khi Add tiêu đề cột, có thể sẽ bực mình vì chuyện độ rộng của từng cột, mình muốn chia sẽ một kinh nghiệm Add nhanh cho nó như sau:

Thông thường mình Add tiêu đề dựa trên một bảng dữ liệu tại sheet nào đó, mình chia độ rộng tại đây đã chuẩn, vì vậy ta lợi dụng điểm này để dùng vòng lặp Add tiêu đề cho nhanh.

Đồng thời cũng nên chú trọng đến Font Size mà chia tỷ lệ cho nó hợp lý:

Thay vì:

[GPECODE=vb] With Sheet1.Range("A1")
ListView1.ColumnHeaders.Add , , .Value, 120
ListView1.ColumnHeaders.Add , , .Offset(, 1).Value, 100
ListView1.ColumnHeaders.Add , , .Offset(, 2).Value, 70
ListView1.ColumnHeaders.Add , , .Offset(, 3).Value, 120
ListView1.ColumnHeaders.Add , , .Offset(, 4).Value, 110
ListView1.ColumnHeaders.Add , , .Offset(, 5).Value, 115
ListView1.ColumnHeaders.Add , , .Offset(, 6).Value, 120
End With
[/GPECODE]

Thì ta chỉ dùng vòng lặp và độ rộng sẳn có của cột làm độ rộng của ListView luôn:

[GPECODE=vb] With Sheet1.Range("A1")
SizeRate = ListView1.Font.Size / .Font.Size
For c = 0 To 6
With .Offset(, c)
ListView1.ColumnHeaders.Add , , .Value, .Width * SizeRate
End With
Next
End With
[/GPECODE]

Mình đưa vào máy chỉ có Ex2003, vẫn nạp dữ liệu được bình thường, cũng chẳng cần References gì cả (mở trên máy của một đồng nghiệp chưa từng biết code là gì).

Thế trường hợp nào đưa listview qua máy khác phải References hả Nghĩa, có phải là trường hợp máy cài Office không đầy đủ? Để mình xóa Office cài thiếu lại thử xem và tìm cách khắc phục ra sao.
 
Upvote 0
Thế trường hợp nào đưa listview qua máy khác phải References hả Nghĩa, có phải là trường hợp máy cài Office không đầy đủ? Để mình xóa Office cài thiếu lại thử xem và tìm cách khắc phục ra sao.
Trường hợp máy chưa có cái này: MSCOMCTL.OCX
Lúc đó dù có References gì gì đó cũng không được (có đâu mà tìm)
Vậy thì phải downoad thằng em MSCOMCTL.OCX về cho vào System32 rồi đăng ký thôi anh à!
 
Upvote 0
Trường hợp máy chưa có cái này: MSCOMCTL.OCX
Lúc đó dù có References gì gì đó cũng không được (có đâu mà tìm)
Vậy thì phải downoad thằng em MSCOMCTL.OCX về cho vào System32 rồi đăng ký thôi anh à!

Biết là do không có file OCX đó trong System32 nhưng mình chưa gặp máy không xử dụng được ListVier lần nào nên muốn biết vì sao nó thiếu, có khả năng cái OCX này dùng chung, khi Remove chương trình khác nó lại xóa theo luôn, hoặc cài chương trình khác thì nó lại chép đè một OCX cùng tên lên nhưng không dùng được. Mình đã từng gặp trường hợp đụng hàng giữa VB6 và Acad.
 
Upvote 0
Biết là do không có file OCX đó trong System32 nhưng mình chưa gặp máy không xử dụng được ListVier lần nào nên muốn biết vì sao nó thiếu, có khả năng cái OCX này dùng chung, khi Remove chương trình khác nó lại xóa theo luôn, hoặc cài chương trình khác thì nó lại chép đè một OCX cùng tên lên nhưng không dùng được. Mình đã từng gặp trường hợp đụng hàng giữa VB6 và Acad.

Chính xác là cái màu đỏ đấy anh, máy em cài đầy đủ, update bình thường, thế nhưng khi cài một cái Tool nào đó làm mình mất luôn cả cái Addition luôn!
 
Upvote 0
Xin được các bạn giải thích cụ thể hạn chế của ListView khi nâng cấp office? Mình thích dùng ListView vì sử dụng được chuột phải khi danh sách dài

Cho em hỏi kỹ lại một tí, dùng chuột phải trên ListView là sao anh? Hay anh muốn nói dùng Scroll-Wheel (bánh xe lăn) của chuột?

Nếu dùng bánh xe cho ListBox, ComboBox, anh tham khảo tại bài này:

http://www.giaiphapexcel.com/forum/...ó-thể-sử-dụng-mouse-wheel&p=456996#post456996
 
Lần chỉnh sửa cuối:
Upvote 0
Cho em hỏi kỹ lại một tí, dùng chuột phải trên ListView là sao anh? Hay anh muốn nói dùng Scroll-Wheel (bánh xe lăn) của chuột?

Nếu dùng bánh xe cho ListBox, ComboBox, anh tham khảo tại bài này:

http://www.giaiphapexcel.com/forum/showthread.php?74588-T%E1%BA%B7ng-c%C3%A1c-b%E1%BA%A1n-validation-combo-box-c%C3%B3-th%E1%BB%83-s%E1%BB%AD-d%E1%BB%A5ng-mouse-wheel&p=456996#post456996

Đúng rồi, dùng bánh xe để tìm trong danh sách. Bài bên đó hay nhỉ, nhưng code có vẻ phức tạp. Vậy theo Nghĩa nên dùng LissView hay Listbox? Theo mình thì mình dùng ListView, tối giản code được chừng nào hay chừng đó.
 
Upvote 0
Không biết các máy khác như thế nào, máy anh thiết kế chỉ dùng 1 office 2007 và save as thành 2003, đem file này qua máy chỉ có 2003 vẫn xài listview được, không những thế, anh đã thử trên nhiều máy 2003 ở cơ quan qua mạng nội bộ, máy 2003 nào cũng xài không bị lỗi gì!
Vậy hả anh? Cái này em cũng không biết nữa. Nhà em thì hầu hết các máy đều bị lỗi, chỉ có dùng Office 2007 thì mới không lỗi. Vậy chắc để em nghiên cứu lại vấn đề này, thấy mọi người không có bị lỗi này :(
 
Upvote 0

Thử bới tí bèo xem có ra bọ không.
Tôi muốn xét code ở bài #10 trong đường dẫn trên.
-------------
Có một nguyên tắc chính trong chung sống cộng đồng là: hãy sống và cho phép mọi người khác cũng sống. Mọi tài nguyên, của cải chung anh có thể sử dụng, nhu cầu tới đâu sử dụng tới đó. Nhưng cũng để người khác có quyền như vậy. Nếu anh chiếm công viên, máy rút tiền cho riêng mình thôi là không được.
Windows là hệ đa nhiệm. Cùng lúc có thể hoạt động nhiều ứng dụng. Nếu mọi tài nguyên anh chiếm làm của riêng là không được. Trừ những việc "đặc thù" mà anh làm thì bình thường anh cứ dùng thoải mái, nhưng không được chiếm làm của riêng. Chẳng hạn nếu anh mở Clipboard (của chung) nhưng anh không đóng tức là không có ứng dụng nào có thể sử dụng clipboard được nữa.
Vậy thì hãy dùng, hãy hưởng bao nhiêu anh muốn nhưng sau đó cho phép "người khác" cũng có quyền đó.
------------
Code Hook tôi thấy chưa chuẩn lắm. Windows là hệ đa nhiệm, có nhiều ứng dụng cùng chạy và user nhiều khi "nhẩy" từ ứng dụng này sang ứng dụng khác, làm việc mỗi nơi một lúc. Người lập trình không thể giả thiết là user chạy xong ứng dụng này rồi mới chuyển sang ứng dụng khác. Vd. anh ta có thể nhập một số dữ liệu trong A --> chuyển sang B --> cuộn cửa sổ B tới dữ liệu cần thiết --> copy vào bộ nhớ đệm --> chuyển về A --> dán vào chỗ cần thiết.
Trong code ta có Hook, nhưng nhu cầu của ta không cần tới "cắt cơm, cúp điện" của người khác. Ta cần nắm bắt thời điểm "bánh xe chuột lăn" thì ta được Windows cung cấp, nhưng làm xong những việc cần làm thì phải cho những người cũng như mình - tức cũng cần nắm bắt thời điểm "bánh xe chuột lăn" trong ứng dụng của họ - làm những việc của họ chứ. Hiện thời thì code Hook "cắt cơm, cúp điện" của người khác.
Các bạn hãy mở UserForm --> click vào ListBox --> mở một tài liệu dài bằng notepad --> quay bánh xe chuột trong notepad. Chắc chắn cửa sổ notepad không được cuộn. Vì code trong hook đã "ngắt" không cho Windows thông báo cho notepad sự kiện "bánh xe chuột lăn".
Trong th của ta thì chả có nhu cầu cắt cơm cúp điện notepad, vậy ta phải gọi CallNextHookEx, tức 2 dòng sau cho vào thành chú thích

Mã:
'            LowLevelMouseProc = -1
'            Exit Function

Tóm lại cần chú ý khi viết code. Chỉ trừ những trường hợp cần thiết khi ta cần viết những code "đặc thù", khi ta cần "ngắt" chuỗi thông báo sự kiện không cho những người khác "xếp hàng sau ta" nhận được sự kiện đó. Tức việc "ngắt" là chủ ý vì một lý do "chính đáng" nào đó. Trong mọi trường hợp còn lại thì phải gọi CallNextHookEx để "những người" xếp hàng chờ đợi sự kiện sau ta cũng nhận được thông báo. Nếu không thì "họ" sẽ thao tác sai.
------------
Có một cái buồn cười là nếu ta kích hoạt notepad bên cạnh UserForm rồi quay bánh xe trong notepad thì ListBox trong UserForm được cuộn. Hoặc quay bánh xe lăn ở bất cứ đâu trên màn hình (desktop, Start, khay hệ thống, thanh tác vụ, thanh tiêu đề ... ) thì cũng như thế. Có "chuyện lạ" như thế vì hook trong code được thiết lập cho toàn system, tức "nắm bắt" sự kiện chuột ở mọi nơi - do giá trị 0 của thông số cuối cùng trong hàm SetWindowsHookEx:

Mã:
 lLowLevelMouse = SetWindowsHookEx _
        (WH_MOUSE_LL, AddressOf LowLevelMouseProc, GetAppInstance,[COLOR=#ff0000] [B]0[/B][/COLOR])

Để thiết lập hook chỉ cho ứng dụng của "ta" thì phải truyền "identifier of the thread with which the hook procedure is to be associated". Tức bình thường thì code là:

Mã:
 lLowLevelMouse = SetWindowsHookEx _
        (WH_MOUSE, AddressOf LowLevelMouseProc, 0, [B][COLOR=#ff0000]GetCurrentThreadId[/COLOR][/B])

Đấy là nói về WH_MOUSE còn WH_MOUSE_LL chỉ có thể thiết lập cho toàn system (global).
 
Lần chỉnh sửa cuối:
Upvote 0
Thử bới tí bèo xem có ra bọ không.
Tôi muốn xét code ở bài #10 trong đường dẫn trên.
-------------

Mã:
'            LowLevelMouseProc = -1
'            Exit Function

Tóm lại cần chú ý khi viết code. Chỉ trừ những trường hợp cần thiết khi ta cần viết những code "đặc thù", khi ta cần "ngắt" chuỗi thông báo sự kiện không cho những người khác "xếp hàng sau ta" nhận được sự kiện đó. Tức việc "ngắt" là chủ ý vì một lý do "chính đáng" nào đó. Trong mọi trường hợp còn lại thì phải gọi CallNextHookEx để "những người" xếp hàng chờ đợi sự kiện sau ta cũng nhận được thông báo. Nếu không thì "họ" sẽ thao tác sai.
------------
Có một cái buồn cười là nếu ta kích hoạt notepad bên cạnh UserForm rồi quay bánh xe trong notepad thì ListBox trong UserForm được cuộn. Hoặc quay bánh xe lăn ở bất cứ đâu trên màn hình (desktop, Start, khay hệ thống, thanh tác vụ, thanh tiêu đề ... ) thì cũng như thế. Có "chuyện lạ" như thế vì hook trong code được thiết lập cho toàn system, tức "nắm bắt" sự kiện chuột ở mọi nơi - do giá trị 0 của thông số cuối cùng trong hàm SetWindowsHookEx:

Mã:
 lLowLevelMouse = SetWindowsHookEx _
        (WH_MOUSE_LL, AddressOf LowLevelMouseProc, GetAppInstance,[COLOR=#ff0000] [B]0[/B][/COLOR])

Để thiết lập hook chỉ cho ứng dụng của "ta" thì phải truyền "identifier of the thread with which the hook procedure is to be associated". Tức bình thường thì code là:

Mã:
 lLowLevelMouse = SetWindowsHookEx _
        (WH_MOUSE, AddressOf LowLevelMouseProc, 0, [B][COLOR=#ff0000]GetCurrentThreadId[/COLOR][/B])

Đấy là nói về WH_MOUSE còn WH_MOUSE_LL chỉ có thể thiết lập cho toàn system (global).

Code tại bài đó không phải em viết, mà em cũng chẳng có trình độ để viết, em chỉ ứng dụng và thấy xài được.

Tuy nhiên có một điều em rất đang thắc mắc và e ngại khi dùng code này, nếu không trả nó về FALSE thì những "con lăn" ở các ứng dụng khác xem như "cứng đơ" ra (MakeScrollableWithMouseWheel(ListBox1) = False)

Tính tới trường hợp người ta dùng Ctrl+Break để tạm ngưng sử dụng code thì làm sao trả về cho nó False được!

Vậy theo Thầy, có thể thay đổi hay cải tiến cho trường hợp này không? Hơn thế nữa, có thể xài trên scroll trên "chuột cảm ứng" laptop được như ta thực hiện với ListView được không ạ?

Xin cám ơn Thầy.
 
Upvote 0
Code tại bài đó không phải em viết, mà em cũng chẳng có trình độ để viết, em chỉ ứng dụng và thấy xài được.

Tuy nhiên có một điều em rất đang thắc mắc và e ngại khi dùng code này, nếu không trả nó về FALSE thì những "con lăn" ở các ứng dụng khác xem như "cứng đơ" ra (MakeScrollableWithMouseWheel(ListBox1) = False)

Tính tới trường hợp người ta dùng Ctrl+Break để tạm ngưng sử dụng code thì làm sao trả về cho nó False được!

Vậy theo Thầy, có thể thay đổi hay cải tiến cho trường hợp này không? Hơn thế nữa, có thể xài trên scroll trên "chuột cảm ứng" laptop được như ta thực hiện với ListView được không ạ?

Xin cám ơn Thầy.

Chuyện trước khi đóng UserForm thì phải "gỡ" hook là đương nhiên. Thiết lập hook --> làm việc --> xong việc --> gỡ hook. Nó như là dậy bé: bầy đồ chơi ra --> chơi thỏa thích --> hết chơi --> dọn đồ gọn gàng.
Trong suốt quá trình làm việc thì để con lăn không bị "đơ" khi user chuyển sang ứng dụng khác thì tôi đã viết rồi: 2 dòng ... phải loại bỏ.
Nhưng như thế thì khi user lăn chuột ở ứng dụng khác thì ListBox của ta cũng cuộn theo.
Có thể: trong procedure hook kiểm tra vị trí trỏ chuột --> nếu trỏ chuột nằm trong vùng làm việc của UserForm (client area) thì cuộn ListBox và thêm 2 dòng kia. Code dưới đây chỉ là 1 ví dụ thôi:

[GPECODE=vb]
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Declare Function ScreenToClient Lib "user32.dll" (ByVal hwnd As Long, ByRef lpPoint As POINTAPI) As Long
Private Declare Function GetClientRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function PtInRect Lib "user32.dll" (ByRef lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long

Function LowLevelMouseProc _
(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim pt As POINTAPI, h As Long, mst As MSLLHOOKSTRUCT, rc As RECT
Static iTopIndex As Integer

On Error Resume Next

If (nCode = HC_ACTION) Then
If wParam = WM_MOUSEWHEEL Then
With oObject
mst = GetHookStruct(lParam)
pt = mst.pt
h = FindWindow("ThunderDFrame", vbNullString)
ScreenToClient h, pt
GetClientRect h, rc
If PtInRect(rc, pt.x, pt.y) Then
If mst.mousedata > 0 Then
.TopIndex = iTopIndex - 1
iTopIndex = .TopIndex
Else
.TopIndex = iTopIndex + 1
iTopIndex = .TopIndex
End If
LowLevelMouseProc = -1
Exit Function
End If
End With
End If
End If

LowLevelMouseProc = _
CallNextHookEx(lLowLevelMouse, nCode, wParam, ByVal lParam)

End Function
[/GPECODE]
 
Upvote 0
Đúng rồi, dùng bánh xe để tìm trong danh sách. Bài bên đó hay nhỉ, nhưng code có vẻ phức tạp. Vậy theo Nghĩa nên dùng LissView hay Listbox? Theo mình thì mình dùng ListView, tối giản code được chừng nào hay chừng đó.

Theo quan điểm của em thì ListBox và ListView đều có các mặt mạnh và hạn chế riêng.

Với ListBox, không kén font nguồn nên không phải convert nếu máy có font đó; nạp list bằng mảng rất nhanh, không cần vòng lặp gì cả (ListBox1.List = Rang("A1:D10").Value), nó có thuộc tính RowSource để liên kết từ Sheet đến ListBox.

Hạn chế của nó là không có Gridline, có tiêu đề cột nhưng chỉ dựa vào RowSource, thanh cuộn (scrollbar) không tự xài scrollwheel của chuột được như các scrollbar khác, hình thức sơ sài, không định dạng được màu trong 1 item của list (định dạng ban đầu thế nào thì ra thế đó thôi); tự điều chỉnh độ cao của nó khi ta đặt chiều cao so với số dòng (ListRow) mà nó hiển thị không đúng (điều này làm cho ta sắp xếp trên Form có thể không đẹp mắt).

Với ListView thì về hình thức đẹp, thanh cuộn mượt mà, sử dụng thanh cuộn kiểu nào cũng ổn (vì thanh cuộn có khả năng co giản để phù hợp với số hàng nên không làm co giản độ cao của ListView); có gridline; định dạng màu sắc, font chữ (lớn, nhỏ, đậm, nghiêng) từng mục trong list; ngoại trừ cột đầu tiên, ta có thể định dạng canh trái, canh phải, canh giữa cho từng cột; có tiêu đề cột và thông qua đó nó như là một nút lệnh, có thể sort theo mục trong cột đó; có nhiều kiểu View cho đối tượng này v.v...

Hạn chế lớn nhất của ListView khiến nhiều người quay lưng với nó là không hỗ trợ font Unicode, vì thế khi sử dụng nó ta cần phải chuyển về một font nào đó mà nó có thể hiển thị được tiếng Việt. Ngoài ra khi Add tiêu đề cũng như nội dung thì không thể làm trực tiếp như ListBox mà phải Add từng mục một. Có thuộc tính RowSource rồi RowSourceType nhưng xem ra không xài được (có thể phải đăng ký nó như thế nào đó mới cho xài, thử bấm vào mục Custom trong properties sẽ thấy).

Cho nên, khi thực hiện bất cứ công việc gì, tùy vào hoàn cảnh và cách bố trí trên form mà ta chọn ListView hay ListBox anh nhé!
 
Lần chỉnh sửa cuối:
Upvote 0
Chuyện trước khi đóng UserForm thì phải "gỡ" hook là đương nhiên. Thiết lập hook --> làm việc --> xong việc --> gỡ hook. Nó như là dậy bé: bầy đồ chơi ra --> chơi thỏa thích --> hết chơi --> dọn đồ gọn gàng.
Trong suốt quá trình làm việc thì để con lăn không bị "đơ" khi user chuyển sang ứng dụng khác thì tôi đã viết rồi: 2 dòng ... phải loại bỏ.
Nhưng như thế thì khi user lăn chuột ở ứng dụng khác thì ListBox của ta cũng cuộn theo.
Có thể: trong procedure hook kiểm tra vị trí trỏ chuột --> nếu trỏ chuột nằm trong vùng làm việc của UserForm (client area) thì cuộn ListBox và thêm 2 dòng kia.

Thầy ơi, nhờ code cải tiến của Thầy mà nó đã trở nên rất tiện ích, em không e ngại gì khi dùng nữa! Cám ơn Thầy rất nhiều!

Nhưng cho em hỏi, với scrollbar của NotePad mình có thể dùng chuột cảm ứng của laptop, nhưng cái này thì chỉ dùng được với scroll wheel thôi. Vậy Thầy có thể cải tiến thêm cho nó được không? (chỉ là "được voi đòi tiên" nhưng nếu có thể thì Thầy cũng thử một lần xem sao Thầy nhé!).

Một lần nữa em cám ơn Thầy rất nhiều.
 
Upvote 0
Theo quan điểm của em thì ListBox và ListView đều có các mặt mạnh và hạn chế riêng.

Với ListBox, không kén font nguồn nên không phải convert nếu máy có font đó; nạp list bằng mảng rất nhanh, không cần vòng lặp gì cả (ListBox1.List = Rang("A1:D10").Value), nó có thuộc tính RowSource để liên kết từ Sheet đến ListBox.

Hạn chế của nó là không có Gridline, có tiêu đề cột nhưng chỉ dựa vào RowSource, thanh cuộn (scrollbar) không tự xài scrollwheel của chuột được như các scrollbar khác, hình thức sơ sài, không định dạng được màu trong 1 item của list (định dạng ban đầu thế nào thì ra thế đó thôi); tự điều chỉnh độ cao của nó khi ta đặt chiều cao so với số dòng (ListRow) mà nó hiển thị không đúng (điều này làm cho ta sắp xếp trên Form có thể không đẹp mắt).

Với ListView thì về hình thức đẹp, thanh cuộn mượt mà, sử dụng thanh cuộn kiểu nào cũng ổn (vì thanh cuộn có khả năng co giản để phù hợp với số hàng nên không làm co giản độ cao của ListView); có gridline; định dạng màu sắc, font chữ (lớn, nhỏ, đậm, nghiêng) từng mục trong list; ngoại trừ cột đầu tiên, ta có thể định dạng canh trái, canh phải, canh giữa cho từng cột; có tiêu đề cột và thông qua đó nó như là một nút lệnh, có thể sort theo mục trong cột đó; có nhiều kiểu View cho đối tượng này v.v...

Hạn chế lớn nhất của ListView khiến nhiều người quay lưng với nó là không hỗ trợ font Unicode, vì thế khi sử dụng nó ta cần phải chuyển về một font nào đó mà nó có thể hiển thị được tiếng Việt. Ngoài ra khi Add tiêu đề cũng như nội dung thì không thể làm trực tiếp như ListBox mà phải Add từng mục một. Có thuộc tính RowSource rồi RowSourceType nhưng xem ra không xài được (có thể phải đăng ký nó như thế nào đó mới cho xài, thử bấm vào mục Custom trong properties sẽ thấy).

Cho nên, khi thực hiện bất cứ công việc gì, tùy vào hoàn cảnh và cách bố trí trên form mà ta chọn ListView hay ListBox anh nhé!

Một bài tổng hợp kinh nghiệm, so sánh giữa ListBox và ListView mà không sách vở nào có được. Cảm ơn Nghĩa!
 
Upvote 0
Thầy ơi, nhờ code cải tiến của Thầy mà nó đã trở nên rất tiện ích, em không e ngại gì khi dùng nữa! Cám ơn Thầy rất nhiều!

Nhưng cho em hỏi, với scrollbar của NotePad mình có thể dùng chuột cảm ứng của laptop, nhưng cái này thì chỉ dùng được với scroll wheel thôi. Vậy Thầy có thể cải tiến thêm cho nó được không? (chỉ là "được voi đòi tiên" nhưng nếu có thể thì Thầy cũng thử một lần xem sao Thầy nhé!).

Một lần nữa em cám ơn Thầy rất nhiều.

Chuột này khác chuột kia thì kể cũng lạ.
Tôi không có chuột cảm ứng và laptop nên muốn nghiên cứu cũng đành chịu.
Tôi viết lại theo cách mới. Thực ra ta không cần theo dõi sự kiện chuột trong toàn system mà chỉ trong phạm vi ứng dụng của ta. Khi chuột được lăn trong cửa sổ của ta thì thông điệp WM_MOUSEWHEEL sẽ được gửi tới hàm cửa sổ của UserForm (window procedure). Vậy chỉ cần "đánh tráo" hàm cửa sổ để xử lý thông điệp WM_MOUSEWHEEL.
Tóm lại ta dùng công nghệ "Window Subclassing" thay cho hook. Với cách này thì lăn chuột trong UserForm hay notepad không ảnh hưởng tới nhau. Code này lại còn đơn giản hơn hook.
Trong code sau và trong tập tin đính kèm là code đầy đủ để chạy. Nhưng tôi thêm 1 dòng (mầu đỏ) để test thông điệp được gửi tới hàm cửa sổ. Vậy sau khi test xong thì dòng này xóa đi cho khỏi nhàm code.
Bạn hãy: Kích hoạt UserForm1 (bấm Button 1) --> chọn 1 mục trong ListBox hoặc nhấn tam giác của Combobox --> lăn chuột vài lần --> copy và dán lên GPE những dòng mà Debug.Print ghi trong cửa sổ Immediate để tôi xem.

Module:

[GPECODE=vb]
Option Explicit

Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_WNDPROC = (-4)
Private Const WM_MOUSEMOVE As Long = &H200
Private Const WM_VSCROLL = &H115
Private Const WM_MOUSEWHEEL = &H20A

Public OldWindowProc As Long
Public obj As Object

Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Static TopIndex As Integer
Dim mousedata As Integer
On Error GoTo end_

If uMsg = WM_MOUSEWHEEL Or uMsg = WM_VSCROLL Then Debug.Print CStr(uMsg)

If uMsg = WM_MOUSEWHEEL And Not obj Is Nothing Then
mousedata = wParam \ 65536
With obj
If mousedata > 0 Then
.TopIndex = TopIndex - 1
TopIndex = .TopIndex
Else
.TopIndex = TopIndex + 1
TopIndex = .TopIndex
End If
Exit Function
End With
End If
end_:
WindowProc = CallWindowProc(OldWindowProc, hwnd, uMsg, wParam, lParam)
End Function

Sub SetWindowProc(ByVal hWin As Long, ByVal DoSet As Boolean)
If DoSet Then
If OldWindowProc = 0 Then
OldWindowProc = SetWindowLong(hWin, GWL_WNDPROC, AddressOf WindowProc)
End If
ElseIf OldWindowProc <> 0 Then
SetWindowLong hWin, GWL_WNDPROC, OldWindowProc
OldWindowProc = 0
End If
End Sub
[/GPECODE]

UserForm:

[GPECODE=vb]
Private hWin As Long

Private Sub ComboBox1_Enter()
Set obj = ComboBox1
End Sub

Private Sub ComboBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Set obj = Nothing
End Sub

Private Sub ListBox1_Enter()
Set obj = ListBox1
End Sub

Private Sub ListBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Set obj = Nothing
End Sub

Private Sub UserForm_Initialize()
hWin = FindWindow("ThunderDFrame", Me.Caption)
SetWindowProc hWin, True
End Sub

Private Sub UserForm_Terminate()
SetWindowProc hWin, False
End Sub
[/GPECODE]
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Chuột này khác chuột kia thì kể cũng lạ.
Tôi không có chuột cảm ứng và laptop nên muốn nghiên cứu cũng đành chịu.
Tôi viết lại theo cách mới. Thực ra ta không cần theo dõi sự kiện chuột trong toàn system mà chỉ trong phạm vi ứng dụng của ta. Khi chuột được lăn trong cửa sổ của ta thì thông điệp WM_MOUSEWHEEL sẽ được gửi tới hàm cửa sổ của UserForm (window procedure). Vậy chỉ cần "đánh tráo" hàm cửa sổ để xử lý thông điệp WM_MOUSEWHEEL.
Tóm lại ta dùng công nghệ "Window Subclassing" thay cho hook. Với cách này thì lăn chuột trong UserForm hay notepad không ảnh hưởng tới nhau. Code này lại còn đơn giản hơn hook.
Trong code sau và trong tập tin đính kèm là code đầy đủ để chạy. Nhưng tôi thêm 1 dòng (mầu đỏ) để test thông điệp được gửi tới hàm cửa sổ. Vậy sau khi test xong thì dòng này xóa đi cho khỏi nhàm code.
Bạn hãy: Kích hoạt UserForm1 (bấm Button 1) --> chọn 1 mục trong ListBox hoặc nhấn tam giác của Combobox --> lăn chuột vài lần --> copy và dán lên GPE những dòng mà Debug.Print ghi trong cửa sổ Immediate để tôi xem.

Trên máy tính bàn, Window XP, tại cửa sổ Immediate, các thao tác trên ListBox cũng như trên ComboBox đều cho kết quả số giống nhau là 522.

Cám ơn Thầy đã cải tiến. Để em thử với laptop xem sao.

===============================

Kiểm tra trên Window 7, máy laptop, thao tác trên chuột ảo, kết quả thật "quái chiêu" là TRÊN CẢ TUYỆT VỜI!!!

Em không ngờ, Thầy không có máy tính để thử scroll ảo của mousepad cảm ứng, vậy mà Thầy vẫn thành công! Quá siêu mà!

Tại đây cũng cho ra giá trị 522 Thầy nhé!

Cám ơn Thầy rất rất nhiều!
 
Lần chỉnh sửa cuối:
Upvote 0
Tuyệt!
Mình thử cũng vậy, khi lăn chuột thì được các số 522, khi bấm các nút tam giác thì không in ra cửa sổ Immediate gì cả
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
522
Thử xong, xin mạn phép cho thêm lệnh này
Mã:
Private Sub UserForm_Activate()
    ListBox1.SetFocus
End Sub
 
Upvote 0
Thầy ơi, cho em hỏi, Thầy cần kiểm tra cái này với mục đích gì?

copy và dán lên GPE những dòng mà Debug.Print ghi trong cửa sổ Immediate để tôi xem.

Và sau khi em đã thử với 2 máy tính, kết quả chỉ cho ra đúng 1 con số là 522, vậy nó mang ý nghĩa gì ạ?
 
Lần chỉnh sửa cuối:
Upvote 0
Thầy ơi, cho em hỏi, Thầy cần kiểm tra cái này với mục đích gì?



Và sau khi em đã thử với 2 máy tính, kết quả chỉ cho ra đúng 1 con số là 522, vậy nó mang ý nghĩa gì ạ?

522 thì chuẩn rồi - Private Const WM_MOUSEWHEEL = &H20A = 522
522 là thông điệp WM_MOUSEWHEEL
 
Upvote 0
522 thì chuẩn rồi - Private Const WM_MOUSEWHEEL = &H20A = 522
522 là thông điệp WM_MOUSEWHEEL

Cho em hỏi thêm, Trong Hàm có dòng này:

mousedata = wParam \ 65536

Với số đó có nghĩa là gì ạ? Hay là chia theo số hàng của sheet? Nếu vậy thì Excel 2007 có phải chia lại không?
 
Upvote 0
Anh Siwtom ơi. Khi Form đang được Show, nếu bị lỗi khi chạy code thì không Debug được, Excel bị treo, phải dùng Ctrl+Alt+Delete để thoát Excel.
 
Upvote 0
Anh Siwtom ơi. Khi Form đang được Show, nếu bị lỗi khi chạy code thì không Debug được, Excel bị treo, phải dùng Ctrl+Alt+Delete để thoát Excel.

Anh có thể cho biết anh đang bị lỗi gì và những thủ tục anh gán lên trên form là gì không?
 
Upvote 0
Ví dụ thay vì chạy code
Mã:
Private Sub UserForm_Activate()
ListBox1.SetFocus
ListBox1.ListIndex = [COLOR=#ff0000]ListBox1.ListCount - 1
[/COLOR]End Sub
Mình chạy code (do ListIndex bắt đầu từ 0 nên vượt 1 dòng)
Mã:
Private Sub UserForm_Activate()
ListBox1.SetFocus
ListBox1.ListIndex = [COLOR=#ff0000]ListBox1.ListCount[/COLOR]
End Sub
Hoặc cố tình cho một câu lệnh sai nào đó hoặc Form đang Show lại tạm dừng (bấm Ctrl+Pause). Nếu gặp lỗi mình nhờ anh siwtom cho câu lệnh để bẩy lỗi (có lẽ là SetWindowProc hWin, False), trả lại nguyên trạng ban đầu, còn nếu tạm dừng, e rằng không có thuốc chữa!
 
Lần chỉnh sửa cuối:
Upvote 0
Ví dụ thay vì chạy code
Mã:
Private Sub UserForm_Activate()
ListBox1.SetFocus
ListBox1.ListIndex = [COLOR=#ff0000]ListBox1.ListCount - 1
[/COLOR]End Sub
Mình chạy code (do ListIndex bắt đầu từ 0 nên vượt 1 dòng)
Mã:
Private Sub UserForm_Activate()
ListBox1.SetFocus
ListBox1.ListIndex = [COLOR=#ff0000]ListBox1.ListCount[/COLOR]
End Sub
Hoặc cố tình cho một câu lệnh sai nào đó hoặc Form đang Show lại tạm dừng (bấm Ctrl+Pause). Nếu gặp lỗi mình nhờ anh siwtom cho câu lệnh để bẩy lỗi (có lẽ là SetWindowProc hWin, False), trả lại nguyên trạng ban đầu, còn nếu tạm dừng, e rằng không có thuốc chữa!

Chuyện Excel bị treo đâu có phải chỉ khi có SetWindowProc?
Bạn chưa gặp trường hợp khi code có lỗi thì Excel bị treo tới mức không Debug được, không đóng bình thường được, thậm chí dùng Ctrl + Alt + Del cũng phải vài lần mới đóng được.
Vậy câu hỏi là: liệu có thể làm thế nào để khi gặp lỗi thì vẫn luôn debug được hoặc đóng Excel bình thường? Và câu hỏi đó phải đặt chung cho mọi người. "Bệnh" như bạn kể đâu phải là "độc quyền" hay tính chất của riêng SetWindowProc? Tất nhiên khi dùng window subclassing mà cố tình gây lỗi thì "bệnh" nguy hiểm hơn.
Theo tôi bạn cứ viết code cẩn thận, những chỗ có thể có lỗi thì phải bẫy lỗi. Nhưng con người không lường được hết mọi trường hợp, viết chuẩn 100%, vậy đôi khi bị treo Excel thì chấp nhận thôi.
Cái Ctrl + Pause của bạn thì tôi nghĩ không ít trường hợp chả có SetWindowProc mà vẫn treo máy.

Tôi hỏi ngoài lề một chút: đôi khi bạn có nhu cầu nhấn Ctrl + Pause à? Để làm gì vậy?
 
Lần chỉnh sửa cuối:
Upvote 0
Chuyện Excel bị treo đâu có phải chỉ khi có SetWindowProc?
Bạn chưa gặp trường hợp khi code có lỗi thì Excel bị treo tới mức không Debug được, không đóng bình thường được, thậm chí dùng Ctrl + Alt + Del cũng phải vài lần mới đóng được.
Vậy câu hỏi là: liệu có thể làm thế nào để khi gặp lỗi thì vẫn luôn debug được hoặc đóng Excel bình thường? Và câu hỏi đó phải đặt chung cho mọi người. "Bệnh" như bạn kể đâu phải là "độc quyền" hay tính chất của riêng SetWindowProc? Tất nhiên khi dùng window subclassing mà cố tình gây lỗi thì "bệnh" nguy hiểm hơn.
Theo tôi bạn cứ viết code cẩn thận, những chỗ có thể có lỗi thì phải bẫy lỗi. Nhưng con người không lường được hết mọi trường hợp, viết chuẩn 100%, vậy đôi khi bị treo Excel thì chấp nhận thôi.
Cái Ctrl + Pause của bạn thì tôi nghĩ không ít trường hợp chả có SetWindowProc mà vẫn treo máy.

Tôi hỏi ngoài lề một chút: đôi khi bạn có nhu cầu nhấn Ctrl + Pause à? Để làm gì vậy?

Cũng xin thưa với mọi người, nếu không để code bị lỗi vào thì khi nhấn Ctrl+Break thì form vẫn thoát và Excel vẫn hoạt động bình thường. Vậy phải có một lỗi gì đó làm cho đứng màn hình.

Nhưng hình như nếu Ctrl+Break, mặc dù không bị lỗi gì, song sử dụng form vài lần (thoát-mở form), sau đó đóng Excel nó hiện lên thông báo "Out of Memory", thoát thông báo vài lần mới thoát được Excel.

Vã lại, theo em thì chúng ta nên thiết kế form cho hoàn chỉnh, không bị lỗi nữa, bước sau cùng chúng ta mới dùng đến hàm này để hoàn thiện cái ComboBox hoặc ListBox của mình để tránh rủi ro.

Em chưa hề biết class module xài như thế nào, em đang chuẩn bị nghiên cứu về nó, vậy có thể thông qua 2 sự kiện của class dưới đây để tạo thêm thuộc tính cho ComboBox hoặc ListBox được không nhỉ?

PHP:
Private Sub Class_Initialize()

End Sub

Private Sub Class_Terminate()

End Sub
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    76.9 KB · Đọc: 244
Lần chỉnh sửa cuối:
Upvote 0
Tôi hỏi ngoài lề một chút: đôi khi bạn có nhu cầu nhấn Ctrl + Pause à? Để làm gì vậy?
À, Tôi giả thiết vậy thôi chớ thực ra lúc sử dụng thì đâu cần Ctrl + Pause. Chỉ có đôi khi chạy thử code mới có nhu cầu đó, tức là lúc thiết kế thôi, ví dụ như để quên dòng lệnh Msgbox ... trong vòng lặp mà thử code.
Nhưng nếu cẩn thận như anh nói, kiểm tra code cẩn thận, trước khi thử thì cũng chẳng cần.
Chân thành cảm ơn Anh!
 
Upvote 0
Cũng xin thưa với mọi người, nếu không để code bị lỗi vào thì khi nhấn Ctrl+Break thì form vẫn thoát và Excel vẫn hoạt động bình thường. Vậy phải có một lỗi gì đó làm cho đứng màn hình.

Nhưng hình như nếu Ctrl+Break, mặc dù không bị lỗi gì, song sử dụng form vài lần (thoát-mở form), sau đó đóng Excel nó hiện lên thông báo "Out of Memory", thoát thông báo vài lần mới thoát được Excel.

Vã lại, theo em thì chúng ta nên thiết kế form cho hoàn chỉnh, không bị lỗi nữa, bước sau cùng chúng ta mới dùng đến hàm này để hoàn thiện cái ComboBox hoặc ListBox của mình để tránh rủi ro.

Em chưa hề biết class module xài như thế nào, em đang chuẩn bị nghiên cứu về nó, vậy có thể thông qua 2 sự kiện của class dưới đây để tạo thêm thuộc tính cho ComboBox hoặc ListBox được không nhỉ?

PHP:
Private Sub Class_Initialize()

End Sub

Private Sub Class_Terminate()

End Sub

Tôi ủng hộ. Nghĩa cứ tự tìm tòi đi. Có điểm gì thắc mắc hãy hỏi - hỏi toàn diễn đàn.
Có tự làm thì mới biết chứ cứ xài đồ có sẵn thì chả bao giờ học được điều mới
 
Upvote 0
Chuột này khác chuột kia thì kể cũng lạ.
Tôi không có chuột cảm ứng và laptop nên muốn nghiên cứu cũng đành chịu.
Tôi viết lại theo cách mới. Thực ra ta không cần theo dõi sự kiện chuột trong toàn system mà chỉ trong phạm vi ứng dụng của ta. Khi chuột được lăn trong cửa sổ của ta thì thông điệp WM_MOUSEWHEEL sẽ được gửi tới hàm cửa sổ của UserForm (window procedure). Vậy chỉ cần "đánh tráo" hàm cửa sổ để xử lý thông điệp WM_MOUSEWHEEL.
Tóm lại ta dùng công nghệ "Window Subclassing" thay cho hook. Với cách này thì lăn chuột trong UserForm hay notepad không ảnh hưởng tới nhau. Code này lại còn đơn giản hơn hook.

...............

Với hàm của Thầy viết thì ComboBox, ListBox trên UserForm rất tuyệt vời, thế nhưng lại không thể sử dụng được đối với ComboBox trong ActiveX Controls khi dùng trên sheet.

Xin Thầy vui lòng cải tiến thêm nữa được không ạ?

À, nếu có thể được thì trên ListBox hoặc ComboBox có Scroll cuộn ngang nữa, mình có thể làm như cuộn đứng được không ạ? Chỉ thấy sao hỏi vậy chứ em nghĩ có lẽ cũng chẳng cần thiết, số cột thường cố định và thường ít hơn so với hàng mà.
 
Lần chỉnh sửa cuối:
Upvote 0
Chuột này khác chuột kia thì kể cũng lạ.
Tôi không có chuột cảm ứng và laptop nên muốn nghiên cứu cũng đành chịu.
Tôi viết lại theo cách mới. Thực ra ta không cần theo dõi sự kiện chuột trong toàn system mà chỉ trong phạm vi ứng dụng của ta. Khi chuột được lăn trong cửa sổ của ta thì thông điệp WM_MOUSEWHEEL sẽ được gửi tới hàm cửa sổ của UserForm (window procedure). Vậy chỉ cần "đánh tráo" hàm cửa sổ để xử lý thông điệp WM_MOUSEWHEEL.
Tóm lại ta dùng công nghệ "Window Subclassing" thay cho hook. Với cách này thì lăn chuột trong UserForm hay notepad không ảnh hưởng tới nhau. Code này lại còn đơn giản hơn hook.
Trong code sau và trong tập tin đính kèm là code đầy đủ để chạy. Nhưng tôi thêm 1 dòng (mầu đỏ) để test thông điệp được gửi tới hàm cửa sổ. Vậy sau khi test xong thì dòng này xóa đi cho khỏi nhàm code.
Bạn hãy: Kích hoạt UserForm1 (bấm Button 1) --> chọn 1 mục trong ListBox hoặc nhấn tam giác của Combobox --> lăn chuột vài lần --> copy và dán lên GPE những dòng mà Debug.Print ghi trong cửa sổ Immediate để tôi xem.

Mới sưu tầm được file này, cái hay của nó là khi bị lỗi không bị "đơ" Excel như những code khác (dùng một nút lệnh tạo lỗi). Tuy nhiên có một bất tiện là khi lăn chuột, nó luôn luôn select các hàng mà nó cuộn qua, thay vì phải giữ nguyên Index ban đầu cho đến lúc ta cần hàng nào thì chọn hàng đó.

Xin các Thầy rành về API chỉnh sửa giúp phần này được không ạ? Cảm ơn rất nhiều!
 

File đính kèm

Upvote 0
Mới sưu tầm được file này, cái hay của nó là khi bị lỗi không bị "đơ" Excel như những code khác (dùng một nút lệnh tạo lỗi). Tuy nhiên có một bất tiện là khi lăn chuột, nó luôn luôn select các hàng mà nó cuộn qua, thay vì phải giữ nguyên Index ban đầu cho đến lúc ta cần hàng nào thì chọn hàng đó.

Xin các Thầy rành về API chỉnh sửa giúp phần này được không ạ? Cảm ơn rất nhiều!
Xin vui lòng giúp đỡ cho vấn đề này ạ. Cám ơn rất nhiều!

quần áo trẻ em | quan ao tre em | quần áo sơ sinh | quần áo bé trai | quần áo bé gái | bodysuit carter | quan ao so sinh | quan ao tre em nhap khau
 
Lần chỉnh sửa cuối:
Upvote 0
cho em hỏi sao tải file đính kèm về mà dùng chuôt vẫn không được ạ.
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom