Reputation: 932
I'm writing a card game with Qt. Initially, the UI was written in C++ with Qt Widgets, but after porting to Android (Qt Widgets app looks awkwardly there, because of the settings and color choose dialogues being almost unusable) I've decided to switch into QML, keeping game logic in C++.
However, the part of game logic which cannot be separated from visual rendering (e.g. players place cards on the table) is written in QGraphicsScene
-derived class:
class Table : public QGraphicsScene
{
// some code omitted
}
Table::Table(QObject* parent) : QGraphicsScene(parent) { /* ... */ }
I've tried to register Table
as QML type via qmlRegisterType()
, but it doesn't work for me - placing Table
object into QML results in the segfault in QGraphicsScene
constructor. Here's the part of the backtrace:
#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 graphicsview\qgraphicsscene.cpp:334
q = 0x362be1a8
#6 0x192a61e9 in QGraphicsScene::QGraphicsScene (this=0x362be1a8, parent=0x0) at graphicsview\qgraphicsscene.cpp:1636
No locals.
#7 0x00402f53 in Table::Table (this=0x362be1a8, parent=0x0) at ..\OpenFool\src\table.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 qml\qqmlmetatype.cpp:761
rv = 0x362be1a8
So, is there a way to re-use the code of Table
without re-writing it into QML?
Upvotes: 0
Views: 4771
Reputation: 13691
As far as I know, the render engine of QtWidget and QML is fundamentally different, so it would be hard to register a Widget
as a QML Type
.
So I think the two best options for you are:
QQuickPaintedItem
to have a most similar API to your QGraphicsScene
so the changes you need on your code are only minimal. (*Thank you, @BenjaminT for pointing me to QQuickPaintedItem
rather than Context2D
)Upvotes: 3
Reputation: 8311
You need a QGraphicsView
widget to display a QGraphicsScene
.
However you cannot embed a widget in a Qt Quick 2 interface. (If you use Qt Quick 1 see @xander answer).
But there is a solution if you take the problem the other way around. You could make a Qt Widget HMI, display your scene in a QGraphicsView widget and display the Qt Quick parts of your using one or more QQuickWidget. This has some limitations, but if you do not overlap the QtQuick and QtWidget parts this works well and can be quite efficient
Upvotes: 1
Reputation: 1765
As far as I know you can't embed a QWidget
into Qt Quick 2 elements, however if you can use Qt Quick 1 it's still possible with a custom QDeclarativeItem
and a QGraphicsProxyWidget
.
Example with a custom 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();
};
In your case you might even replace the QGraphicsProxyWidget
with your QGraphicsScene
directly because QGraphicsScene
is a base class in Qt Quick 1 (was replaced in Qt Quick 2).
Upvotes: 1