Qt 如果鼠标在窗口外单击,则关闭窗口小部件窗口

Qt 如果鼠标在窗口外单击,则关闭窗口小部件窗口,qt,Qt,这是一个鸡和蛋的问题。我想我的窗口小部件关闭时,鼠标点击外面。据我所知,我的小部件在外部点击时不会出现鼠标事件。有一个SetFocus插槽,但它的对应项或焦点丢失在哪里?“focusOutEvent”在我的课堂上没有被调用 我的小部件窗口是一个小部件的子窗口,它总是显示在我的主窗口上,是一个“Qt::ToolTip”,所以我认为可能会出现一些问题。有办法吗 我的目标是:我有一个自定义工具栏小部件,上面的按钮可能有“下拉”小部件。这些下拉小部件没有标准的windows框架。我不希望他们从主窗口“窃

这是一个鸡和蛋的问题。我想我的窗口小部件关闭时,鼠标点击外面。据我所知,我的小部件在外部点击时不会出现鼠标事件。有一个SetFocus插槽,但它的对应项或焦点丢失在哪里?“focusOutEvent”在我的课堂上没有被调用

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

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


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

如果你的小部件可以有焦点,并“窃取”一些其他小部件的标题焦点,那会更容易。类似这样的方法可能会奏效:

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();
完成了!嗯,我想不是很安静。首先,您不希望工具栏小部件首先获得任何焦点。第二,您希望用户能够单击任意位置并隐藏工具栏小部件。 因此,您可以跟踪您创建的每个工具栏小部件。例如,在“QList ttWidgets”成员变量中。然后,无论何时创建新的工具栏小部件,都要执行以下操作:

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)函数,并在那里查找这些事件。

我使用了:

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

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

您可以使用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();

}

这对我来说很有用,因为我不需要从主应用程序中获取焦点:

h

.cpp


OP自己的答案对于4.8以下的Qt版本很好,但正如他们在答案中所提到的,它对4.8以上的版本不起作用。当鼠标在小部件外部单击时,Qt::Popup小部件不会消失,它将接收所有通常会关闭它的输入


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

这正是popup窗口是用于。据我所知,组合框显示的小部件是显示为弹出窗口的小部件,这听起来像是您想要做的。在Qt 4.8中,这种技术停止工作。但在4.7.4中效果很好。在Qt 5.9.2中,我可以在主窗口“失去焦点”(单击出或tab out)时隐藏它。这比使用
StrongFocus
策略的
focusOutEvent
效果更好,该策略给出了非常不一致的结果。不幸的是,我可以确认
Qt::Popup
确实在GNU/Linux上窃取了Qt 5.14.1中的焦点。如果您在小部件中有一个LineEdit控件,当您单击LineEdit时,整个小部件似乎都会消失。ob显然,
eventFilter
示例将永远递归
bool eventFilter(QObject *obj, QEvent *event) override;
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);