【问题标题】:How to show a window that acts like a popup menu?如何显示一个像弹出菜单一样的窗口?
【发布时间】:2010-02-01 17:00:15
【问题描述】:

当显示窗口 A 时,我想显示另一个非模态弹出窗口 B,但是:

  1. 我不希望窗口 A 由于窗口 B 成为前窗口而变为非活动状态;
  2. 我希望当窗口 B 获得焦点时,我一键下拉窗口 A 上的组合框控件(通常您必须单击两次,一次用于将焦点移动到窗口 A,第二次用于下拉组合框);

如您所见,我想要的窗口 B 类似于一个更有用的弹出窗口,如弹出菜单(当您希望它通过单击任何按钮离开时,它比一般的非模态窗口的障碍更小)父窗口的其他部分)。

我的问题清楚吗? 谢谢。

【问题讨论】:

    标签: delphi winapi popup


    【解决方案1】:

    我为“1”找到的最简单的解决方案是在弹出表单被激活后立即向调用表单发送 WM_NCACTIVATE(在 WM_ACTIVATE 处理程序中),以便调用表单将其标题与活动颜色。您必须在弹出表单中有调用表单的引用才能实现此目的。

    对于“2”,您可以在同一个 WM_ACTIVATE 处理程序中释放弹出表单,这不会吃掉转到调用表单的点击。

    等等。像这样应该去弹出窗体;

    type
      TForm2 = class(TForm)
        [..]
      private
        FOwner: TForm;
        procedure WmActivate(var Msg: TWMActivate); message WM_ACTIVATE;
      public
        constructor Create(AOwner: TComponent); override;
    
    [...]
    constructor TForm2.Create(AOwner: TComponent);
    begin
      if not (AOwner is TForm) then
        raise Exception.Create('Owner should be TForm');
      FOwner := TForm(AOwner);
      inherited;
    end;
    
    procedure TForm2.WmActivate(var Msg: TWMActivate);
    begin
      SendMessage(FOwner.Handle, WM_NCACTIVATE, Ord(Msg.Active <> WA_INACTIVE), 0);
      inherited;
      if Msg.Active = WA_INACTIVE then
        Release;
    end;
    

    并提供调用表单作为弹出表单的所有者;

    procedure TForm1.Button1Click(Sender: TObject);
    var
      PopForm: TForm2;
    begin
      PopForm := TForm2.Create(Self);
      [..]
    


    FWIW,我同意loursonwinnyUlrich。 IMO 弹出式表单看起来比它看起来更复杂。尽管在 SpTBXFormPopupMenu 的情况下,您必须安装两个库,TB2KSpTBXLib。至少浏览资源可以暗示可能涉及的内容。

    【讨论】:

    • 在 Button1Click 上我不创建表单只是显示它(但分配 FOwner 变量)。为什么我在第二次点击后得到 AV 错误? (如果我从 TForm2 中删除 WmActivate 程序,AV 错误就会消失)
    • @SAM - 可能您在发布表单后正在访问它。不过我不能肯定...
    • @Sertac Akyuz 我不会发布它!我没有创建它只是显示它。
    【解决方案2】:

    为了防止窗口获得焦点,您必须指定WS_EX_NOACTIVATE 扩展窗口样式(Windows 2000 及更高版本)或处理WM_MOUSEACTIVATE 并返回MA_NOACTIVATE

    【讨论】:

    • 谢谢 Koro,我希望第二个获得焦点,但不会使调用者表单的标题栏变为非活动状态。
    【解决方案3】:

    我可以用它来不失去焦点:

    SetWindowPos(Form2.Handle, HWND_TOP, 0, 0, 0, 0,
      SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
    

    第二部分没看懂。

    【讨论】:

      【解决方案4】:

      spTBXLib 中的 SpTBXFormPopupMenu 完成这项工作。

      转到http://www.silverpointdevelopment.com/sptbxlib/index.htm 并查找“表单弹出窗口”

      关键似乎是容器'popuped'必须继承TPopupMenu。但是处理很复杂,你可以在代码中自己看到。我的建议是按原样使用它,因为 Robert Lee 做得很好。

      【讨论】:

      • 我已经知道了,这与我想要的相似,但它不符合我在问题中描述的两个要求。
      【解决方案5】:

      我自己在这里找到了解决方案。谢谢大家!:

      Keep Window Inactive In Appearance Even When Activated

      【讨论】:

        【解决方案6】:

        我找到了一个几乎完全符合我要求的:TAdvStickyPopupMenu

        【讨论】:

        • 我认为这并不能完全回答这个问题。您能否详细说明一下它是如何实现问题中的“1”和“2”的。
        • @Sertac,也许我很难解释,但我会尝试 ;) 首先我可以在 TAdvStickyPopupMenu 中使用任何控件,包括 tpanel 或 tframe,所以我可以将其用作弹出窗口我的 tpanel 的容器(模拟表单),单击 tpanel 不会隐藏菜单,因此我可以模拟弹出表单。这种方法如何实现问题中的“1”和“2”?
        • 当你弹出菜单时(上面有一个模拟表单),你会感觉你还在处理父表单,这意味着有弹出表单和父表单之间不需要切换。通过切换我的意思是额外的鼠标点击需要先聚焦表单,然后才能操作表单上的控件。如果您将其与上面提到的下拉表单和 SpTbx 下拉列表进行比较,您会发现不同之处。如果您使用 Gmail,请尝试使用标签下拉弹出表单,您就会明白我的意思。
        • 感谢您的解释。快速浏览一下 TAdvStickyPopupMenu,我认为您已经改变了您的要求并选择了不同的路线,而我的回答 (stackoverflow.com/questions/2178494/2192590#2192590) 实际上确实满足了该问题的要求。好吧,也许我首先以某种方式误解了这个问题,所以如果你能够编辑无论如何你的答案,那么我将允许我撤销我的反对票。再次感谢。
        • 嗨 Sertac,我认为首先我没有很好地描述我的问题,我认为满足我的要求我需要使用弹出表单,所以我直接问了最初的问题,但实际上我在这里的解释是最终要求...我可以选择您的回复作为答案,但是您的方法会阻止弹出表单获得​​用户输入吗?你知道我需要在弹出表单上使用一个 TList 控件来允许用户选择一个值。
        猜你喜欢
        • 2013-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多