将QGraphicsScene嵌入QML中

Embedding QGraphicsScene into QML

本文关键字:QML 嵌入 QGraphicsScene      更新时间:2023-10-16

我正在用qt编写一张纸牌游戏。最初,UI是用QT小部件编写的,但是在移植到Android之后(Qt Widgets App看起来很尴尬,因为设置和颜色选择对话几乎是不可用的)C 。

但是,游戏逻辑的一部分不能与视觉渲染分开(例如,玩家将卡片放在桌子上)是在QGraphicsScene衍生的类中写的:

class Table : public QGraphicsScene
{
    // some code omitted
}
Table::Table(QObject* parent) : QGraphicsScene(parent) { /* ... */ }

我尝试通过qmlRegisterType()Table注册为QML类型,但是对我不起作用 - 将Table对象放入QML中会导致QGraphicsScene构造函数中的segfault。这是回溯的一部分:

#0  0x19312fa4 in std::__atomic_base<int>::load (__m=std::memory_order_relaxed, this=0xabababab) at C:/MINGW530/i686-w64-mingw32/include/c++/bits/atomic_base.h:396
        __b = std::memory_order_relaxed
#1  QAtomicOps<int>::load<int> (_q_value=...) at ../../include/QtCore/../../src/corelib/arch/qatomic_cxx11.h:227
No locals.
#2  0x193e1780 in QBasicAtomicInteger<int>::load (this=0xabababab) at ../../include/QtCore/../../src/corelib/thread/qbasicatomic.h:102
No locals.
#3  0x1940f7a7 in QtPrivate::RefCount::isShared (this=0xabababab) at ../../include/QtCore/../../src/corelib/tools/qrefcount.h:101
        count = 571316634
#4  0x1937f29d in QList<QGraphicsScene*>::append (this=0x139914c, t=@0x112e8cc: 0x362be1a8) at ../../include/QtCore/../../src/corelib/tools/qlist.h:580
No locals.
#5  0x192a1188 in QGraphicsScenePrivate::init (this=0x362be258) at graphicsviewqgraphicsscene.cpp:334
        q = 0x362be1a8
#6  0x192a61e9 in QGraphicsScene::QGraphicsScene (this=0x362be1a8, parent=0x0) at graphicsviewqgraphicsscene.cpp:1636
No locals.
#7  0x00402f53 in Table::Table (this=0x362be1a8, parent=0x0) at ..OpenFoolsrctable.cpp:41
No locals.
#8  0x0041239a in QQmlPrivate::QQmlElement<Table>::QQmlElement (this=0x362be1a8) at J:/Qt/Qt5.8.0/5.8/mingw53_32/include/QtQml/qqmlprivate.h:99
No locals.
#9  0x0041235d in QQmlPrivate::createInto<Table> (memory=0x362be1a8) at J:/Qt/Qt5.8.0/5.8/mingw53_32/include/QtQml/qqmlprivate.h:108
No locals.
#10 0x01c7a5d5 in QQmlType::create (this=0x1398550, out=0x112ed70, memory=0x112ed4c, additionalMemory=72) at qmlqqmlmetatype.cpp:761
        rv = 0x362be1a8 

那么,有没有办法重复使用Table的代码,而无需重新编写QML?

据我所知,QTwidget和QML的渲染引擎从根本上有所不同,因此很难将Widget注册为QML Type

所以我认为您的两个最佳选择是:

  1. 将其改编为QML
  2. QQuickPaintedItem扩展到与QGraphicsScene最相似的API,因此您在代码上需要的更改仅是最小的。(*谢谢, @benjamint 将我指向QQuickPaintedItem而不是Context2D

据我所知,您不能将 QWidget嵌入qt quick 2元素中,但是,如果您可以使用QT Quick 1,则可以使用自定义QDeclarativeItemQGraphicsProxyWidget

用自定义QPushButton的示例:

#include <QtDeclarative>
#include <QtGui>
class PushButtonItem : public QDeclarativeItem {
  Q_OBJECT
public:
  PushButtonItem(QDeclarativeItem *parent =0) : QDeclarativeItem(parent) {
    pb = new QPushButton("text");
    proxy = new QGraphicsProxyWidget(this);
    proxy->setWidget(pb);
    proxy->setPos(-pb->sizeHint().width()/2, -pb->sizeHint().height()/2);
  }
private:
  QPushButton *pb;
  QGraphicsProxyWidget *proxy;
};
#include "main.moc"
int main(int argc, char **argv) {
  QApplication app(argc, argv);
  QDeclarativeView view;
  qmlRegisterType<PushButtonItem>("PushButton", 1, 0, "PushButtonItem");
  view.setSource(QUrl::fromLocalFile("file.qml"));
  view.show();
  return app.exec();
};

在您的情况下,您甚至可以直接用QGraphicsScene替换QGraphicsProxyWidget,因为QGraphicsScene是QT Quick 1中的基类(在QT Quick 2中替换为2)。

您需要一个QGraphicsView窗口小部件才能显示QGraphicsScene。但是,您不能将小部件嵌入QT Quick 2接口中。(如果您使用QT Quick 1请参阅@xander答案)。

但是,如果您以相反的方式处理问题,请有一个解决方案。您可以制作QT小部件HMI,在Qgraphicsview小部件中显示您的场景,并使用一个或多个Qquickwidget显示QT快速部分。这有一些局限性,但是如果您不重叠QTquick和Qtwidget零件,则可以很好地工作,并且可以非常有效