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



我有一个QWidget,我需要做一些动作(刷新小部件中的图片)时,调整大小事件结束。我怎样才能捕捉到这个动作?我需要抓住的时刻,当用户结束他所有的调整大小的行动,释放鼠标按钮。在我的应用程序中,每调整一个像素就刷新图像并不是一个好的做法。它应该只在鼠标释放和调整大小动作结束时调用。

我只是试图重新实现QMouseReleaseEvent来捕捉它,但是当用户按下小部件的边界来调整它的大小时,它不起作用。这意味着在我们的情况下不起作用。

然后我试图创建我自己的QSizeGrip并将其插入到我的小部件的底部,但重新实现的事件QMouseReleaseEvent再次不起作用。事件没有在用户释放鼠标时产生。我不知道为什么。

谁能帮我解决那个问题?

timeout方法是一个不错的主意,但如果用户正在调整大小,然后暂停的时间超过计时器的间隔,那么你最终不会得到真正的"用户完成了窗口大小的调整"事件。将间隔设置得更长的时间可以减少出现这种情况的可能性,但是这样做的话,用户完成调整大小的时间和函数被调用的时间之间会有很长的延迟。在我寻找解决方案的过程中,我发现有相当多的人使用计时器方法来解决这个问题,所以显然它对于某些用例来说是足够可靠的,但我认为它有点黑客。

我喜欢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. 定义私有变量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;
}

窗口装饰上的鼠标事件由底层窗口系统管理,这就是为什么您无法捕获它们的原因。我曾经遇到过同样的问题,我选择的解决方案是(重新)在每个调整大小事件上启动一个单次QTimer,并在计时器间隔过去后才处理更新。不是很性感,但我没有找到任何其他的解决方法…

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

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

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

所以我是这样解决的:

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

setMouseTracking(true);

然后,在窗口类中,我有一个布尔值,puntme;当捕捉到resize事件时设置:

bool puntme;

然后,在鼠标移动事件中:

void imgWindow::mouseMoveEvent(QMouseEvent* event){

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

基本上,它的作用是一旦用户将鼠标移动到窗口上——如果他们只是在调整它的大小,这是一件很自然的事情——那么窗口就会用新的大小重新绘制。它不会发生调整大小,因为Qt没有转发移动移动。

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

最坏的情况是,用户调整大小,将从窗口移开,并保留粗略缩放的位图,直到返回它,此时它将及时更新为实际显示的新位图== scale/size条件。

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

相关内容

  • 没有找到相关文章