我有一个场景,我想制作它的缩影,所以我想调整它的大小,使其适合特定的比例。我有这样的东西:
void makeMiniature(QGraphicsScene * scene)
{
QGraphicsView * gv = new GraphicsView(scene, this);
gv->setMaximumHeight(150);
gv->setMaximumWidth(150);
gv->setSceneRect(0, 0, gv->frameSize().width(), gv->frameSize().height());
layout->addWidget(gv);
}
其中layout是QVBoxLayout类型。目前我只是在 150x150 窗口中获取我的场景的一部分,但我想调整所有场景的大小以使其适合那里。有什么办法吗?或者我能以某种方式将 QGraphicsScene 转换为 QGraphicsView 元素吗?
最佳答案
问题的要求是一个QGraphicsView
,它会自动缩放 View 以适应整个场景。
我已经扫描了文档。 QGraphicsView
如果没有这样的功能可用。要么我没有找到,要么没有。
但是,有一些方法可以用很少的代码来“DIY”这个特性:
-
QGraphicsScene::sceneRect()
...返回图形场景的边界矩形 -
QGraphicsView::fitInView()
...调整图形 View 中的 View 转换,使某个矩形的区域可见。
我做了一个 MCVE演示这一点:testQGraphicsViewDual.cc
#include <QtWidgets>
enum { Width = 256, Height = 256 };
enum { MinWidth = 8, MinHeight = 8 };
enum { MaxRects = 8 };
// returns a random floating point number in [min, max).
qreal randF(qreal min, qreal max)
{
return (qreal)qrand() / RAND_MAX * (max - min) + min;
}
// returns a random integer number in [min, max).
int rand(int min, int max)
{
return qrand() % (max - min) + min;
}
/* adds a random rectangle to a Qt graphics scene.
* The scene is cleared if the decremented clear counter reaches 0.
*/
void populate(QGraphicsScene &qGScene, unsigned &clear)
{
if (!clear--) { qGScene.clear(); clear = MaxRects; }
const QPointF pt(randF(-Width, Width - MinWidth), randF(-Height, Height - MinHeight));
const QSizeF size(
randF(MinWidth, 2 * Width - pt.x()), randF(MinHeight, 2 * Height - pt.y()));
qGScene.addRect(
QRectF(pt, size),
QPen(QColor(rand(0, 256), rand(0, 256), rand(0, 256)), 2),
QColor(rand(0, 256), rand(0, 256), rand(0, 256)));
qGScene.setSceneRect(qGScene.itemsBoundingRect()); // update scene rect.
}
// class for widget to demostrate auto-fit-in-view
class Canvas: public QGraphicsView {
// variables:
private:
// flag: true ... auto-scaling enabled to fit whole scene in view
bool _autoScale;
// methods:
public:
// constructor.
Canvas(bool autoScale = false);
// destructor.
virtual ~Canvas() = default;
// disabled:
Canvas(const Canvas&) = delete;
Canvas& operator=(const Canvas&) = delete;
// returns current state of autoScale.
bool autoScale() const { return _autoScale; }
// sets autoScale.
void setAutoScale(bool autoScale);
protected:
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
Canvas::Canvas(bool autoScale):
QGraphicsView()
{
setAutoScale(autoScale);
}
void Canvas::setAutoScale(bool autoScale)
{
_autoScale = autoScale;
setHorizontalScrollBarPolicy(_autoScale ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
setVerticalScrollBarPolicy(_autoScale ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
}
void Canvas::paintEvent(QPaintEvent *pQEvent)
{
const QGraphicsScene *pQGScene = scene();
if (pQGScene && _autoScale) {
fitInView(pQGScene->sceneRect(), Qt::KeepAspectRatio);
}
QGraphicsView::paintEvent(pQEvent);
}
// main function
int main(int argc, char **argv)
{
qDebug() << "Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup graphics scene
QGraphicsScene qGScene;
// setup GUI
QWidget qWin;
qWin.resize(2 * Width, Height);
QHBoxLayout qHBox;
Canvas qView1(false);
qView1.setScene(&qGScene);
Canvas qView2(true);
qView2.setScene(&qGScene);
qHBox.addWidget(&qView1, 1);
qHBox.addWidget(&qView2, 1);
qWin.setLayout(&qHBox);
qWin.show();
// install timer for continuous population of qGScene
QTimer qTimer; unsigned clear = 0;
qTimer.setInterval(1000 /* ms */);
QObject::connect(&qTimer, &QTimer::timeout,
[&qGScene, &clear]() { populate(qGScene, clear); });
qTimer.start();
// do runtime loop
return app.exec();
}
QMake 脚本testQGraphicsViewDual.pro
SOURCES = testQGraphicsViewDual.cc
QT += widgets
在 bash
中编译和测试(在 cygwin/Windows 10 上):
$ qmake-qt5
$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQGraphicsViewDual.o testQGraphicsViewDual.cc
g++ -o testQGraphicsViewDual.exe testQGraphicsViewDual.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
$ ./testQGraphicsViewDual
Version: 5.9.2
注意事项:
class Canvas
派生自 Qtclass QGraphicsView
以添加自动适应功能。为此,重载了paintEvent()
。它只是在“返回”到QGraphicsView::paintEvent()
之前调用QGraphicsView::fitInView()
。左 View 和右 View 是
Canvas
的实例 – 左侧禁用了autoScale
,右侧启用了autoScale
。两个 View 共享相同的
QGraphicsScene
实例qGScene
。populate()
函数用于填充图形场景。因此,内容的坐标/大小被选择,结果几何体很可能不适合 View 。快照显示左侧(未缩放) View 仅显示部分场景(通过滚动条可视化)。右 View 显示了整个场景(缩小以适合 View ),即没有滚动条。
为防止滚动条意外闪烁(由于舍入问题),激活
autoScroll
会显式停用滚动条。看了一会儿示例代码后,我意识到场景矩形从未缩小(即使场景会定期清除)。这让我有些头疼。我试过
QGraphicsScene::itemsBoundingRect
但将其视为文档的次优解决方案。明确说明:This function works by iterating over all items, and because of this, it can be slow for large scenes.
最后,我更改了
<populate()
以便显式设置QGraphicsScene::sceneRect
((仅)当其内容被修改时)。
关于上一期,我发现了一个类似的Q/A,我觉得值得一提:
SO: QGraphicsScene::clear doesn't change sceneRect .
关于Qt - 如何将 QGraphicsScene 缩放到 QGraphicsView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48604392/