跳至主要內容

QT

LincZero大约 4 分钟

QT

目录

混合 - 数种UI流

QWidgets 协同 QGraphics

关系树详见 QWidget与继承树

QWidget 与 QGraphics 都继承于 QObject、模块均为 widgets,邻近度很高

常用控件

  • QWidget系列,常用控件如 QWidget、QPushButton、QFlame 等
  • QGraphics系列,常用控件如 QGraphicsScene、QGraphicsItem 、QGraphicsView (这个是QWidget)

QWidget 嵌套 QGraphics

非常简单

核心在于:QObject > QWidget > QFrame > QAbstractScrollArea > QGraphicsView,是一个构造函数接受QGraphicsScene参数的QWidget对象

QGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr)
QGraphicsView(QWidget *parent = nullptr)

使用示例

from .node_graphics_view import QDMGraphicsView
from .node_scene import Scene

class NodeEditWidget(QWidget):
    def __init__(self, parent=None):
        # create graphics sence
        self.scene = Scene()
        self.grScene = self.scene.grScene
        
        # create graphics view
        self.view = QDMGraphicsView(self.scene.grScene, self)
        self.layout.addWidget(self.view)

QGraphics 嵌套 QWidget

也非常简单(之前开发NodeEditor时用过这个操作)

核心在于:QObject > QGraphicsItem > QGraphicsObject > QGraphicsWidget > QGraphicsProxyWidget,有一个接受QWidget对象的方法

QGraphicsProxyWidget(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = Qt::WindowFlags())
void setWidget(QWidget *widget)

使用示例

class QDMGraphicsNode(QGraphicsItem):
	def __init__(self, node, parent=None):
        # ……
        self.wdContent = self.node.wdContent
        self.wdContent.setGeometry(self.node_padding, self.title_height + self.node_padding
        	, self.width - 2 * self.node_padding, self.height - 2 * self.node_padding - self.title_height)
        
        self.grContent = QGraphicsProxyWidget(self)
        self.grContent.setWidget(self.wdContent)
        

Qt Widget 协同 Qt Quick

main.cpp 直接 使用QML

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;                                       // QML引擎
    const QUrl url(QStringLiteral("qrc:/main.qml"));                    // 需要加载的qml
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,	// 将引擎结果关联到lambda上
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)										// 无法加载则退出程序
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);                                                   // 用QML引擎加载qml文档

    return app.exec();                                                  // 消息循环
}

这种情况下,QML文件需要以Window之类的作为根节点

import QtQuick 2.6
import QtQuick.Window 2.2

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
}

简单嵌套( QQuickWidget)

参考:【简书】QWidget 和 QML窗口 相互嵌套open in new window

QWidget界面和QML窗口相互嵌套都是需要借助 quickwidgets 这个模块中的类 这里使用的是QQuickWidget,这个类是继承QWidget的,就和 QWidget 一样使用就行

.cpp

#include <QApplication>
#include <QtQuickWidgets/QQuickWidget>
#include <QQuickView>
#include <QHBoxLayout>
#include <QLabel>

int main(int argc, char *argv[])
{
    // QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
    QApplication app(argc, argv);
    
    QWidget * widget = new QWidget;
    widget->setWindowTitle("widget 主窗口");
    widget->resize(800, 400);
    
    // 设置布局
    QHBoxLayout * layout = new QHBoxLayout;
    layout->setContentsMargins(0, 0, 0 ,0);
    widget->setLayout(layout);
    
    // qml 界面 嵌入到 widget
    QQuickWidget qmlWidget(QUrl("qrc:/main.qml"));
    qmlWidget.setResizeMode(QQuickWidget::SizeRootObjectToView );
    // 设置这个之后 anchor不用设置,root节点大小会根据 QQuickWidget大小改变
    // 在qml里 通过 parent 获取不到 widget 窗口 !!!   
    layout->addWidget(&qmlWidget);
    
    // widget 界面 嵌入到 qmlWidget里
    QLabel label("QLabel", &qmlWidget);
    label.move(100, 100);
    
    // widget 界面 嵌入到 widget
    QLabel nativeWidget;
    nativeWidget.setText("Widget");
    nativeWidget.setAlignment(Qt::AlignCenter);
    layout->addWidget(&nativeWidget);
    
    widget->show();
    
    return app.exec();
}

.qml

  • 注意:如果是用 QQuickView或者QQuickWidget 加载的qml,root节点不能是 Window 这一类类型,最好是Rectangle
  • 注意:Rectangle里不能放QWidget界面,否则直接断言退出程序 ASSERT: "!d->isWidget" in file [kernel\qobject.cpp, line 1979](kernel\qobject.cpp, line 1979)
import QtQuick 2.9

Rectangle {
    //visible: true
    //width: 150
    //height: 150
    //anchors.fill: parent
    //anchors.centerIn: parent
    
    border.color: "#00ffd5"
    border.width: 10
    radius : 10
    
    Text {
        id : text
        anchors.centerIn: parent
        text: qsTr("QML Text")
        antialiasing: true  //抗锯齿
    }

    // 旋转动画
    NumberAnimation {
        id : numberAnimation
        target: text
        property: "rotation"
        from: 0
        to: 360
        duration: 3000
        
        running: true
        loops: Animation.Infinite
        
    }
}

QWidget 嵌套 QML 并交互

参考:

原理

  1. 使用QQuickView 类提供一个用于显示 Qt Quick 用户界面的窗口。

  2. 使用QWidget::createWindowContainer()函数,将QtQuick组件嵌入到QWidget中,该函数直接返回qwidget指针。

  3. 如果不需要交互就到此为止了。步骤 3 进行交互

    使用QQmlContext 类定义 QML 引擎中的上下文。通过该类可实现C++和qml属性数据的交互,比如读取qml控件中的公开属性(成员变量)。

实现

  1. 通过 QQuickView 类添加qml控件代码文件:
QQuickView *mQuickView = new QQuickView();
mQuickView->setSource(QUrl("qrc:/testQml.qml"));
  1. 将qml控件导入QWidget中:
QWidget *mQuickWidget = QWidget::createWindowContainer(mQuickView, this);
mQuickWidget->setMinimumSize(80,30);	//设置被嵌入的窗口大小和位置
mQuickWidget->move(0,0);
mQuickWidget->show(); 					// 显示qml
  1. 如果不需要交互就到此为止了。步骤 3 进行交互

    设置qml控件成员及读取其值

QQmlContext *mQuickContext = mQuickView->rootContext();// 用于与qml交互

//首先进行读取,属性名:quickWidgetWidth、quickWidgetHeigh
int width = mQuickContext->contextProperty("quickWidgetWidth").toInt();
int hight = mQuickContext->contextProperty("quickWidgetHeigh").toInt();
qDebug()<<"width:"<<width;
qDebug()<<"hight:"<<hight;

//设置qml控件quickWidgetWidth、quickWidgetHeigh属性
mQuickContext->setContextProperty("quickWidgetWidth", 30);
mQuickContext->setContextProperty("quickWidgetHeight", 30);

//读取显示,测试是否写入成功
width = mQuickContext->contextProperty("quickWidgetWidth").toInt();
hight = mQuickContext->contextProperty("quickWidgetHeigh").toInt();
qDebug()<<"width:"<<width;
qDebug()<<"hight:"<<hight;

测试用的testQml.qml文件:

import QtQuick 2.0

Rectangle {
    x: 0; // 缺省为0
    y: 0; // 缺省为0
    width: quickWidgetWidth;   // width是宽度
    height: quickWidgetHeight; // height是高度
    color: "red";
}

QML 嵌套 QWidget(必要性不大?)

https://download.csdn.net/download/zs1123/13211576

https://download.csdn.net/download/weixin_40912639/10876647

.ui 混合 .qml

https://blog.csdn.net/weixin_43814837/article/details/104969474

协同 Web

QWidget 嵌入 Web

QWidget中与Web相关的主要类:

  • QWebEngineView
  • QWebInspector
  • QWebView

QGraphics 嵌入 Web

QGraphics系列中与Web相关的主要类:

  • QGraphicsItem > QGraphicsObject > QGraphicsWidget
    • QGraphicsProxyWidget
    • QGraphicsWebView

看到这个 QGraphicsWidget 应该也明白了,原理跟 QWidget 嵌入 Web 是一样的

QML 嵌入 Web

WebEngine QML Type

Web 中嵌入 ……(应该做不到吧,也没什么必要)