【问题标题】:Close Widget Window if mouse clicked outside of it如果鼠标在窗口外单击,则关闭窗口小部件
【发布时间】:2011-11-17 07:31:13
【问题描述】:

这是一个先有鸡还是先有蛋的问题。当鼠标在外面点击时,我希望我的小部件窗口关闭。据我了解,我的小部件不会有鼠标事件发生在它之外的点击。有一个 SetFocus 插槽,但它的对应物或焦点损失在哪里?我的课程没有调用“focusOutEvent”。

我的小部件窗口是一个小部件的子窗口,它总是显示在我的主窗口上,它是一个“Qt::ToolTip”,所以我认为这个事实可能会出现一些问题。有什么办法吗?

我的目标:我有一个自定义工具栏小部件,其上的按钮可能有“下拉”小部件。这些下拉小部件没有标准的窗口框架。我不希望它们从主窗口中“窃取”标题焦点,并且我希望它们在用户单击其区域外屏幕上的任何位置时立即消失。我很难找到一种不会在 Qt 上妥协的策略来完成这项工作。

我错过了什么吗? (我敢打赌)。

【问题讨论】:

    标签: qt


    【解决方案1】:

    我用过:

    setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
    

    这似乎在 OSX 和 Windows 上运行良好。我的窗口显示正确,不会从我的主窗口的标题中窃取焦点,并且只要我在它外部单击,就会正确调用焦点丢失事件。

    【讨论】:

    • 这正是弹出窗口的用途。据我所知,为组合框显示的小部件是显示为弹出窗口的小部件,这听起来像是您想要做的。
    • 在 Qt 4.8 中,这种技术停止工作。不过适用于 4.7.4。
    • 在 Qt 5.9.2 中为我工作,一旦主窗口“失去焦点”(点击或退出)就隐藏主窗口。这比使用StrongFocus 策略的focusOutEvent 效果更好,后者给出了非常不一致的结果。
    • 不幸的是,我可以确认Qt::Popup 确实在 GNU/Linux 上的 Qt 5.14.1 中抢走了焦点。
    【解决方案2】:

    如果您的小部件可以具有焦点,并“窃取”您的其他一些小部件的标题焦点,那就更容易了。像这样的东西可以工作:

    class ToolBarWidget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit ToolBarWidget(QWidget * parent = 0)
        {
            setFocusPolicy(Qt::ClickFocus);
        }
    
    protected:
        void focusOutEvent(QFocusEvent * event)
        {
            close();
        }
    }
    

    当您创建任何小部件时,您会这样做:

    ToolBarWidget * pWidget = new ToolBarWidget(this);
    pWidget->show();
    pWidget->setFocus();
    

    完成!好吧,我想不安静。首先,您不希望 ToolBarWidget 首先获得任何焦点。其次,您希望用户能够单击任意位置并隐藏 ToolBarWidget。 因此,您可以跟踪您创建的每个 ToolBarWidget。例如,在“QList ttWidgets”成员变量中。然后,每当您创建一个新的 ToolBarWidget 时,您都会这样做:

    ToolBarWidget * pWidget = new ToolBarWidget(this);
    pWidget->installEventFilter(this);
    pWidget->show();
    

    在您的主小部件类中,实现 eventFilter() 函数。比如:

    bool MainWidget::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::FocusOut ||
            event->type() == QEvent::KeyPress ||
            event->type() == QEvent::MouseButtonPress)
        {
            while (!ttWidgets.isEmpty()) {
                ToolBarWidget * p = ttWidgets->takeFirst();
                p->close();
                p->deleteLater();
            }
        }
        return MainWidget::eventFilter(obj, event);
    }
    

    这会奏效。因为这样,即使您的 ToolTabWidgets 没有获得焦点,主小部件中的其他一些小部件也会获得焦点。一旦这种情况发生变化(无论用户是点击了窗口外,还是点击了窗口内的另一个控件,或者在这种情况下,按下了键或鼠标按钮,控件都会到达 eventFilter() 函数并关闭所有选项卡小部件。

    顺便说一句,为了从其他小部件中捕获 MouseButtonPress、KeyPress 等,您也需要在它们上安装EventFilter,或者只需在主小部件中重新实现 QWidget::event(QEvent * event) 函数,并且在那里寻找那些事件。

    【讨论】:

    • 如果小部件中有 LineEdit 控件,当您单击 LineEdit 时,似乎整个小部件都会消失。
    • 显然,eventFilter 示例将永远递归
    【解决方案3】:

    你可以像这样使用 QDesktopWidget.h 来做到这一点

    void MainWindow::on_actionAbout_triggered()
    {
        AboutDialog aboutDialog;
        //Set location of player in center of display
        aboutDialog.move(QApplication::desktop()->screen()->rect().center() -aboutDialog.rect().center());
        // Adding popup flags so that dialog closes when it losses focus
        aboutDialog.setWindowFlags(Qt::Popup);
        //finally opening dialog
        aboutDialog.exec();
    
    }
    

    【讨论】:

      【解决方案4】:

      这对我有用,以便不从主应用程序中集中注意力:

      .h

      bool eventFilter(QObject *obj, QEvent *event) override;
      

      .cpp

      bool Notification::eventFilter(QObject *obj, QEvent *event)
      {
          if(event->type() == QEvent::MouseButtonPress)
              deleteLater();
      
          return QObject::eventFilter(obj, event);
      }
      ...
      // somewhere else (i.e. constructor, main window,...)
      qApp->installEventFilter(this);
      

      【讨论】:

        【解决方案5】:

        OP 自己的回答非常适合 4.8 以下的 Qt 版本,但正如他们在回答中提到的那样,它不适用于高于 4.8 的版本。 Qt::Popup 小部件不会在鼠标在小部件外部单击时消失,它会接收所有通常会关闭它的输入。

        经过进一步调查,这只是非对话框小部件的问题。使用 Qt::Popup 的 QDialog 将在用户在其外部单击时正确关闭,但任何其他 QWidget,如 QFrame,都不会。因此,为了解决 Qt 4.8 中的这种行为变化,只需将小部件包装在 QDialog 中即可。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-09
          • 2021-11-21
          • 1970-01-01
          • 2019-11-10
          相关资源
          最近更新 更多