Qt用户调整大小事件结束(停止)

时间:2011-10-13 12:01:11

标签: c++ qt events event-handling resize

我有一个QWidget,我需要在调整大小事件结束时执行一些操作(在小部件中刷新图片)。我怎么能抓住这个动作? 当用户通过释放鼠标按钮结束所有调整大小操作时,我需要抓住时刻。在我的应用程序中,每个调整大小的像素刷新图像都不是一个好习惯。它只应在鼠标释放和调整大小操作结束时调用。

我只是尝试重新实现QMouseReleaseEvent以捕获它,但是当用户按下窗口小部件的边框以调整它时,它不起作用。这意味着在我们的情况下不起作用。

然后我尝试创建自己的QSizeGrip并将其插入到我的小部件的底部,但重新实现的事件QMouseReleaseEvent再次无效。事件没有生成用户释放鼠标的任何时间。我不知道为什么。

任何人都可以帮我解决这个问题吗?

提前致谢。

5 个答案:

答案 0 :(得分:5)

超时方法是个不错的主意,但是如果用户正在调整大小然后暂停的时间超过了计时器的间隔,那么你最终没有得到真正的"用户已经完成了调整窗口的大小&#34 ;事件。将时间间隔设置得更长会使这种情况发生的可能性降低,但通过这样做,您最终会在用户完成调整大小和调用函数的时间之间有很长的延迟。在我寻找解决方案的过程中,我找到了不少人使用计时器方法解决它,所以显然它对某些用例来说足够可靠,但我认为它有点笨拙。

我喜欢mhstnsc的想法,所以在实现之后,我决定在这里添加一些可能对尝试做类似事情的人有用的代码。 您可以轻松地调整它以捕捉"用户完成移动窗口"通过制作m_bUserIsMoving标志并覆盖" void MainWindow :: moveEvent(QMoveEvent * pEvent)"来生成事件。我会在用户完成调整大小或移动窗口时使用它来保存配置文件,这样即使应用程序以不干净的方式被杀死,也会始终保存最后一个位置。

// constructor
MainWindow::MainWindow(QWidget* pParent, Qt::WindowFlags flags) : QMainWindow(pParent, flags)
{
    m_bUserIsResizing = false;
    qApp->installEventFilter(this);
}

// this will be called when any event in the application occurs
bool MainWindow::eventFilter(QObject* pObj, QEvent* pEvent)
{
    // We need to check for both types of mouse release, because it can vary on which type happens when resizing.
    if ((pEvent->type() == QEvent::MouseButtonRelease) || (pEvent->type() == QEvent::NonClientAreaMouseButtonRelease)) {
        QMouseEvent* pMouseEvent = dynamic_cast<QMouseEvent*>(pEvent);
        if ((pMouseEvent->button() == Qt::MouseButton::LeftButton) && m_bUserIsResizing) {
            printf("Gotcha!\n");
            m_bUserIsResizing = false; // reset user resizing flag
        }
    }
    return QObject::eventFilter(pObj, pEvent); // pass it on without eating it
}

// override from QWidget that triggers whenever the user resizes the window
void MainWindow::resizeEvent(QResizeEvent* pEvent) { m_bUserIsResizing = true; }

它比计时器稍微复杂一点,但更强大。

答案 1 :(得分:3)

我是这样做的:

  1. 从QWidget继承我的课程
  2. 定义私有变量int timerId = 0
  3. 重载QWidget :: resizeEvent和QObject :: timerEvent

  4. void MapLoader::resizeEvent(QResizeEvent *){
        if (timerId){
            killTimer(timerId);
            timerId = 0;
        }
        timerId = startTimer(5000/*delay beetween ends of resize and your action*/);
    }
    
    void MapLoader::timerEvent(QTimerEvent *te){
        /*your actions here*/
        killTimer(te->timerId());
        timerId = 0;
    }
    

答案 2 :(得分:1)

Windows装饰上的鼠标事件由底层窗口系统管理,这就是您尝试无法捕获它们的原因。 我有一次相同的问题,我选择的解决方案是(重新)在每个resize事件上启动单一QTimer,并且只在定时器间隔过去后处理更新。不是很性感,但我没有找到任何其他的解决方法..

答案 3 :(得分:1)

另一种方法是为应用程序安装事件过滤器并获取应用程序的所有事件,捕获鼠标按下和鼠标释放,并且不要在两者之间更新窗口。

“在QCoreApplication :: instance()上安装事件过滤器。这样的事件过滤器能够处理所有窗口小部件的所有事件,因此它与重新实现notify()一样强大;此外,它可以有多个应用程序全局事件过滤器。全局事件过滤器甚至可以查看禁用小部件的鼠标事件。请注意,仅为主线程中的对象调用应用程序事件过滤器。“

答案 4 :(得分:0)

我的Qt应用程序使用图像窗口并执行复杂的分层重建,即使在非常快的机器上也可能需要一些时间。因此,不对窗口框架大小的每次更改重绘窗口对我来说都很重要,因此对窗口框架调整大小的响应不会太滞后。

所以我这样解决了:

在我的图片窗口中,我启用了鼠标跟踪功能:

setMouseTracking(true);

然后,在窗口类中,我有一个布尔值puntme;这是在捕获resize事件时设置的:

bool puntme;

然后,在mousemove事件中:

void imgWindow :: mouseMoveEvent(QMouseEvent * event) {

if (puntme)
{
    puntme = false;
    needRebuild = true;
    update();
}

...

基本上,当用户将鼠标移到窗口上时,它的作用就是 - 如果他们只是调整大小,这对他们来说是很自然的事情 - 那么窗口会重新绘制新的大小。在调整大小期间不会发生,因为Qt不会转发移动然后移动。

相反,在调整大小期间,我只是缩放已经存在的位图,这给出了比例变化的粗略近似值,必须处理实际新近或多或少的可用分辨率。

最糟糕的情况是,用户调整大小,从窗口移开远离,并将原始缩放的位图保留到位,直到返回到它,此时它将适时更新为实际新显示的位图==规模/大小条件。

没有完美的方法 - 这里真正需要的是Qt提供(用户已经停止调整窗口大小“的消息,但代替这一点,这对我来说效果很好。