【问题标题】:Embedding QGraphicsScene into QML将 QGraphicsScene 嵌入 QML
【发布时间】:2017-07-31 13:37:46
【问题描述】:

我正在用 Qt 编写一个纸牌游戏。最初,UI 是用 Qt Widgets 用 C++ 编写的,但在移植到 Android 之后(Qt Widgets 应用程序看起来很尴尬,因为设置和颜色选择对话框几乎无法使用)我决定切换到 QML,保持游戏逻辑C++。

但是,与视觉渲染不能分离的部分游戏逻辑(例如玩家将牌放在桌子上)写在QGraphicsScene-派生类中:

class Table : public QGraphicsScene
{
    // some code omitted
}

Table::Table(QObject* parent) : QGraphicsScene(parent) { /* ... */ }

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

#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 

那么,有没有一种方法可以重用Table 的代码,而无需将其重新写入QML?

【问题讨论】:

    标签: c++ qt qml


    【解决方案1】:

    据我所知,QtWidget 和 QML 的渲染引擎根本不同,所以很难将Widget 注册为QML Type

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

    1. 使其适应 QML
    2. QQuickPaintedItem 扩展为与QGraphicsScene 最相似的API,这样您对代码所需的更改就很少了。 (*感谢您,@BenjaminT 将我指向 QQuickPaintedItem 而不是 Context2D

    【讨论】:

    • Context2D 性能较差,QQuickPaintedItem 更快,应该是首选(在这种情况下更是如此,因为代码已经是 C++)
    • 我什至建议使用QQuickItem 而不是QQuickPaintedItem,因为最后一个使用OpenGL,它应该工作得更快。
    • AFAIK QQuickPaintedItem 也可以做到这一点,如果你将 QQuickPaintedItem::RenderTarget 设置为 QQuickPaintedItem::FramebufferObject,还是我错了?
    • 谢谢!在我看来,这是最合理的解决方案。
    【解决方案2】:

    据我所知,您无法将 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();
    };
    

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

    【讨论】:

      【解决方案3】:

      您需要一个QGraphicsView 小部件来显示QGraphicsScene。 但是,您不能在 Qt Quick 2 界面中嵌入小部件。 (如果您使用 Qt Quick 1,请参阅 @xander 答案)。

      但是,如果您反过来解决问题,则有解决方案。您可以制作一个 Qt Widget HMI,在 QGraphicsView 小部件中显示您的场景,并使用一个或多个 QQuickWidget 显示您的 Qt Quick 部分。这有一些限制,但如果你不重叠 QtQuick 和 QtWidget 部分,这会很好并且非常有效

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-09
        • 1970-01-01
        • 1970-01-01
        • 2015-10-23
        相关资源
        最近更新 更多