繁体   English   中英

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

[英]Qt user resize event ends (stops)

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

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

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

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

提前致谢。

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

我喜欢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. 从QWidget继承我的类
  2. define private variable int timerId = 0
  3. 重载QWidget :: resizeEvent和QObject :: timerEvent

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;
}

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

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

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

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

所以我这样解决了:

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

setMouseTracking(true);

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

bool puntme;

然后,在mousemove事件中:

void imgWindow :: mouseMoveEvent(QMouseEvent * event){

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

...

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

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

最坏的情况是,用户调整大小, 远离窗口移动,并将粗略缩放的位图留在原位,直到返回到它,此时它将适时更新到实际新显示的位图==缩放/大小条件。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM