Tôi có 1 file sử dụng Form. Theo chương trình khi mở File lên sẽ tự động load Form, từ Form sẽ vào chương trình bảng tính bằng nút lệnh VÀO BẢNG TÍNH và kết thúc chương trình bằng nút THOÁT CHƯƠNG TRÌNH.
Bây giờ tôi đang bị lỗi như sau: nếu thoát chương trình bằng lệnh đóng file của Excel(Dấu x góc phải của bảng tính) thì khi mở lại bảng tính hoàn toàn không có lỗi gì. Ngược lại nếu tôi thoát chương trình bằng nút lệnh trên Form thì khi mở lại bảng tính sẽ xuất hiện lỗi: activex component can't create object.
Tôi không cho rằng code viết bị lỗi mà cho rằng máy tính của tôi đang thiếu một Control nào đó, tôi gửi ảnh minh họa và file lỗi nhờ mọi người giúp giải quyết lỗi. Xin cám ơn
Tôi có 1 file sử dụng Form. Theo chương trình khi mở File lên sẽ tự động load Form, từ Form sẽ vào chương trình bảng tính bằng nút lệnh VÀO BẢNG TÍNH và kết thúc chương trình bằng nút THOÁT CHƯƠNG TRÌNH.
Bây giờ tôi đang bị lỗi như sau: nếu thoát chương trình bằng lệnh đóng file của Excel(Dấu x góc phải của bảng tính) thì khi mở lại bảng tính hoàn toàn không có lỗi gì. Ngược lại nếu tôi thoát chương trình bằng nút lệnh trên Form thì khi mở lại bảng tính sẽ xuất hiện lỗi: activex component can't create object.
Tôi không cho rằng code viết bị lỗi mà cho rằng máy tính của tôi đang thiếu một Control nào đó, tôi gửi ảnh minh họa và file lỗi nhờ mọi người giúp giải quyết lỗi. Xin cám ơn
Private Sub QuitAndSave_Click()
Sheets("InTemThung").Select
Cells.Select
Selection.Delete
Sheets("Menu").Select
ThisWorkbook.Close SaveChanges:=True
Application.WindowState = xlMaximized
End Sub
Anh cần sửa lại là
Mã:
Private Sub QuitAndSave_Click()
ThisWorkbook.Close SaveChanges:=True
Application.WindowState = xlMaximized
[COLOR="#FF0000"]Unload Me[/COLOR] 'Giải phóng form & bộ nhớ
End Sub
Các code xóa vì nó đã chạy trong sự kiện ThisWorkbook.BeforeSave().
Khi đóng form anh phải chạy lệnh "Unload Me" để giải phóng bộ nhớ và đóng form thực sự.
Trong file Excel của anh không có dùng controls nào lạ cả nên chạy máy nào cũng được.
Các code xóa vì nó đã chạy trong sự kiện ThisWorkbook.BeforeSave().
Khi đóng form anh phải chạy lệnh "Unload Me" để giải phóng bộ nhớ và đóng form thực sự.
Tuân à, nếu bỏ các lệnh xóa đi thì khi đóng Form nó không xóa mặc dù đã có lệnh trong sự kiện trước khi Save.
Trên máy của anh vẫn không hết lỗi như anh đã nêu: activex component can't create object.
Private Sub UserForm_Activate()
On Error Resume Next
If Application.WindowState = xlMinimized Then
DonmauDonco.Enabled = False
DonmauDonco2.Enabled = False
DonmauDaco.Enabled = False
DamauDaco.Enabled = False
Assort.Enabled = False
GhepTam.Enabled = False
Else
DonmauDonco.Enabled = True
DonmauDonco2.Enabled = True
DonmauDaco.Enabled = True
DamauDaco.Enabled = True
Assort.Enabled = True
GhepTam.Enabled = True
End If
Dunglai = False
Me.Caption = "SONDONG GAMENT JOINT STOCK COMPANY - SONDONG.,JSC - "
ChuChay = Me.CompanyName
[COLOR="#008000"]Thuchien:
PauseTime = 0.2
Start = Timer
Do While Timer < Start + PauseTime
DoEvents
Loop
L = Len(CompanyName.Caption)
CompanyName.Caption = Right(CompanyName.Caption, L - 1) + Left(CompanyName.Caption, 1)
If Dunglai = False Then GoTo Thuchien[/COLOR]
End Sub
Lỗi là ở lệnh lặp từ đoạn Thuchien:, trong suốt quá trình chạy form nó không thoát khỏi vòng lặp này được và một số sự kiện của đối tượng máy tính không nhận được đúng. Anh sử dụng vòng lặp này cốt để chạy một thủ tục chạy chữ mà thôi. Giải pháp là thay thế bằng hàm Windows API SetTimer() tốt hơn và chạy độc lập với form, nó định kỳ (theo mili giây) chạy một thủ tục.
Code trong form sửa lại và thêm như sau:
+ Trong sự kiện Activate(): Xóa từ dòng Thuchien: và thêm lệnh StartTimer - Khởi hoạt chế độ chạy Timer
+ Thêm sự kiện Terminate() và gán lệnh StopTimer - Ngưng chế độ chạy Timer
Mã:
Private Sub UserForm_Activate()
On Error Resume Next
If Application.WindowState = xlMinimized Then
DonmauDonco.Enabled = False
DonmauDonco2.Enabled = False
DonmauDaco.Enabled = False
DamauDaco.Enabled = False
Assort.Enabled = False
GhepTam.Enabled = False
Else
DonmauDonco.Enabled = True
DonmauDonco2.Enabled = True
DonmauDaco.Enabled = True
DamauDaco.Enabled = True
Assort.Enabled = True
GhepTam.Enabled = True
End If
Dunglai = False
Me.Caption = "SONDONG GAMENT JOINT STOCK COMPANY - SONDONG.,JSC - "
ChuChay = Me.CompanyName
[COLOR="#FF0000"]StartTimer[/COLOR]
End Sub
Private Sub UserForm_Terminate()
[COLOR="#FF0000"]StopTimer[/COLOR]
End Sub
Tạo một Module tên là modTimer chứa code của các hàm và thủ tục StartTimer, StopTimer, TimeProc - Thủ tục chạy chữ
Mã:
Option Explicit
Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Const nIDEvent = 9999 [COLOR="#008000"]'Tuy chon, so > 0[/COLOR]
Sub StartTimer()
StopTimer
SetTimer Application.hwnd, nIDEvent, 100, AddressOf TimeProc [COLOR="#008000"]'100 -- Tốc độ chạy chữ = mili giây[/COLOR]
End Sub
Sub StopTimer()
KillTimer Application.hwnd, nIDEvent
End Sub
[COLOR="#008000"]'Thủ tục chạy chữ[/COLOR]
Function TimeProc(ByVal H As Long, ByVal nMSG As Long, ByVal nID As Long, ByVal nTsys As Long)
On Error Resume Next
If Not frmMain Is Nothing Then
Dim L As Long
L = Len(frmMain.CompanyName.Caption)
frmMain.CompanyName.Caption = Right(frmMain.CompanyName.Caption, L - 1) + Left(frmMain.CompanyName.Caption, 1)
End If
End Function
Nếu dùng SetTimer, tôi thường thấy nó đi cặp với 1 hàm TimeProc(các tham số) Sẵn tiên cho tôi hỏi tí:
- Hàm TimeProc thường có 1 lô tham số đi kèm, nó dùng để làm gì vậy?
- Do không hiểu mấy tham số này nên tôi thường bỏ luôn ---> Vì thật ra có để nguyên mấy tham số ấy thì tôi cũng đâu thấy chung tham gia gì vào quá trình tính toán đâu
Nếu dùng SetTimer, tôi thường thấy nó đi cặp với 1 hàm TimeProc(các tham số) Sẵn tiên cho tôi hỏi tí:
- Hàm TimeProc thường có 1 lô tham số đi kèm, nó dùng để làm gì vậy?
- Do không hiểu mấy tham số này nên tôi thường bỏ luôn ---> Vì thật ra có để nguyên mấy tham số ấy thì tôi cũng đâu thấy chung tham gia gì vào quá trình tính toán đâu
Hàm SetTimer để thiết lập chế độ gọi thông điệp WM_TIMER trong thủ tục Windows (nguyên lý hoạt động chương trình trong Windows là duyệt các thông điệp (Message) trong một vòng lặp, hàm để bắt thông điệp này thường có tên WndProc() nó được cài vào Handle của chương trình. Application.hwnd chính là Handle của Microsoft Excel đang chạy). Nếu không gán TimeProc trong SetTimer thì hàm WndProc sẽ gửi thông điệp WM_TIMER để chúng ta xử lý.
Trong việc gọi trên, SetTimer luôn trả về giá trị là ID của lần gọi SetTimer, và nó chính bằng nIDEvent.
Trong một hoàn cảnh nào đó chúng ta có thể gọi hai hay nhiều lần SetTimer với cùng thủ tục có tên TimeProc
Trong trường hợp này thủ tục TimeProc được gọi trên hai thread (hiểu như là chạy trên hai luồng). Một cái theo Winword - WordHwnd và cái kia theo Excel - ExcelHwnd với 2 ID là nIDEventWord, nIDEventExcel (có thể đặt hằng số cho các ID với giá trị là 9999, 9998).
Cấu trúc của thủ tục TimeProc như sau:
Mã:
Sub TimeProc(ByVal hwnd As Long, ByVal nMSG As Long, ByVal idEvent As Long, ByVal dwTime As Long)
[COLOR="#008000"] 'On Error Resume Next[/COLOR]
End Sub
+ hwnd: là Handle của ứng dụng mà được gọi trong hàm SetTimer, nếu TimeProc chạy trên luồng Winword thì giá trị của nó chính là WordHwnd, nếu Excel thì là ExcelHwnd. Trong ví dụ bài trước thì nó chính là Application.hwnd. Trong lập trình API biết được giá trị Handle sẽ là đầu mối để làm mọi việc xử lý tới ứng dụng chứa Handle đó.
+ nMSG: là thông điệp/Message mà Windows gửi đến, nó chính là WM_TIMER với giá trị 275.
+ idEvent: là ID của thủ tục TimeProc, nó được nạp khi gọi hàm SetTimer, nếu TimeProc chạy trên luồng Winword thì giá trị của nó chính là nIDEventWord, nếu Excel thì là nIDEventExcel. Trong ví dụ bài trước thì nó chính là 9999. Biết được giá trị ID ta biết là TimerProc đang chạy trên luồng nào.
+ dwTime: trả về số mili giây kể từ lúc hệ thống được khởi động. Giá trị này trùng với giá trị trả về bởi hàm GetTickCount.
(*) Trong ví dụ ở bài trước hay ở đâu đó chúng ta nhầm hay gọi hàm function TimeProc nhưng cách gọi này là sai dẫn đến giá trị các tham số trong TimerProc trả về không đúng, đúng phải là Sub TimeProc.
Việc giải thích cách thức hoạt động của mấy hàm API này có vẻ trừu tượng, không dễ ngấm. Vậy hiểu nôm na thế này.
SetTimer(Lào, Số hộ chiếu ở Lào, thời gian nhắc việc, đ/c ndu96081631)
SetTimer(Campuchia, Số hộ chiếu ở Campuchia, thời gian nhắc việc, đ/c ndu96081631)
Như vậy cùng một người là ndu96081631 nhưng phải làm việc ở ở hai nơi Lào và Campuchia. Máy tính có khả năng nhân bản ndu96081631 thành hai, cùng một thời điểm có mặt và làm việc cả hai quốc gia Lào và Campuchia. đ/c ndu96081631 chỉ biết mình đang ở đâu khi nhìn vào idEvent.
Tôi xóa mọi bài tranh luận không liên quan đến chủ đề.
Chủ topic cũng đã thỏa mãn, nên tôi khóa chủ đề này,
Ai muốn tranh luận bên ngoài chủ đề, thì mở topic khác.
Gởi siwtom,
Tôi biết bạn có lưu lại các bài viết ở đây, nếu bạn muốn tranh luận thì mở topic khác, dán bản sao lưu vào hay không tùy bạn.