【问题标题】:Keep form on top of other application windows将表单置于其他应用程序窗口之上
【发布时间】:2017-06-17 16:57:15
【问题描述】:

我正在尝试展示一个位于所有其他应用程序之上的 VCL 表单,以便可以将数据从该表单复制到另一个应用程序,而无需在前面的两个应用程序之间来回切换。

我可以显示一个表单并将其置于所有其他应用程序之上,并使用 fsStayOnTop 与其他应用程序交互并使用以下代码打开它:

form := TForm2.Create(nil);

SetWindowPos(form.Handle, // handle to window
    HWND_TOPMOST, // placement-order handle
    form.Left, // horizontal position
    form.Top, // vertical position
    form.Width, form.Height,
    // window-positioning options
    SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

form.Show();

我目前遇到的问题是,当我单击表单以复制并粘贴数据时,我的应用程序的其他表单也被提出来,这隐藏了我将数据复制到的应用程序。主应用程序表单使用 ShowModal 打开一个 TForm1,然后可以使用上面的代码打开 TForm2,我认为这会保持它向前推进 TForm1,因为它不应该有所有者或父级。

我已经看过这个问题How can get my form to be on top of everything all the time?,不幸的是它并没有阻止其他表格被提出。

所以当 TForm2 聚焦时我想要的窗口顺序是:

mainform
TForm1
Whatever application, normally word
TForm2

相反,我得到了

Whatever application, normally word
mainform
TForm1
TForm2

我知道这个功能看起来有点奇怪,但它对于提高可用性很重要,主要是在单显示器机器上,因为用户可能会频繁地在我的表单和其他应用程序之间切换。

我目前在 Windows 10 Professional 64 位上使用 Delphi 10 Seattle,以防万一。

超级简单的例子

(如果有更好的方法来提供上述示例,我很想知道):

Form1 按钮

procedure TForm1.Button1Click(Sender: TObject);
var
    form2: TForm2;
begin
    form2 := TForm2.Create(self);
    form2.ShowModal();
end;

Form2 按钮

procedure TForm2.Button1Click(Sender: TObject);
var
    form3: TForm3;
begin
    form3 := TForm3.Create(nil);

    SetWindowPos(form3.Handle, // handle to window
        HWND_TOPMOST, // placement-order handle
        form3.Left, // horizontal position
        form3.Top, // vertical position
        form3.Width, form3.Height,
        // window-positioning options
        SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

    form3.Show();
end;

Form3:FormStyle = fsStayOnTop

【问题讨论】:

  • 隐藏其他表单。
  • @Nat 谢谢你,我会试一试看看效果如何

标签: delphi vcl delphi-10-seattle


【解决方案1】:

感谢 Nat 建议隐藏其他表单,我利用从 How to get a list from all opened forms of my software? 找到的信息提出了这个解决方案

简单的解决方案

procedure TForm2.Button1Click(Sender: TObject);
var
    form3: TForm3;
    ii: integer;
begin
    for ii := 0 to Screen.FormCount - 1 do
        Screen.Forms[ii].Visible := false;

    form3 := TForm3.Create(nil);

    SetWindowPos(form3.Handle, // handle to window
        HWND_TOPMOST, // placement-order handle
        form3.Left, // horizontal position
        form3.Top, // vertical position
        form3.Width, form3.Height,
        // window-positioning options
        SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

    form3.ShowModal();
    form3.Free();

    for ii := 0 to Screen.FormCount - 1 do
        Screen.Forms[ii].Visible := true;
end;

我们的想法是简单地使用Screen.Forms/Screen.FormCount 循环遍历所有当前显示的表单并使它们不可见,然后在我们完成后再次使它们全部可见。

扩展解决方案

如果您的表单是使用Application.CreateForm() 创建的,并且只是显示和关闭但从未释放,那么这也会打开所有这些表单。我找到的解决方案是存储可见表单的列表,并只在最后使那些可见。

procedure TForm2.Button1Click(Sender: TObject);
var
    form3: TForm3;
    ii: integer;
    visibleForms: TList<TForm>;
begin
    visibleForms := TList<TForm>.Create();
    try
        for ii := 0 to Screen.FormCount - 1 do
        begin
            if Screen.Forms[ii].Visible then
                visibleForms.Add(Screen.Forms[ii]);
            Screen.Forms[ii].Visible := false;
        end;

        form3 := TForm3.Create(nil);

        SetWindowPos(form3.Handle, // handle to window
            HWND_TOPMOST, // placement-order handle
            form3.Left, // horizontal position
            form3.Top, // vertical position
            form3.Width, form3.Height,
            // window-positioning options
            SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

        form3.ShowModal();
        form3.Free();
    finally
        for ii := 0 to visibleForms.Count - 1 do
            visibleForms[ii].Visible := true;
        visibleForms.Free();
    end;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多