检测QMainWindow/QDialog(Qt 4.8)移动结束

检测QMainWindow/QDialog(Qt 4.8)移动结束,qt,qt4,qdialog,qmainwindow,qt4.8,Qt,Qt4,Qdialog,Qmainwindow,Qt4.8,我在X11上使用Qt4.8.3 我需要知道当用户在屏幕上拖动窗口时, 这是为了读取最终位置并最终启动动画以将窗口位置调整为“允许”位置 我注意到,每个小动作都会调用QWidget::moveEvent,但这非常不方便,因为只有当用户释放鼠标按钮并且动作完全完成时,我才能执行位置检查(并最终启动动画) 这是真正的问题:当用户单击标题栏时,似乎没有办法检测鼠标释放事件(或获取鼠标按钮状态),因为它是由操作系统控制的,而不是由Qt控制的。 我还尝试了QWidget::x11event(XEvent*e

我在X11上使用Qt4.8.3

我需要知道当用户在屏幕上拖动窗口时, 这是为了读取最终位置并最终启动动画以将窗口位置调整为“允许”位置

我注意到,每个小动作都会调用
QWidget::moveEvent
,但这非常不方便,因为只有当用户释放鼠标按钮并且动作完全完成时,我才能执行位置检查(并最终启动动画)

这是真正的问题:当用户单击标题栏时,似乎没有办法检测鼠标释放事件(或获取鼠标按钮状态),因为它是由操作系统控制的,而不是由Qt控制的。 我还尝试了
QWidget::x11event(XEvent*e)
…但是事件只在窗口中收集,而不是在标题栏中收集

有人知道实现这一目标的方法吗


<>我怀疑我自己必须重新实施标题栏…太糟糕了…

让我们考虑下面的测试应用: main.cpp

如您所见,有两个移动事件,一个是在应用程序最初创建时,另一个是在我完成窗口移动后。我用Qt4.8.1和XOrg 7.6进行测试

检查原始X事件的步骤

  • 让测试应用程序运行
  • 获取测试应用程序的窗口Id。为此,请在命令行
    xwininfo-name WINDOW\u name
    中执行,其中
    WINDOW\u name
    是测试应用程序窗口的名称。另一个选项是使用不带参数的xwininfo,然后必须用鼠标指针选择测试应用程序窗口
  • 运行X事件监视器
    xev-id 0x2a00002
    ,其中
    0x2a00002
    是在上一步中找到的窗口id。这将打印窗口从X服务器接收的X事件
    ConfigureNotify
    QMoveEvent
    的X协议对应项

  • 让我们考虑下面的测试应用: main.cpp

    如您所见,有两个移动事件,一个是在应用程序最初创建时,另一个是在我完成窗口移动后。我用Qt4.8.1和XOrg 7.6进行测试

    检查原始X事件的步骤

  • 让测试应用程序运行
  • 获取测试应用程序的窗口Id。为此,请在命令行
    xwininfo-name WINDOW\u name
    中执行,其中
    WINDOW\u name
    是测试应用程序窗口的名称。另一个选项是使用不带参数的xwininfo,然后必须用鼠标指针选择测试应用程序窗口
  • 运行X事件监视器
    xev-id 0x2a00002
    ,其中
    0x2a00002
    是在上一步中找到的窗口id。这将打印窗口从X服务器接收的X事件
    ConfigureNotify
    QMoveEvent
    的X协议对应项

  • 我和你有同样的问题。moveEvent在移动过程中的每个点都会触发,而Qt没有提供明确的方法来确定移动的结束

    但是现在,受divanov回答的启发,我发现当我们移动对话框后释放鼠标时,总是会触发键入173的事件。这就是QEvent::NonClienteamouseMove

    所以代码很简单

    首先安装事件过滤器并宣布一个成员变量:
    int nLastEvent

    bool Win::eventFilter(QObject *obj, QEvent *event)
    {
        if (nLastEvent == QEvent::Move && event->type() == 173)
        {
            // do what you wanna do here when the mouse is released,
            // like attaching the dialog to the main window
        }
        nLastEvent = event->type();
        return QWidget::eventFilter(obj, event);
    }
    
    这很简单也很有效,不是吗


    希望它对您也有用。:)

    我和你有同样的问题。moveEvent在移动过程中的每个点都会触发,而Qt没有提供明确的方法来确定移动的结束

    但是现在,受divanov回答的启发,我发现当我们移动对话框后释放鼠标时,总是会触发键入173的事件。这就是QEvent::NonClienteamouseMove

    所以代码很简单

    首先安装事件过滤器并宣布一个成员变量:
    int nLastEvent

    bool Win::eventFilter(QObject *obj, QEvent *event)
    {
        if (nLastEvent == QEvent::Move && event->type() == 173)
        {
            // do what you wanna do here when the mouse is released,
            // like attaching the dialog to the main window
        }
        nLastEvent = event->type();
        return QWidget::eventFilter(obj, event);
    }
    
    这很简单也很有效,不是吗

    希望它对您也有用。:)

    意识到这是一个非常古老的问题,这是您尝试“Qt检测窗口移动事件的结束”时遇到的第一个问题。因此,我想我应该添加一个解决方案,该解决方案与当前(撰写本文时)的Qt版本5.12.3配合得很好

    您可以设置一个小型状态机,该状态机提供边界,以便使用
    QObject::eventFilter()
    知道顶级窗口的位置何时被更改。在Qt 5.12.x中,当鼠标在窗口的非客户端区域(例如标题栏)中按下时,您将收到一个
    QEvent::nonclientreamousebutonpress
    事件,当窗口位置发生变化(如果有)时,将收到一个后续的
    QEvent::Move
    事件,然后在释放鼠标按钮时出现最后一个
    QEvent::nonclientreamousebutonrelease
    事件

    知道这个序列,并使用一个持久的布尔状态标志(
    user\u moved\u window
    )来知道实际更改的位置,将在
    QObject::eventFilter()方法中为您提供以下代码片段:

    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        QEvent::Type event_type = event->type();
        [...]
        else if(event_type == QEvent::NonClientAreaMouseButtonPress)
            user_moved_window = false;
        else if(event_type == QEvent::Move && isVisible())
            user_moved_window = true;
        else if(event_type == QEvent::NonClientAreaMouseButtonRelease)
        {
            if(user_moved_window)
            {
                // do what you need to do to here to respond to
                // the end of the reposition event...
    
                user_moved_window = false;
            }
        }
        [...]
        return MainWindow::eventFilter(obj, event);
    }
    
    根据您的情况,您可能需要添加一些额外的检查——例如,确保事件的
    obj
    实际上是主窗口——但是这个示例对于使用Qt 5.12.3的我的生产代码非常有效。

    意识到这是一个非常老的问题,这是您尝试时遇到的第一个问题“Qt检测窗口移动事件的结束”。因此,我想我应该添加一个解决方案,该解决方案与当前(截至本文撰写之时)的Qt版本5.12.3配合良好

    您可以使用
    QObject::eventFilter()
    设置一个小型状态机,该状态机提供边界,以便知道顶级窗口的位置何时被更改。在Qt 5.12.x中,当鼠标在窗口的非客户端区域按下时,您将收到一个
    QEvent::nonclientareamousebutonpress
    事件(例如标题栏),子标题
    bool Win::eventFilter(QObject *obj, QEvent *event)
    {
        if (nLastEvent == QEvent::Move && event->type() == 173)
        {
            // do what you wanna do here when the mouse is released,
            // like attaching the dialog to the main window
        }
        nLastEvent = event->type();
        return QWidget::eventFilter(obj, event);
    }
    
    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        QEvent::Type event_type = event->type();
        [...]
        else if(event_type == QEvent::NonClientAreaMouseButtonPress)
            user_moved_window = false;
        else if(event_type == QEvent::Move && isVisible())
            user_moved_window = true;
        else if(event_type == QEvent::NonClientAreaMouseButtonRelease)
        {
            if(user_moved_window)
            {
                // do what you need to do to here to respond to
                // the end of the reposition event...
    
                user_moved_window = false;
            }
        }
        [...]
        return MainWindow::eventFilter(obj, event);
    }