如何使用 QGraphicsScene 中的 QToolBar 修复 Qt QMainWindow 的可拖动区域问题
How to fix Qt QMainWindow's Draggable Area Issue with QToolBar in QGraphicsScene
我在尝试将 QMainWindow
添加到 QGraphicsScene
时遇到了一个奇怪的问题。出于所有意图和目的,请不要推荐我使用 QMdiArea
作为替代方案,因为这会分散我对实际问题的注意力,而且它不符合我的需要。
这是说明 2 个关键问题的最小示例,我认为这两个问题都可能是 Qt 错误。
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QToolBar>
#include <QVBoxLayout>
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
resize(1000, 750);
QGraphicsView* view = new QGraphicsView;
QGraphicsScene* scene = new QGraphicsScene;
view->setFixedSize(1000, 750);
view->setScene(scene);
view->scene()->setSceneRect(-150, -150, view->size().width(), view->size().height());
setCentralWidget(view);
QWidget* widget = new QWidget;
widget->resize(300, 300);
QVBoxLayout* vLay = new QVBoxLayout;
widget->setLayout(vLay);
QMainWindow* testWindow = new QMainWindow;
testWindow->resize(300, 300);
QToolBar* toolbar = new QToolBar;
toolbar->setFloatable(false);
toolbar->setStyleSheet("border: 1px solid red"); //For better seeing the issue
toolbar->addAction("Test");
testWindow->addToolBar(toolbar);
vLay->addWidget(testWindow);
scene->addWidget(widget);
}
现在,您可能会挠头,想知道我到底为什么要这样做...
tl;dr:我正在使用自定义 Dock 和分层管理器在 QGraphicsView
中创建一个自定义 MDI 区域。我需要每个子窗口都有一个可停靠的 QToolBar
,很像 QMainWindow
,但只有 QMainWindow
开箱即用地支持此功能。在我上面的示例中,每个子窗口都是包罗万象的 QWidget
。
在将我的子窗口的 "inside" 内容转换为 QMainWindow
之前,一切正常,即使是 QMainWindow
,一切仍然很好。但是,一旦我将 QToolBar
添加到 QMainWindow
中,一切就开始出错了。
启动后您会注意到程序看起来是正确的,QToolBar
的位置和偏移也正确。现在,如果您尝试将 QToolBar
拖到任何地方,甚至在 QMainWindow
之外并执行鼠标键释放,将会发生以下两种情况之一:
当 运行 在我当前的系统上时程序会崩溃并且有一个非常奇怪的堆栈跟踪:REHL 上的 Qt 5.10.1 和 gcc 5.2.0
QToolBar
会错误地捕捉到 QMainWindow
中的错误位置。将鼠标悬停在有效的可停靠位置上时,请仔细查看预定义的矩形区域,并使用红色边框作为指导。
崩溃是不一致的,有时在第一次拖动事件之后每隔第二次发生一次。有时它发生在你抓住 QToolBar
的那一刻,而其他时候它发生在 drop 事件之后。我会添加堆栈跟踪,但每次调试器都有不同的输出。我看到了一些关于 nVidia.so 库的消息,例如:
7fd6d96c1000-7fd6daf36000 r-xp 00000000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6daf36000-7fd6db135000 ---p 01875000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6db135000-7fd6db4a9000 rw-p 01874000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6db4a9000-7fd6db4c2000 rw-p 00000000 00:00 0
7fd6db4c2000-7fd6db5d3000 r-xp 00000000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db5d3000-7fd6db7d3000 ---p 00111000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db7d3000-7fd6db7f8000 rw-p 00111000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db7f8000-7fd6db7ff000 rw-p 00000000 00:00 0
7fd6db7ff000-7fd6db800000 ---p 00000000 00:00 0
7fd6db800000-7fd6dc000000 rw-p 00000000 00:00 0 [stack:30187]
7fd6dc000000-7fd6dc021000 rw-p 00000000 00:00 0
7fd6dc021000-7fd6e0000000 ---p 00000000 00:00 0
7fd6e00aa000-7fd6e00ad000 r-xp 00000000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
7fd6e00ad000-7fd6e02ad000 ---p 00003000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
7fd6e02ad000-7fd6e02ae000 rw-p 00003000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
调试器可能有超过 50 个灰显的函数回调,有时相同,有时不同。值得注意的是,我已经看到 QPropertyAnimation
混合在这些回调中,但不是每次都这样,所以我无法确定它,我觉得我快要疯了。
现在,您可能认为这与 QMainWindow
作为 QGraphicsProxyWidget
嵌入到 QGraphicsScene
中有关,并且只是产生了副作用...但是不。如果您直接将 QMainWindow
添加到场景并使用包含它的 QWidget
绕过,那么一切正常。捕捉工作没有偏移问题,也没有更多的崩溃。由于这种交互,我几乎确信这是一个 Qt 错误,并想使用此 post 作为基础提交错误报告。如果我遗漏了什么或需要更新我的图形驱动程序,我会的。但是,它没有解释为什么在拖动时捕捉与 QMainWindow's
橡皮筋矩形位置不匹配。
这个奇怪问题的解决方案类似于我的另一个 post 关于 QGraphicsScene
内的上下文菜单。要修复此行为,只需在父 window 小部件或子主 window 本身上设置 setWindowFlags(Qt::BypassGraphicsProxyWidget)
。如果您在父小部件上执行此操作,它将隐式地将其应用于 QMainWindow
。任何时候 QGraphicsScene
似乎有问题,设置上面的标志似乎可以解决大多数问题 bugs/issues.
我在尝试将 QMainWindow
添加到 QGraphicsScene
时遇到了一个奇怪的问题。出于所有意图和目的,请不要推荐我使用 QMdiArea
作为替代方案,因为这会分散我对实际问题的注意力,而且它不符合我的需要。
这是说明 2 个关键问题的最小示例,我认为这两个问题都可能是 Qt 错误。
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QToolBar>
#include <QVBoxLayout>
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
resize(1000, 750);
QGraphicsView* view = new QGraphicsView;
QGraphicsScene* scene = new QGraphicsScene;
view->setFixedSize(1000, 750);
view->setScene(scene);
view->scene()->setSceneRect(-150, -150, view->size().width(), view->size().height());
setCentralWidget(view);
QWidget* widget = new QWidget;
widget->resize(300, 300);
QVBoxLayout* vLay = new QVBoxLayout;
widget->setLayout(vLay);
QMainWindow* testWindow = new QMainWindow;
testWindow->resize(300, 300);
QToolBar* toolbar = new QToolBar;
toolbar->setFloatable(false);
toolbar->setStyleSheet("border: 1px solid red"); //For better seeing the issue
toolbar->addAction("Test");
testWindow->addToolBar(toolbar);
vLay->addWidget(testWindow);
scene->addWidget(widget);
}
现在,您可能会挠头,想知道我到底为什么要这样做...
tl;dr:我正在使用自定义 Dock 和分层管理器在 QGraphicsView
中创建一个自定义 MDI 区域。我需要每个子窗口都有一个可停靠的 QToolBar
,很像 QMainWindow
,但只有 QMainWindow
开箱即用地支持此功能。在我上面的示例中,每个子窗口都是包罗万象的 QWidget
。
在将我的子窗口的 "inside" 内容转换为 QMainWindow
之前,一切正常,即使是 QMainWindow
,一切仍然很好。但是,一旦我将 QToolBar
添加到 QMainWindow
中,一切就开始出错了。
启动后您会注意到程序看起来是正确的,QToolBar
的位置和偏移也正确。现在,如果您尝试将 QToolBar
拖到任何地方,甚至在 QMainWindow
之外并执行鼠标键释放,将会发生以下两种情况之一:
当 运行 在我当前的系统上时程序会崩溃并且有一个非常奇怪的堆栈跟踪:REHL 上的 Qt 5.10.1 和 gcc 5.2.0
QToolBar
会错误地捕捉到QMainWindow
中的错误位置。将鼠标悬停在有效的可停靠位置上时,请仔细查看预定义的矩形区域,并使用红色边框作为指导。
崩溃是不一致的,有时在第一次拖动事件之后每隔第二次发生一次。有时它发生在你抓住 QToolBar
的那一刻,而其他时候它发生在 drop 事件之后。我会添加堆栈跟踪,但每次调试器都有不同的输出。我看到了一些关于 nVidia.so 库的消息,例如:
7fd6d96c1000-7fd6daf36000 r-xp 00000000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6daf36000-7fd6db135000 ---p 01875000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6db135000-7fd6db4a9000 rw-p 01874000 fd:00 34442271 /usr/lib64/libnvidia-glcore.so.390.67
7fd6db4a9000-7fd6db4c2000 rw-p 00000000 00:00 0
7fd6db4c2000-7fd6db5d3000 r-xp 00000000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db5d3000-7fd6db7d3000 ---p 00111000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db7d3000-7fd6db7f8000 rw-p 00111000 fd:00 35871194 /usr/lib64/libGLX_nvidia.so.390.67
7fd6db7f8000-7fd6db7ff000 rw-p 00000000 00:00 0
7fd6db7ff000-7fd6db800000 ---p 00000000 00:00 0
7fd6db800000-7fd6dc000000 rw-p 00000000 00:00 0 [stack:30187]
7fd6dc000000-7fd6dc021000 rw-p 00000000 00:00 0
7fd6dc021000-7fd6e0000000 ---p 00000000 00:00 0
7fd6e00aa000-7fd6e00ad000 r-xp 00000000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
7fd6e00ad000-7fd6e02ad000 ---p 00003000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
7fd6e02ad000-7fd6e02ae000 rw-p 00003000 fd:00 3060689 /usr/lib64/tls/libnvidia-tls.so.390.67
调试器可能有超过 50 个灰显的函数回调,有时相同,有时不同。值得注意的是,我已经看到 QPropertyAnimation
混合在这些回调中,但不是每次都这样,所以我无法确定它,我觉得我快要疯了。
现在,您可能认为这与 QMainWindow
作为 QGraphicsProxyWidget
嵌入到 QGraphicsScene
中有关,并且只是产生了副作用...但是不。如果您直接将 QMainWindow
添加到场景并使用包含它的 QWidget
绕过,那么一切正常。捕捉工作没有偏移问题,也没有更多的崩溃。由于这种交互,我几乎确信这是一个 Qt 错误,并想使用此 post 作为基础提交错误报告。如果我遗漏了什么或需要更新我的图形驱动程序,我会的。但是,它没有解释为什么在拖动时捕捉与 QMainWindow's
橡皮筋矩形位置不匹配。
这个奇怪问题的解决方案类似于我的另一个 post 关于 QGraphicsScene
内的上下文菜单。要修复此行为,只需在父 window 小部件或子主 window 本身上设置 setWindowFlags(Qt::BypassGraphicsProxyWidget)
。如果您在父小部件上执行此操作,它将隐式地将其应用于 QMainWindow
。任何时候 QGraphicsScene
似乎有问题,设置上面的标志似乎可以解决大多数问题 bugs/issues.