将userform放在最上面,允许用户隐藏它

时间:2018-02-20 23:06:54

标签: vba excel-vba excel

我有一个运行单独进程的excel vba应用程序。在外部过程中,初始化具有中止按钮的进度指示器。对于最终用户而言,中止按钮可用是至关重要的。查看外部进程是否也很有用。

我希望将进度指示器/中止按钮放在外部进程的顶部。但我不会强迫用户形成一切。

我尝试使用findwindow / setwindowpos,导致以下问题:

如果我在运行进程之前初始化HWND_TOPMOST,那么无论用户想要什么,userform始终位于顶部。我发现这非常烦人,特别是如果出现某种错误,其中debuging窗口可能被非活动的vba用户窗体阻止。但是,工作簿仍然处于所需的背景中。

如果我使用HWND_TOP(在外部进程启动并运行之后),则激活整个工作簿(不仅仅是用户表单),然后隐藏外部应用程序的进度。与激活工作簿相比,它不是很有用。

是否有关于如何将用户表单放在外部应用程序前面的建议,同时仍然允许用户停用它?

代码段:

Option Explicit

' Code stolen with pride from various sources.
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) 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

Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1

Public Const HWND_TOP = 0
Public Const HWND_BOTTOM = 1
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2

Public id As Integer
Public ProgressForm As fProgress

' Main routine, launch application and progress indicator.
Sub LoadForm()

    Set ProgressForm = New fProgress
    ProgressForm.Show

    ' Force userform to front, makes it on top but does not allow reorder of windows.
    ForceToFront ProgressForm

    ' Run external process, notepad used for example.
    id = Shell("notepad", vbNormalFocus)

End Sub


' Routine to bring userform to front after the external program is up and running.
Sub TestBringToFront()
    BringToFront ProgressForm
End Sub

Sub BringToFront(fm As fProgress)
    Dim hwnd As Long, ret As Variant
    hwnd = FindWindow("ThunderDFrame", fm.Caption)
    ret = SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Sub

Sub ForceToFront(fm As fProgress)
    Dim hwnd As Long, ret As Variant
    hwnd = FindWindow("ThunderDFrame", fm.Caption)
    ret = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Sub

1 个答案:

答案 0 :(得分:0)

不幸的是,这是Windows和应用程序的指定行为。但是,我可以建议一些解决方法:

  1. 使用TOPMOST选项并使用户表单可点击,例如捕获ProgressForm_Click并在TOPMOST和NOTOPMOST状态之间切换。或者,可以在ProgressForm上使用“Always On Top”复选框,就像在任务管理器中一样。
  2. 使用TOP选项并将后面的工作簿窗口调整为尽可能小,或者甚至移到一边(在屏幕外),并在外部应用程序完成后恢复大小和位置。
  3. 使用ProgressForm.Show(vbModeless)和TOP
  4. 进行尝试可能是值得的。