Cách tạo Background phía sau một form (1 người xem)

Liên hệ QC

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

vba_gpe

Thành viên thường trực
Tham gia
15/12/10
Bài viết
296
Được thích
44
Nghề nghiệp
Thất nghiệp
Gửi anh chị GPE
- Em có dùng chương trình Smart Install Maker để đóng gói một số ứng dụng nhỏ. Sau khi build thành công, em thấy trong màng hình chào mừng của file setup có cái Backgourd và một form để chọn người dùng thao tác. (Cái form trước background).
- Xin hỏi mọi người, nếu em dùng VB6 thì có thể làm được điều này không ạ!

Mong nhận được đóng góp của mọi người.

Cảm ơn anh chị trước.
Trân trọng.
 
Gửi anh chị GPE
- Em có dùng chương trình Smart Install Maker để đóng gói một số ứng dụng nhỏ. Sau khi build thành công, em thấy trong màng hình chào mừng của file setup có cái Backgourd và một form để chọn người dùng thao tác. (Cái form trước background).
- Xin hỏi mọi người, nếu em dùng VB6 thì có thể làm được điều này không ạ!

Mong nhận được đóng góp của mọi người.

Cảm ơn anh chị trước.
Trân trọng.
Hình thù nố ra làm sao? Bạn chụp hình đưa lên đây mới hình dung được chứ
 
Hình thù nố ra làm sao? Bạn chụp hình đưa lên đây mới hình dung được chứ
Em gửi thầy và mọi người hình ảnh tham khảo
Em upload ảnh nãy giờ không được nên đành gửi file nén vậy. Thầy và mọi người xem giúp em nhé.
Cảm ơn thầy.
 

File đính kèm

Lần chỉnh sửa cuối:
Em gửi thầy và mọi người hình ảnh tham khảo
Em upload ảnh nãy giờ không được nên đành gửi file nén vậy. Thầy và mọi người xem giúp em nhé.
Cảm ơn thầy.

Mấy trò này có gì đâu. Người ta cố tình làm thế để "dọa" nhau thôi.
Có thể làm theo nhiều cách. Ví dụ như cách sau đây.

code trong Module1:

Mã:
Private Const PROCESS_TERMINATE As Long = 1
Private Const SPI_GETDESKWALLPAPER As Long = 115
Private Const SPI_SETDESKWALLPAPER As Long = 20
Private Const SW_HIDE = 0
Private Const SW_SHOW = 5
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Private Declare Function SystemParametersInfo Lib "user32.dll" Alias "SystemParametersInfoA" _
(ByVal uAction As Long, ByVal uParam As Long, ByVal lpvParam As String, ByVal fuWinIni As 
Long) As Long
Private Declare Function EnumWindows Lib "user32.dll" _
(ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function ShowWindow Lib "user32.dll" _
(ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" _
(ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" _
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) 
As Long
Private Declare Function TerminateProcess Lib "kernel32.dll" _
(ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare Function IsWindowVisible Lib "user32.dll" (ByVal hwnd As Long) As Long

Dim myHandle As Long, list() As Long
Dim filename As String, index As Long

Public Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
  EnumWindowsProc = 1
  If IsWindowVisible(hwnd) <> 0 And hwnd <> myHandle Then
      [COLOR=#0000ff]' nếu cửa sổ đang hiển thị và không phải của ta thì cho handle của nó vào danh sách
[/COLOR]   index = index + 1
    ReDim Preserve list(1 To index)
    list(index) = hwnd
  End If
End Function

Sub HideWindows(ByVal hwnd As Long)
Dim hWindow As Long, hProc As Long, ProcID As Long, k As Long
    [COLOR=#0000ff]' ghi nhớ handle của cửa sổ của ta
[/COLOR]   myHandle = hwnd
    index = 0
    filename = String(256, Chr(0))
    [COLOR=#0000ff]' đọc và ghi nhớ wallpaper hiện hành[/COLOR]
    SystemParametersInfo SPI_GETDESKWALLPAPER, 256, filename, 0
    [COLOR=#0000ff]' duyệt các cửa sổ top-level có trong system[/COLOR]
    EnumWindows AddressOf EnumWindowsProc, 0
    [COLOR=#0000ff]' giấu các cửa sổ có trong danh sách - các cửa sổ đang hiển thị
[/COLOR]   For k = LBound(list) To UBound(list)
        ShowWindow list(k), SW_HIDE
        Sleep 40
        Do While IsWindowVisible(list(k)) <> 0
            ShowWindow list(k), SW_HIDE
            Sleep 40
        Loop
    Next k
    [COLOR=#0000ff]' đọc handle của dải Start - "đồ" của Explorer[/COLOR]
    hWindow = FindWindow("Shell_TrayWnd", vbNullString)
    If hWindow <> 0 Then
        [COLOR=#0000ff]' đọc  process identifier của Explorer
[/COLOR]       GetWindowThreadProcessId hWindow, ProcID
       [COLOR=#0000ff]' đọc handle của process Explorer[/COLOR]
        hProc = OpenProcess(PROCESS_TERMINATE, 0, ProcID)
        If hProc <> 0 Then
             [COLOR=#0000ff]' "thịt" chú Explorer
[/COLOR]           TerminateProcess hProc, 1
            CloseHandle hProc
        End If
        [COLOR=#0000ff]' lấy ảnh của ta làm hình nền[/COLOR]
        SystemParametersInfo SPI_SETDESKWALLPAPER, 0, _
 App.Path & "\forest.bmp", SPIF_SENDCHANGE
    End If
End Sub

Sub ShowWindows()
Dim k As Long
    [COLOR=#0000ff]' Explorer cũ bị ta "thịt" rồi nên phải "đúc" Explorer mới
[/COLOR]   ShellExecute 0, "open", "explorer.exe", vbNullString, vbNullString, SW_SHOW
   [COLOR=#0000ff]' hiển thị lại các cửa sổ đã bị ẩn[/COLOR]
    For k = LBound(list) To UBound(list)
        ShowWindow list(k), SW_SHOW
    Next k
   [COLOR=#0000ff]' phục hồi lại hình nền cũ[/COLOR]
    SystemParametersInfo SPI_SETDESKWALLPAPER, 0, filename, SPIF_SENDCHANGE
End Sub

code trong Form1:

Mã:
Private Sub Form_Load()
    Call HideWindows(Me.hwnd)
End Sub
Private Sub Form_Unload(Cancel As Integer)
    Call ShowWindows
End Sub

Trong tập tin đính kèm có Project1.exe để chạy ngay. Cũng có cả Project trong VB, nếu ai có VB thì cũng có thể tự compile project

Đã test trên XP Home + SP2 và Win 7 Starter. Tôi chỉ có 2 hđh như thế thôi.
 

File đính kèm

Lần chỉnh sửa cuối:
Cảm ơn thầy Siwtom nhiều lắm.

Cho em hỏi nếu muốn tìm chủ đề tương tự với chủ đề em hỏi (chủ đề hiện nay) trên goole bằng Tiếng Anh thì nên viết như thế nào để cho ra kết quả giải quyết phù hợp với đề tài này. Em tìm với từ khóa "how to make background window behide UserForm in VB6" nhưng vẫn chưa tìm được những kết quả mong muốn. Xin thầy và mọi người giúp đỡ.

Trân trọng cảm ơn thầy và anh chị GPE.
 
Lần chỉnh sửa cuối:
Cảm ơn thầy Siwtom nhiều lắm.

Cho em hỏi nếu muốn tìm chủ đề tương tự với chủ đề em hỏi (chủ đề hiện nay) trên goole bằng Tiếng Anh thì nên viết như thế nào để cho ra kết quả giải quyết phù hợp với đề tài này. Em tìm với từ khóa "how to make background window behide UserForm in VB6" nhưng vẫn chưa tìm được những kết quả mong muốn. Xin thầy và mọi người giúp đỡ.

Trân trọng cảm ơn thầy và anh chị GPE.

Tôi không tìm kiếm nên cũng chả biết từ khóa nào tốt nhất.
Vấn đề thực ra không khó. Cái khó là ý tưởng, là hướng đi, là phân tích và chia nhỏ vấn đề. Nhiều khi bạn tìm
cách giải quyết một vấn đề phức tạp thì chưa chắc tìm thấy nhưng những vấn đề "đơn lẻ" cụ thể thì thường
tìm thấy.
Khi tôi nhìn vào hình của bạn thì tôi thấy 2 vấn đề:
1. Ảnh nền. Ảnh nền thì thường ai cũng có trên màn hình, và không ít người thay đổi hình nền "bằng tay". Vậy
vấn đề bây giờ chỉ là làm bằng code.
Hình nền hả? Thế thì thử tìm xem trong help nói gì. Có ngay một mục "Desktop Window". Tôi click vào thì
thấy như hình dưới.

View attachment 90413


Nhìn chữ đỏ đỏ là biết dùng hàm gì để thay hình nền. Để xem các thông số của hàm và cách dùng thì tôi click
vào SystemParametersInfo. Nhìn vào dòng đỏ đỏ ở hình dưới thì tôi sẽ viết code để test, rồi thì ra ngô ra
khoai hết.

View attachment 90414


2. Form. Để cho Form "bá chủ" trên màn hình thì phải ẩn những cửa sổ khác đi. Window? Thì trong help có
mục window. Hide window, show window? Thì cũng có ngay.
Tất nhiên tôi không phải tìm kiếm nữa vì tôi lập trình bằng Windows API nhiều, đọc help nhiều nên biết rồi.
Trong help có tất cả các mục về ListBox, Combobox, Button, ListView, trỏ text, thông điệp, bộ nhớ đệm v...v
Ví dụ như trong hình dưới bạn thấy có nhiều vấn đề nhỏ. Đọc và thử viết code thôi

View attachment 90415

Nếu bạn chia nhỏ vấn đề thì để giải quyết các chi tiết nhỏ bạn chỉ cần đọc help là đủ. Tôi bây giờ chỉ tìm trên
mạng khi việc sử dụng hàm nào đó thực sự phức tạp, "công nghệ" nâng cao. Cái thời tôi "không biết gì" thì
internet cũng chưa được như hiện nay. Tôi đã đọc nhiều sách và tạp chí về máy tính về lập trình.
Muốn lập trình thực sự thì bạn phải biết về API, biết system nó có cấu trúc như thế nào, cơ cấu hoạt động ra
sao v...v Cái này không phải ngày một ngày hai mà có được. Phải đọc nhiều, thử nghiệm nhiều, tự viết code
nhiều.
 
Cảm ơn thầy rất nhiều.
Em sẽ cố gắng! Mong được chỉ bảo của thầy và mọi người nhiều hơn.

Trân trọng.
 
Mấy trò này có gì đâu. Người ta cố tình làm thế để "dọa" nhau thôi.
Có thể làm theo nhiều cách. Ví dụ như cách sau đây.

...........

Trong tập tin đính kèm có Project1.exe để chạy ngay. Cũng có cả Project trong VB, nếu ai có VB thì cũng có thể tự compile project

Đã test trên XP Home + SP2 và Win 7 Starter. Tôi chỉ có 2 hđh như thế thôi.

Nếu mình "thịt" cái Explorer rồi thì khi bấm vào minimize của form, không có taskbar nên muốn thoát chương trình chỉ có Alt+F4, vậy phải làm sao anh?

Nhìn hình dưới, không biết phải làm sao cho cái form phục hồi:
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    37.9 KB · Đọc: 198
Thiết lập form nền cho form chính trong VB6 vaf VBA

Tôi nghĩ chỉ là có một màn hình nền phủ toàn màn hình thì không nên can thiệp vào Background của hệ điều hành (HĐH), càng không nên "thịt" Explorer của nó (sẽ mất hết các thư mục đang mở, có thể ảnh hưởng tới các tiền trình khác mà HĐH đang phục vụ.

Giải pháp của tôi là tạo 2 form: form1 làm nền, form2 là điều khiển chính, nổi trên form1 (form2 là con của form1).
Trong Form1 code như sau:
Mã:
Option Explicit

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Const WS_BORDER = &H800000
Private Const WS_CAPTION = &HC00000          [COLOR="#008000"]'  WS_BORDER Or WS_DLGFRAME[/COLOR]
Private Const WS_THICKFRAME = &H40000
Private Const WS_DLGFRAME = &H400000
Private Const WS_EX_DLGMODALFRAME = &H1&
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const GWL_EXSTYLE = (-20)
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_FRAMECHANGED = &H20        [COLOR="#008000"]'  The frame changed: send WM_NCCALCSIZE[/COLOR]
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long

Dim hForm As Long

Private Sub Form_Initialize()
   'Lấy handle của form
    #If VBA6 Then [COLOR="#008000"]'Nếu code dùng cho VBA[/COLOR]
        hForm = FindWindow("ThunderDFrame", Me.Caption)
    #Else [COLOR="#008000"]'Trong VB6[/COLOR]
        hForm = hwnd
        [COLOR="#008000"]'BorderStyle = None 'Thiết lập ở chế độ design. Có thể bỏ qua [/COLOR]
    #End If
    [COLOR="#008000"]'Loại bỏ tiêu đề, đường viền của form1 [/COLOR]
    SetWindowLong hForm, GWL_STYLE, GetWindowLong(hForm, GWL_STYLE) And Not (WS_BORDER Or WS_CAPTION Or WS_THICKFRAME Or WS_DLGFRAME)
    SetWindowLong hForm, GWL_EXSTYLE, GetWindowLong(hForm, GWL_EXSTYLE) And Not WS_EX_DLGMODALFRAME
    Dim rc As RECT
    [COLOR="#008000"]'Lấy độ rộng, cao của màn hình  [/COLOR]
    GetWindowRect GetDesktopWindow, rc
    [COLOR="#008000"]'Thiết lập độ rộng, độ cao của form1 cho toàn màn hình  [/COLOR]
    SetWindowPos hForm, 0, rc.Left, rc.Top, rc.Right, rc.Bottom, SWP_FRAMECHANGED
    Form1.Show vbModeless [COLOR="#008000"]'Nếu trong VBA phải thiết lập ở chế độ thiết kế (design mode) là Userform1.ShowModal = False [/COLOR]
    [COLOR="#008000"]'Tạo quan hệ form2 là con của form1  [/COLOR]
    SetParent Form2.hwnd, hForm
End Sub

Private Sub Form_Load()
    [COLOR="#008000"]'Khi form1 load xong thì mở form2  [/COLOR]
    Form2.Show
End Sub

Trong Form2 code như sau:
Mã:
Private Sub cmdClose_Click()
    [COLOR="#008000"]'Đóng form2 khi nhấn nút "Close"[/COLOR]
    Unload Me
End Sub

Private Sub Form_Unload(Cancel As Integer)
    [COLOR="#008000"]'Khi form2 bị đóng (bởi nhấn vào button "Close" hoặc nút [X] của form) thì kết thúc chương trình[/COLOR]
    End
End Sub

Nếu viết code trong VBA thì chỉ cần chỉnh sửa một chút là được. Tôi viết code cho cả VB6 và VBA trong file đính kèm các bạn có thể tham khảo.
 

File đính kèm

Lần chỉnh sửa cuối:
Nếu mình "thịt" cái Explorer rồi thì khi bấm vào minimize của form, không có taskbar nên muốn thoát chương trình chỉ có Alt+F4, vậy phải làm sao anh?

Nhìn hình dưới, không biết phải làm sao cho cái form phục hồi:
Nghĩa thử phím Windows chưa? (Mình bận quá nên chưa down về thử)
 
Nghĩa thử phím Windows chưa? (Mình bận quá nên chưa down về thử)

Đúng là bấm nút Windows thì nó có hiện ra cái form giống như subform. Theo em nghĩ dù là cái hình nó full screen đi nữa cũng nên chừa lại cái taskbar cho dễ thao tác hen!
 
Tôi nghĩ chỉ là có một màn hình nền phủ toàn màn hình thì không nên can thiệp vào Background của hệ điều hành (HĐH), càng không nên "thịt" Explorer của nó (sẽ mất hết các thư mục đang mở, có thể ảnh hưởng tới các tiền trình khác mà HĐH đang phục vụ.

Tôi không hiểu tại sau lại: "không nên can thiệp vào Background của hệ điều hành"?. Vì chuyện thay đổi nó thì user thực hiện liên tục theo ý thích. Nó đâu phải vấn đề "mạo hiểm" để mà "không nên"? Nếu nói "không cần" thì đúng.
Tôi đã nói là có nhiều cách. Đó chỉ là một cách thôi.
Vì sao tôi chủ ý, cố tình "thịt" Explorer? Vì trên cơ sở hình đính kèm thì thì khó biết cái setup kia nó "bá củ" thực sự hay chỉ "giả tạo". Tôi "thịt" explorer là để setup bá chủ thực sự. Vì nếu không thì vẫn có thể gọi các ct khác, và bấm lá cờ Win thì vẫn mở được Start, vẫn chuyển được sang các ct khác. Tất nhiên thịt Explorer thì vẫn còn gọi được các cửa sổ khác, Ctrl + Alt + Del (Task Manage) rồi nạp Explorer nhưng cũng có thể tắt cả Task Manage.
Nói chung chỉ nhìn hình thôi thì khó biết cái setup kia nó là "duy nhất" hay không. Nếu không cần "bá chủ" thực sự thì xóa đoạn "thịt" Explorer, thế thôi.
Còn chuyện làm hình nền "giả lập" hay thực sự thì cũng tùy theo ý thích mỗi người. Nói chung là có nhiều cách. Tôi đã nói là đó chỉ là một cách thôi.
 
Lần chỉnh sửa cuối:
Tôi nghĩ chỉ là có một màn hình nền phủ toàn màn hình thì không nên can thiệp vào Background của hệ điều hành (HĐH), càng không nên "thịt" Explorer của nó (sẽ mất hết các thư mục đang mở, có thể ảnh hưởng tới các tiền trình khác mà HĐH đang phục vụ.

Giải pháp của tôi là tạo 2 form: form1 làm nền, form2 là điều khiển chính, nổi trên form1 (form2 là con của form1).


Nếu viết code trong VBA thì chỉ cần chỉnh sửa một chút là được. Tôi viết code cho cả VB6 và VBA trong file đính kèm các bạn có thể tham khảo.

Với Excel, Có một vấn đề là khi dùng chế độ Userform1.ShowModal = False thì với form2 nó không có cái hiện tượng setfocus ở bất cứ control nào (em thêm 1 textbox), cho dù mình có bắt nó làm nó cũng không!

Cho dù ở form2 em có dùng:
Mã:
Private Sub UserForm_Initialize()
    TextBox1.SetFocus
End Sub

hay ở Form1 em thêm:

Mã:
Private Sub UserForm_Activate()
    UserForm2.Show False
    UserForm2.TextBox1.SetFocus
End Sub

Vậy làm cách nào để mặc định load form lên thì nó setfocus như không có 2 form vậy anh?
 
Đúng là bấm nút Windows thì nó có hiện ra cái form giống như subform. Theo em nghĩ dù là cái hình nó full screen đi nữa cũng nên chừa lại cái taskbar cho dễ thao tác hen!

Tôi cố tình tắt tất cả, kể cả taskbar để setup bá chủ mà. Nếu bạn muốn thì xóa đoạn "thịt" Explorer đi, thế thôi.
 
Tôi cố tình tắt tất cả, kể cả taskbar để setup bá chủ mà. Nếu bạn muốn thì xóa đoạn "thịt" Explorer đi, thế thôi.

Em cũng đã bỏ cái đoạn này:

If hProc <> 0 Then
TerminateProcess hProc, 1
CloseHandle hProc
End If

nhưng hình như nó vẫn bị "thịt" à! Taskbar cũng bị ẩn đi.

Mà Anh có thể làm trên Excel được không, vì em không biết xài VB6.
 
Em cũng đã bỏ cái đoạn này:

If hProc <> 0 Then
TerminateProcess hProc, 1
CloseHandle hProc
End If

nhưng hình như nó vẫn bị "thịt" à! Taskbar cũng bị ẩn đi.

Mà Anh có thể làm trên Excel được không, vì em không biết xài VB6.

Tôi viết thiếu vì vội. Explorer không bị thịt nhưng thanh Start là "đồ" của Explorer mà tôi cũng đã ẩn đi. Cần phải kiểm tra trong EnumWindowsProc xem nếu handle hiện tìm thấy có phải là của Shell_TrayWnd không (thanh Start) hay của Progman không (có SysListView với các icon trên desktop), nếu đúng thì KHÔNG thêm vào danh sách để ẩn.
Nhưng làm như thế thì không đúng với dụng ý của tôi. Tôi nhìn hình của người hỏi không thấy thanh Start nên kết luận:
1. Hoặc setup ẩn toàn bộ và bá chủ kiểu: hãy đi "tới cùng" hoặc thoát để trở về Explorer
2. Hoặc thanh Start không nhìn thấy (nhưng không bị ẩn) do cái "hình - form" kia được show MAX và thanh Start không ở chế độ "Always on top"
Tôi chọn th 1 vì thế ẩn tất cả, từ đó mới đề nghị code kia. Nếu không ẩn gì cả thì cái code kia "vô duyên" quá. Lấy cái code được cố tình "thiết kế" để làm một việc rồi sửa lại để nó không làm việc đó thì có lẽ tôi phải vào "bệnh viện tâm thần" mất thôi.
Vậy nếu không ẩn gì, và cho phép user làm việc tí với setup, chuyển sang cửa sổ khác cũng làm việc tí, rồi lại về setup - cứ như thế mãi, thì đi theo hướng của tôi làm gì? Trong th 2 thì dùng cách của bạn Tuân là được rồi.
 
Với Excel, Có một vấn đề là khi dùng chế độ Userform1.ShowModal = False thì với form2 nó không có cái hiện tượng setfocus ở bất cứ control nào (em thêm 1 textbox), cho dù mình có bắt nó làm nó cũng không!

Cho dù ở form2 em có dùng:
Mã:
Private Sub UserForm_Initialize()
    TextBox1.SetFocus
End Sub

hay ở Form1 em thêm:

Mã:
Private Sub UserForm_Activate()
    UserForm2.Show False
    UserForm2.TextBox1.SetFocus
End Sub

Vậy làm cách nào để mặc định load form lên thì nó setfocus như không có 2 form vậy anh?

Mình đã cố tìm cách nhưng chưa được. Vụ này có vẻ khó, khi nào có time mình sẽ tìm cách sửa. Mà vấn đề về mất focus khi Userform.ShowModal = False có thể cũng là lỗi của VBA. Nếu tạo một Userform thường có đăt ShowModal = False, trong Userform có một TextBox, khi chạy thì có focus tại TextBox nhưng khi đặt con trỏ vào sheet rồi lại bấm vào tiêu đề form (để active) thì mất focus mà đúng ra nó vẫn phải có focus.
 
Thì vẫn thường làm trong hđh Windows thôi, tức Alt + TAB

Em có hướng như vầy nha, không biết Anh giúp được em không.

Em thấy rằng, bằng thủ công mình có thể chọn ẩn Icon trên màn hình:

Picture1.jpg

Rồi sau đó, mình chuyển cái hình của mình làm hình nền.

Vậy Anh có thể giúp em code khi mở file Excel lên thì giấu icon trên màn hình và tất cả các cửa sổ sẽ thu nhỏ (minimum) đương nhiên chỉ có cái file của mình là không bị thu nhỏ, đồng thời hiển thị cái hình của mình làm hình nền.

Sau khi thoát file, mình cho mọi thứ trở lại bình thường. Làm vậy có vướng gì cho anh không?

Cám ơn Anh rất nhiều.
 
Lần chỉnh sửa cuối:
Em có hướng như vầy nha, không biết Anh giúp được em không.

Em thấy rằng, bằng thủ công mình có thể chọn ẩn Icon trên màn hình:

View attachment 90552

Rồi sau đó, mình chuyển cái hình của mình làm hình nền.

Vậy Anh có thể giúp em code khi mở file Excel lên thì giấu icon trên màn hình và tất cả các cửa sổ sẽ thu nhỏ (minimum) đương nhiên chỉ có cái file của mình là không bị thu nhỏ, đồng thời hiển thị cái hình của mình làm hình nền.

Sau khi thoát file, mình cho mọi thứ trở lại bình thường. Làm vậy có vướng gì cho anh không?

Cám ơn Anh rất nhiều.

Những cái này có thể làm được nhưng nếu làm trong Excel thì rồi cũng có "bệnh" như bạn Tuân nói. Khi Textbox nào đó có Focus nhưng rồi Form mất Focus --> Form lấy lại Focus thì bạn không có trỏ text trong Textbox mà trước đó có Focus.
Bạn Tuân nói: sau khi đặt trỏ chuột vào cell --> click thanh tiêu đề hay Form thì không có trỏ text (caret) trong Textbox. Nhưng không chỉ thế. Bằng bất cứ cách nào bạn làm cho Form mất Focus vd. nhấn "lá cờ Windows" thì sau khi click vào Form bạn không nhìn thấy caret trong text box.
Rõ ràng đây là lỗi của Excel.
Có thể khắc phục nửa vời. Nửa vời vì bạn không khắc phục được lỗi trên nhưng khi Form được show thì bạn có thể trong Activate thực hiện SetFocus vào textbox tùy ý (bạn thử thêm 3 textbox rồi SetFocus vào textbox bất kỳ). Làm như thế nào?
Trong code của bạn Tuân trong Initialize của UserForm1 bạn bỏ dòng "SetParent hForm2, hForm" còn trong Acivate của UserForm2 bạn SetFocus cho textbox. Nếu bạn muốn có caret trong textbox đầu tiên thì bạn chả cần SetFocus làm gì vì "tự nó sẽ có".
 
Những cái này có thể làm được nhưng nếu làm trong Excel thì rồi cũng có "bệnh" như bạn Tuân nói. Khi Textbox nào đó có Focus nhưng rồi Form mất Focus --> Form lấy lại Focus thì bạn không có trỏ text trong Textbox mà trước đó có Focus.
Bạn Tuân nói: sau khi đặt trỏ chuột vào cell --> click thanh tiêu đề hay Form thì không có trỏ text (caret) trong Textbox. Nhưng không chỉ thế. Bằng bất cứ cách nào bạn làm cho Form mất Focus vd. nhấn "lá cờ Windows" thì sau khi click vào Form bạn không nhìn thấy caret trong text box.
Rõ ràng đây là lỗi của Excel.
Có thể khắc phục nửa vời. Nửa vời vì bạn không khắc phục được lỗi trên nhưng khi Form được show thì bạn có thể trong Activate thực hiện SetFocus vào textbox tùy ý (bạn thử thêm 3 textbox rồi SetFocus vào textbox bất kỳ). Làm như thế nào?
Trong code của bạn Tuân trong Initialize của UserForm1 bạn bỏ dòng "SetParent hForm2, hForm" còn trong Acivate của UserForm2 bạn SetFocus cho textbox. Nếu bạn muốn có caret trong textbox đầu tiên thì bạn chả cần SetFocus làm gì vì "tự nó sẽ có".

Không phải vậy Anh ơi, ý em là đổi desktop background đó mà, không hiện 2 form lên 1 lúc nên ta không cần thiết phải show modal. Chỉ là tạm thời tắt chế độ Icon trên desktop, sau đó thay đổi cái backgound của màn hình bằng cái hình của mình, sau đó, trả lại cái hình cũ của máy rồi hiện lại Icon thôi. Thủ công mình làm cũng được mà, nhưng với code thì em đâu biết làm nên mới hỏi vậy mà Anh.
 
Tôi nghĩ chỉ là có một màn hình nền phủ toàn màn hình thì không nên can thiệp vào Background của hệ điều hành (HĐH), càng không nên "thịt" Explorer của nó (sẽ mất hết các thư mục đang mở, có thể ảnh hưởng tới các tiền trình khác mà HĐH đang phục vụ.

Giải pháp của tôi là tạo 2 form: form1 làm nền, form2 là điều khiển chính, nổi trên form1 (form2 là con của form1).
Trong Form1 code như sau:
Mã:
Option Explicit


Private Sub Form_Initialize()
   'Lấy handle của form
[B]    [COLOR=#ff0000]#[/COLOR]If VBA6 Then [COLOR=#008000]'Nếu code dùng cho VBA[/COLOR]
        hForm = FindWindow("ThunderDFrame", Me.Caption)
    [COLOR=#ff0000]#[/COLOR]Else [COLOR=#008000]'Trong VB6[/COLOR]
        hForm = hwnd
        [COLOR=#008000]'BorderStyle = None 'Thiết lập ở chế độ design. Có thể bỏ qua [/COLOR]
   [COLOR=#ff0000] #[/COLOR]End If[/B]
    [COLOR=#008000]'Loại bỏ tiêu đề, đường viền của form1 [/COLOR]
    SetWindowLong hForm, GWL_STYLE, GetWindowLong(hForm, GWL_STYLE) And Not (WS_BORDER Or WS_CAPTION Or WS_THICKFRAME Or WS_DLGFRAME)
    SetWindowLong hForm, GWL_EXSTYLE, GetWindowLong(hForm, GWL_EXSTYLE) And Not WS_EX_DLGMODALFRAME
    Dim rc As RECT
    [COLOR=#008000]'Lấy độ rộng, cao của màn hình  [/COLOR]
    GetWindowRect GetDesktopWindow, rc
    [COLOR=#008000]'Thiết lập độ rộng, độ cao của form1 cho toàn màn hình  [/COLOR]
    SetWindowPos hForm, 0, rc.Left, rc.Top, rc.Right, rc.Bottom, SWP_FRAMECHANGED
    Form1.Show vbModeless [COLOR=#008000]'Nếu trong VBA phải thiết lập ở chế độ thiết kế (design mode) là Userform1.ShowModal = False [/COLOR]
    [COLOR=#008000]'Tạo quan hệ form2 là con của form1  [/COLOR]
    SetParent Form2.hwnd, hForm
End Sub

Em có một thắc mắc, vì sao có những dấu # ở đằng trước IF? Nó có dụng ý gì vậy?
 
Không phải vậy Anh ơi, ý em là đổi desktop background đó mà, không hiện 2 form lên 1 lúc nên ta không cần thiết phải show modal. Chỉ là tạm thời tắt chế độ Icon trên desktop, sau đó thay đổi cái backgound của màn hình bằng cái hình của mình, sau đó, trả lại cái hình cũ của máy rồi hiện lại Icon thôi. Thủ công mình làm cũng được mà, nhưng với code thì em đâu biết làm nên mới hỏi vậy mà Anh.

Bạn nói là làm thủ công được rồi?
Bạn hãy làm thủ công rồi chụp cái hình mà trong đó UserForm (chỉ UserForm thôi không có cửa sổ Sheet) "ngồi chễm chệ" trên màn hình cho tôi xem mặt mũi chúng như thế nào nhé.
---------
Mà thôi.
Nghĩa xem đúng ý chưa.
Trong Activate tôi setfocus cho textbox2. Nếu cần cho texbox1 thì chả cần setfocus, tự nó có.
--------
À, có một vấn đề như thế này.
1. code chỉ làm việc với UserForm có ShowModal = FALSE
2. Với code hiện thời nếu trong khi UserForm được hiển thị mà ta giải lao tí và chuyển sang làm việc với sheet (click vào Book1.xls trên taskbar) thì cửa sổ sheet nó che hình nền. Nếu ta click vào nút "-" để kéo nó xuống thì UserForm cũng xuống theo. Vậy ta sửa chút code:

a. thêm trong Module1:

Mã:
Private Const SW_SHOW = 5
Public Sub MinimizeApp()
    ShowWindow FindWindow("XLMAIN", Application.Caption), SW_MINIMIZE
    ShowWindow hForm, SW_SHOW
End Sub

b. trong UserForm thêm:

Mã:
Private Sub UserForm_Click()
    MinimizeApp
End Sub

c. Khi làm việc xong với sheet mà muốn "kéo nó xuống" thì click trên Form
 

File đính kèm

Lần chỉnh sửa cuối:
Bạn nói là làm thủ công được rồi?
Bạn hãy làm thủ công rồi chụp cái hình mà trong đó UserForm (chỉ UserForm thôi không có cửa sổ Sheet) "ngồi chễm chệ" trên màn hình cho tôi xem mặt mũi chúng như thế nào nhé.
---------
Mà thôi.
Nghĩa xem đúng ý chưa.
Trong Activate tôi setfocus cho textbox2. Nếu cần cho texbox1 thì chả cần setfocus, tự nó có.
--------
À, có một vấn đề như thế này.
1. code chỉ làm việc với UserForm có ShowModal = FALSE
2. Với code hiện thời nếu trong khi UserForm được hiển thị mà ta giải lao tí và chuyển sang làm việc với sheet (click vào Book1.xls trên taskbar) thì cửa sổ sheet nó che hình nền. Nếu ta click vào nút "-" để kéo nó xuống thì UserForm cũng xuống theo. Vậy ta sửa chút code:

a. thêm trong Module1:

Mã:
Private Const SW_SHOW = 5
Public Sub MinimizeApp()
    ShowWindow FindWindow("XLMAIN", Application.Caption), SW_MINIMIZE
    ShowWindow hForm, SW_SHOW
End Sub

b. trong UserForm thêm:

Mã:
Private Sub UserForm_Click()
    MinimizeApp
End Sub

c. Khi làm việc xong với sheet mà muốn "kéo nó xuống" thì click trên Form

Đúng ý em rồi Anh ơi, phải nói là rất tuyệt vời! Mình chỉ thay màn hình rồi trả lại sẽ tốt hơn mình "thịt" thằng Explorer rồi nuốt không trôi phải "nhả" ra. Khi thịt nó, hình như ta mất luôn kết nối với Net hay sao đó, vì vậy khi trả lại nó sẽ phục hồi, mình có cảm giác chậm và chớp chớp khó chịu. Em chỉ nói hình như thôi, không chắc chắn lắm.

Cám ơn Anh rất nhiều!
 
Em có một thắc mắc, vì sao có những dấu # ở đằng trước IF? Nó có dụng ý gì vậy?

Sử dụng # trước các lệnh để làm việc với môi trường và định hướng biên dịch. Trong ví dụ của mình sử dụng #IF..#Else..#End If để tự động nhận biết đang chạy trong VBA hay môi trường khác (VB6), nếu là VBA thì chạy khối lệnh trong VBA (nếu là môi trường VBA bạn viết code trong nhánh của #Else thì trình biên dịch không làm việc - dù viết lỗi cũng không kiểm tra gì.

Sử dụng phương pháp định hướng biên dịch (sử dụng #) thường với mục đích để viết code dùng chung, đảm bảo tương thích cho từng môi trường. Ví dụ bạn viết code chạy cho VBA, VB6, VBA32-bit, VBA64-bit.

Về ý đồ ẩn biểu tượng, thu nhỏ các cửa sổ có vẻ không ổn đâu, như máy của mình dùng một số ứng dụng chạy thường trú trên Desktop bị biến mất hoặc ẩn đâu đó mà không không phục lại được. Nếu làm ứng dụng phân phối cho nhiều người thì không nên can thiệp làm thay đổi giao diện người dùng của Hệ điều hành. Nếu có thay đổi thì phải hoàn trả ngay sau kthi lệnh đó thực thi xong (trong hàm hoặc thủ tục) chứ không phải đợi thoát ứng dụng.
 
Bạn nói là làm thủ công được rồi?
Bạn hãy làm thủ công rồi chụp cái hình mà trong đó UserForm (chỉ UserForm thôi không có cửa sổ Sheet) "ngồi chễm chệ" trên màn hình cho tôi xem mặt mũi chúng như thế nào nhé.
---------
Mà thôi.
Nghĩa xem đúng ý chưa.

Cho em hỏi thêm một vấn đề, tại sao nó chỉ nhận hình có đuôi *.bmp mà không nhận hình đuôi dạng khác? *.jpg chẳng hạn?

Anh có thể điều chỉnh lại cho em không? Đa dạng đuôi có được không?

Xin cám ơn Anh.
 
Cho em hỏi thêm một vấn đề, tại sao nó chỉ nhận hình có đuôi *.bmp mà không nhận hình đuôi dạng khác? *.jpg chẳng hạn?

Anh có thể điều chỉnh lại cho em không? Đa dạng đuôi có được không?

Xin cám ơn Anh.

JPG và các format khác chỉ là khi "nằm" trên đĩa thôi. Khi đọc vào control (vd. Picture, trong Paint ...) chúng đều được convert sang bitmap.
Về wallpaper thì bạn có thể chọn "bằng tay" tập tin JPG làm hình nền vì sau khi bạn chọn xong thì Windows convert nó sang BMP và "save as" ở chỗ khác với tên "Wallpaper.bmp"
Bạn có thể thấy tận mắt bằng cách: Trong Sub ShowDesktopIcons sau dòng
SystemParametersInfo SPI_GETDESKWALLPAPER, 256, defWallPaper, 0
bạn viết thêm dòng
Debug.Print defWallPaper
Sau khi đọc được defWallPaper thì bạn đi theo đường dẫn và mở tập tin Wallpaper.bmp thì bạn thấy nó chính là ảnh JPG mà bạn đã chọn.
Mỗi lần bạn đổi wallpaper bằng tay thì tập tin JPG bạn chọn được convert sang bitmap và ghi trong thư mục "ấy" với tên wallpaper.bmp. Windows sẽ dùng cái BMP này để làm hình nền.
------------
Nếu bạn muốn chọn JPG cũng được thôi nhưng bạn phải convert nó sang BMP, thế thôi.
Bạn hãy chạy ví dụ sau:

Mã:
Sub Button1_Click()
    Filename = Application.GetOpenFilename("JPG files (*.jpg),*.jpg,GIF files (*.gif),*.gif")
    If Filename <> False Then
        SaveAsBMP Filename
    End If
End Sub

Sub SaveAsBMP(ByVal picFilename As String)
Dim ext As String, pic As IPictureDisp, k As Long
    k = InStrRev(picFilename, ".")
    ext = LCase(Mid(picFilename, k))
    If ext <> ".bmp" Then
        Set pic = LoadPicture(picFilename)
        SavePicture pic, Left(picFilename, k - 1) & ".bmp"
        Set pic = Nothing
    End If
End Sub

Tức khi đã chọn được ảnh rồi thì gọi sub SaveAsBMP và truyền đường dẫn vào. SaveAsBMP sẽ ghi ở cùng thư mục với cùng tên nhưng định dạng là BMP. Bạn có thể thay đổi, vd. thư mục ghi. Khi thay hình nền thì truyền đường dẫn của BMP chứ không phải đường dẫn của ảnh chọn.
Chú ý là SavePicture luôn ghi trên đĩa ở dạng BMP. Vậy nếu bạn gọi:
SavePicture pic, "c:\hichic.TXT"
thì nó vẫn ghi trên đĩa với tên hichic.TXT nhưng thực chất "lõi" là BMP - nếu bạn mở trong HexEditor thì 2 bai đầu sẽ là 42, 4D, tức "BM". Đổi đuôi lại thành hichic.bmp thì mở ra thấy ảnh.
 
Về ý đồ ẩn biểu tượng, thu nhỏ các cửa sổ có vẻ không ổn đâu, như máy của mình dùng một số ứng dụng chạy thường trú trên Desktop bị biến mất hoặc ẩn đâu đó mà không không phục lại được. Nếu làm ứng dụng phân phối cho nhiều người thì không nên can thiệp làm thay đổi giao diện người dùng của Hệ điều hành. Nếu có thay đổi thì phải hoàn trả ngay sau kthi lệnh đó thực thi xong (trong hàm hoặc thủ tục) chứ không phải đợi thoát ứng dụng.

Theo em thấy thì trên desktop khi click phải có mục check Show Desktop Icons nếu bỏ check thì không nhìn thấy Icons nữa, khi cần thì mình lại check, như thế theo em nghĩ thì cũng đâu ảnh hưởng gì đến tất cả các chương trình đang chạy hay không chạy đâu Anh? Dùng code để thực hiện nó chỉ là biên dịch lại cái công đoạn mình check thủ công thôi. Không biết điều gì khiến Anh nghĩ là ảnh hưởng đến các chương trình đang chạy vậy? Không biết nên muốn hỏi cho rõ anh à.
 
Tức khi đã chọn được ảnh rồi thì gọi sub SaveAsBMP và truyền đường dẫn vào. SaveAsBMP sẽ ghi ở cùng thư mục với cùng tên nhưng định dạng là BMP. Bạn có thể thay đổi, vd. thư mục ghi. Khi thay hình nền thì truyền đường dẫn của BMP chứ không phải đường dẫn của ảnh chọn.
Chú ý là SavePicture luôn ghi trên đĩa ở dạng BMP. Vậy nếu bạn gọi:
SavePicture pic, "c:\hichic.TXT"
thì nó vẫn ghi trên đĩa với tên hichic.TXT nhưng thực chất "lõi" là BMP - nếu bạn mở trong HexEditor thì 2 bai đầu sẽ là 42, 4D, tức "BM". Đổi đuôi lại thành hichic.bmp thì mở ra thấy ảnh.

Một thắc mắc nữa là khi chạy thủ tục:

PHP:
Sub HideIcon()
    ShowDesktopIcons False
End Sub

Em thử click phải trên desktop, về bản chất thì nó đã không hiện Icon, nhưng trên Menu thì nút Show Desktop Icons nó vẫn check, vậy tại sao có hiện tượng này vậy, xin Anh vui lòng giải thích ạ.

Khi bấm thử vào nó thì nó lại tiếp tục Hide một lần nữa, tức là khi ta cho hiện lại màn hình cũ thì Icons không được hiện ra.
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    61.7 KB · Đọc: 62
Theo em thấy thì trên desktop khi click phải có mục check Show Desktop Icons nếu bỏ check thì không nhìn thấy Icons nữa, khi cần thì mình lại check, như thế theo em nghĩ thì cũng đâu ảnh hưởng gì đến tất cả các chương trình đang chạy hay không chạy đâu Anh? Dùng code để thực hiện nó chỉ là biên dịch lại cái công đoạn mình check thủ công thôi. Không biết điều gì khiến Anh nghĩ là ảnh hưởng đến các chương trình đang chạy vậy? Không biết nên muốn hỏi cho rõ anh à.

Ah, mình thấy các cửa sổ bị thu nhỏ hoặc ẩn trong hàm "Enum....". Thói quen của người dùng Windows thường thao tác trên nhiều cửa sổ một lúc, đăng chạy cái A thì lại chạy cái B nên nếu ẩn các icon để phục vụ cho App của mình thì có không hợp lý lắm.
 
Ah, mình thấy các cửa sổ bị thu nhỏ hoặc ẩn trong hàm "Enum....". Thói quen của người dùng Windows thường thao tác trên nhiều cửa sổ một lúc, đăng chạy cái A thì lại chạy cái B nên nếu ẩn các icon để phục vụ cho App của mình thì có không hợp lý lắm.

Tất cả các cửa sổ chỉ bị kéo xuống thanh tác vụ chứ không bị ẩn và người dùng luôn có thể kích hoạt chúng - các cửa sổ không bị ẩn mà chỉ bị minimize.
Chỉ có ListView với các icons bị ẩn.

Chắc chắn việc kéo các cửa sổ xuống thanh tác vụ mỗi ngày mỗi người làm 1000 lần. Việc thay hình nền, ẩn icons cũng là việc bình thường mà thỉnh thoảng mỗi người vẫn làm. Nếu việc làm đó nguy hiểm thì Windows không bao giờ tạo khả năng cho user như thế.

Nói cho cùng đã là phần mềm thì nó có thể chạy trên nền, chạy ẩn. Và mọi thao tác: mở ghi tập tin, thư mục, nối mạng, khởi động máy in v...v tóm lại mọi việc đều làm được mà chả cần tới cái gọi là Explorer.
Explorer cần cho user, nó tạo ra giao diện để cho người dùng có thể mở tập tin, ứng dụng, duyệt web, in ấn v...v
Người dùng cần Explorer chứ phần mềm đâu có cần trung gian của Explorer?
Tôi chưa gặp phần mềm kỳ cục kiểu: muốn chạy được thì thư mục abc phải mở hay cửa sổ xyz phải không bị minimized, hoặc hình nền phải là thế này thế này.

Ẩn các cửa sổ đúng không phải là cách "an toàn" tuyệt đối nhưng còn chuyện thay màn hình, ẩn icons, minimize các cửa sổ thì bản thân Windows tạo điều kiện thuận lợi nhất cho user thực hiện, và bản thân user cũng thao tác liên tục (về minimize các cửa sổ, còn thay hình nền thì thỉnh thoảng thôi)

Cuối cùng thì bạn nên để ý tới một điều: Cái ẩn icons là do người dùng cụ thể (ở đây là Nghĩa) muốn như thế. Code được viết cho khách cụ thể, theo đơn đặt hàng cụ thể, với yêu cầu cụ thể. Khách hàng này trên máy của mình thì vừa là người dùng vừa là chủ nên họ muốn thế nào thì kệ họ mà. Người dùng biết "phần mềm" làm gì mà vẫn kích hoạt thì có nghĩa là họ kích hoạt có ý thức, chủ ý, và sẵn sàng chấp nhận những hạn chế có thể có do phần mềm gây ra.
Bản thân tôi cũng đã nói ngay từ bài đầu là người ta bầy ra lắm trò cũng chỉ là cố tình làm thế để phô trương cái gì đấy, "dọa" ai đấy. Vì nói cho cùng thì nếu hình nền đó là cần thiết (logo, e-mail, web ...) thì vẫn có thể làm 1 Form to bằng màn hình và ảnh thì làm hình nền trong Form. Cứ đâu phải Form "nằm" trên hình?
 
Thực ra qua bài viết của anh thì các thành viên cũng biết thêm các kỹ thuật can thiệp Desktop,...cũng là học hỏi. Em chỉ góp ý với Nghĩa là thế vì thực sự máy em có các cửa sổ của ứng dụng chạy trên Desktop (không phải loại Window có title) bị thu nhỏ không thể khôi phục lại bằng chuột.
 
Một thắc mắc nữa là khi chạy thủ tục:

PHP:
Sub HideIcon()
    ShowDesktopIcons False
End Sub

Em thử click phải trên desktop, về bản chất thì nó đã không hiện Icon, nhưng trên Menu thì nút Show Desktop Icons nó vẫn check, vậy tại sao có hiện tượng này vậy, xin Anh vui lòng giải thích ạ.

Ta khởi động ở trạng thái mà Show Desktop Icons được chọn.
Sau khi mở Form thì mặc dù icons bị dấu đi nhưng "Show Desktop Icons" vẫn được chọn. Vì ta tự ẩn SysListView đi nhưng ta có báo cho system biết đâu?

Khi bấm thử vào nó thì nó lại tiếp tục Hide một lần nữa, tức là khi ta cho hiện lại màn hình cũ thì Icons không được hiện ra.

Vì đối với nó thì "Show Desktop Icons" vẫn đang được chọn, vậy nó ẩn đi và bỏ chọn "Show Desktop Icons" là "hợp lý" rồi.
Theo tôi nếu bạn thay đổ trạng thái của "Show Desktop Icons" (đang chọn sang bỏ hoặc đang bỏ sang chọn) thì trước khi đóng Form cần trả về như cũ. Vì nếu bạn bỏ chọn "Show Desktop Icons" thì làm sao bạn đòi system phải hiển thị icons? Vì code chỉ hiển thị lại SysListView. Vị ListView này làm việc ở chế độ Report, tức hiển thị icons và text. Code hiển thị ListView nhưng nó có hiển thị icons hay không thì có lẽ nó dựa vào trạng thái "Show Desktop Icons" mà bạn đã đổi sang bỏ chọn rồi còn gì.
Tôi ẩn ông A thì dĩ nhiên không nhìn thấy huy chương ông ta đang đeo trên ngực. Nhưng hiển thị lại ông A cũng không đồng nghĩa với chuyện sẽ nhìn thấy huy chương trên ngực ông A. Vì đeo hay không do ông A quyết định và có thể một lúc trước đó ông ta đã ẩn huy chương vào túi rồi.
 
Ta khởi động ở trạng thái mà Show Desktop Icons được chọn.
Sau khi mở Form thì mặc dù icons bị dấu đi nhưng "Show Desktop Icons" vẫn được chọn. Vì ta tự ẩn SysListView đi nhưng ta có báo cho system biết đâu?



Vì đối với nó thì "Show Desktop Icons" vẫn đang được chọn, vậy nó ẩn đi và bỏ chọn "Show Desktop Icons" là "hợp lý" rồi.
Theo tôi nếu bạn thay đổ trạng thái của "Show Desktop Icons" (đang chọn sang bỏ hoặc đang bỏ sang chọn) thì trước khi đóng Form cần trả về như cũ. Vì nếu bạn bỏ chọn "Show Desktop Icons" thì làm sao bạn đòi system phải hiển thị icons? Vì code chỉ hiển thị lại SysListView. Vị ListView này làm việc ở chế độ Report, tức hiển thị icons và text. Code hiển thị ListView nhưng nó có hiển thị icons hay không thì có lẽ nó dựa vào trạng thái "Show Desktop Icons" mà bạn đã đổi sang bỏ chọn rồi còn gì.
Tôi ẩn ông A thì dĩ nhiên không nhìn thấy huy chương ông ta đang đeo trên ngực. Nhưng hiển thị lại ông A cũng không đồng nghĩa với chuyện sẽ nhìn thấy huy chương trên ngực ông A. Vì đeo hay không do ông A quyết định và có thể một lúc trước đó ông ta đã ẩn huy chương vào túi rồi.

Có một lần em nhớ man mác đã đọc bài của ai đó đã dùng API can thiệp vào cái gì đó của hệ thống hay Excel gì đó, mà khi đang thực hiện thì cái nút trên menu đó dấu mark vẫn còn đó, song nó lại Enable = False vì thế không thể can thiệp thủ công khi đang chạy thủ tục được. Sau khi chạy thủ tục xong thì nó tự reset lại như ban đầu. Nhưng em nghĩ cái này cũng chỉ là tiểu tiết, quan trọng là em học được từ Anh và anh Tuân việc can thiệp vào hệ thống như thế nào, cách giải quyết ra sao v.v...

Thực ra qua bài viết của anh thì các thành viên cũng biết thêm các kỹ thuật can thiệp Desktop,...cũng là học hỏi. Em chỉ góp ý với Nghĩa là thế vì thực sự máy em có các cửa sổ của ứng dụng chạy trên Desktop (không phải loại Window có title) bị thu nhỏ không thể khôi phục lại bằng chuột.

Có thể anh Tuân nói đúng, khi em thử thủ tục Minimize ở WinXP thì cảm giác nó hoàn hảo, nhưng với Win7 nó có một vấn đề là form nổi lên đồng thời nổi lên thêm một thanh lạ trên màn hình vì vậy cũng ngại khi sử dụng thủ tục này, nhìn hình có thể giải thích được vấn đề gì đang xảy ra không ạ?
 

File đính kèm

  • ThanhLa.jpg
    ThanhLa.jpg
    104.3 KB · Đọc: 67
Nhìn Video chúng ta thấy rõ ràng là bị lỗi do "thu nhỏ tất cả các cửa sổ":

[video=youtube_share;x3UgROOtTvE]http://youtu.be/x3UgROOtTvE[/video]



Vấn đề trên bị phát sinh là do thủ tục này:

PHP:
EnumWindows FuncPtr(AddressOf EnumWindowsProc), 0


Em thấy rằng ngoài cách thu nhỏ của Anh thì còn có nhiều cách khác, như:

PHP:
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

Sub MinimumAllWindow()
    Call keybd_event(&H5B, 0, 0, 0)
    Call keybd_event(&H4D, 0, 0, 0)
    Call keybd_event(&H5B, 0, &H2, 0)
End Sub

Nhưng cách này không thể làm cho con trỏ setfocus trên form được. Vì thế theo em chọn cách dưới đây, tạm thời em cho rằng nó ổn định và setfocus trên form như ý:

PHP:
Sub WindowMinAll()
    CreateObject("Shell.Application").MinimizeAll
    Application.Wait Now + TimeValue("00:00:01")
End Sub

Qua đó, thủ tục khi load form như sau:

PHP:
Private Sub UserForm_Initialize()
      ShowDesktopIcons False
      hForm = FindWindow("ThunderDFrame", UserForm1.Caption)
      Call WindowMinAll
End Sub

Và thoát form thì màn hình excel sẽ trở về trạng thái ban đầu:

PHP:
Private Sub UserForm_Terminate()
      ShowDesktopIcons True
      Application.WindowState = xlMaximized
End Sub

Không biết em làm như vậy có hợp lý không, xin cho em lời khuyên.
 

File đính kèm

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

Back
Top Bottom