1

我在 X11 上使用 Qt 4.8.3。

我需要知道用户何时结束在屏幕上拖动窗口,以便读取最终位置并最终启动动画以将窗口位置调整为“允许”位置。

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

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

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

我怀疑我将不得不自己重新实现标题栏……太糟糕了……</p>

4

3 回答 3

4

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

但是现在,受到divanov回答的启发,我发现当我们在移动对话框后松开鼠标时,总是会触发一个类型为173的事件。那是 QEvent::NonClientAreaMouseMove。

所以代码很简单。

首先安装事件过滤器并宣布一个成员变量: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);
}

它足够简单和高效,不是吗!

希望它对你也有用。:)

于 2012-10-31T03:26:52.747 回答
4

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

您可以设置一个小型状态机,为了解何时使用QObject::eventFilter(). 在 Qt 5.12.x 中,QEvent::NonClientAreaMouseButtonPress当鼠标在窗口的非客户区域(例如,标题栏)向下移动时,您将收到一个事件,QEvent::Move当窗口位置发生变化时(如果有的话),您将收到一个后续事件,然后是QEvent::NonClientAreaMouseButtonRelease释放鼠标按钮时的最终事件。

知道这个序列,并使用一个持久的布尔状态标志 ( user_moved_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 的生产代码。

于 2019-04-30T21:37:21.583 回答
1

让我们考虑以下测试应用程序:main.cpp

#include <QApplication>

#include "win.h"

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    Win w;
    w.show();

    return app.exec();
}

赢.h:

#include <QWidget>
#include <QEvent>
#include <QMoveEvent>
#include <QDebug>

class Win : public QWidget
{
public:
    Win(QWidget *parent = 0) : QWidget(parent) {
        this->installEventFilter(this);
    }

protected:
    bool eventFilter(QObject *obj, QEvent *event) {
        if (event->type() == QEvent::Move) {
            QMoveEvent *moveEvent = static_cast<QMoveEvent*>(event);
            qDebug() << "Move event:" << moveEvent->pos();
        } else {
            qDebug() << "Event type:" << event->type();
        }
        return QWidget::eventFilter(obj, event);
    }
};

此应用程序仅在其自身上安装事件过滤器,并打印到控制台所有接收到的事件,并使用 QMoveEvent 的特殊格式来区分它在日志中。

典型日志:

Event type: 203 
Event type: 75 
Move event: QPoint(0,0) 
Event type: 14 
Event type: 17 
Event type: 26 
Event type: 74 
Event type: 77 
Move event: QPoint(66,52) 
Event type: 12 
Event type: 24 
Event type: 99 
Event type: 77 
Event type: 12 
Event type: 10 
Event type: 11 
Move event: QPoint(308,356) 
Event type: 19 
Event type: 25 
Event type: 99 
Event type: 18 
Event type: 27 
Event type: 77 

如您所见,有 2 个移动事件,一个是在最初创建应用程序时,另一个是在我完成窗口移动之后。我正在使用 Qt 4.8.1 和 XOrg 7.6 进行测试。

检查原始 X 事件

  1. 让测试应用程序运行。
  2. 获取测试应用程序的窗口 ID。为此,请在命令行中执行xwininfo -name WINDOW_NAME,其中WINDOW_NAME是测试应用程序窗口的名称。另一种选择是使用不带参数的 xwininfo,然后您必须用鼠标指针选择测试应用程序窗口。
  3. 运行 X 事件监视器xev -id 0x2a00002,其中0x2a00002是在上一步中找到的窗口 ID。这将打印您的窗口从 X 服务器接收到的 X 事件。ConfigureNotify是 X 协议的对应物QMoveEvent
于 2012-10-18T15:56:13.057 回答