简述
在使用 Qt Widgets 时,经常要实现一些比较炫酷的效果(例如:滑动、翻页),这时选择 QML 会显得非常简单。
那么,问题来了:
- 能不能将 QML 和 Qt Widgets 结合在一起使用?
- 如果能,都有什么方式?
- QML 和 Qt Widgets 之间又该如何交互?
版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820
一个简单的 QML
创建了一个简单的 QML 文件,用于显示一个绿色的矩形,其中包含一个文本。为了说明 QML 与 Qt Widgets 的交互,在矩形中添加了两个信号。
import QtQuick 2.1
Rectangle {
id: root
color: "green"
width: 200
height: 200
// 发送给 Qt Widgets 的信号
signal qmlSignal
// 从 Qt Widgets 接收到的信号
signal cSignal
Text {
id: myText
text: "Click me"
font.pointSize: 14
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: qmlSignal()
}
// 信号处理程序(处理从 Qt Widgets 接收到的信号)
onCSignal: {
root.color = "blue"
myText.text = "Call the qml signal handler"
}
}
如果需要,可以将像往常一样使用 qmlscene 来运行。
加载和显示 QML
要加载和显示 QML,可以使用以下两种方式:
QQuickWidget
QQuickView
无论使用哪种方式,一旦主源文件的 URL 被指定,都将自动加载和显示 QML 视图。
注意: 在 QML运行环境 中,还介绍了另一种方式 - QQmlEngine + QQmlComponent
,但是这种方式不能以 view 的形式加载。
使用 QQuickWidget
QQuickWidget 是 Qt 5.3 中提供的一个类,继承自 QWidget,它是 QQuickWindow 一个很方便的包装器,用于显示 Qt Quick 用户界面。
使用方式:
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();
使用 QQuickView
QQuickView 是 Qt 5.0 中提供的一个类,继承自 QQuickWindow(继承自 QWindow),用于显示 Qt Quick 用户界面。
使用方式:
QQuickView *view = new QQuickView;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();
可以看到,两者的使用方式几乎没什么区别。但是,QQuickWidget 基于 QWidget,而 QQuickView 基于 QWindow,所以需要将其转换为 QWidget,才能与 Qt Widgets 相结合。
这样,就需要再引入一个函数:
[static] QWidget *QWidget::createWindowContainer(QWindow *window, QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags())
该函数用于创建一个 QWidget,可以将 window 嵌入到基于 QWidget 的应用程序中。
所以,要将 QQuickView 转为 QWidget,可以使用下述方式:
QQuickView *view = new QQuickView();
QWidget *widget = QWidget::createWindowContainer(view, this);
view->setSource(QUrl("qrc:/main.qml"));
将 QML 与 Qt Widgets 相结合
当一切准备就绪,就可以将 QML 与 Qt Widgets 完美结合在一起了:
最终效果:
源码如下:
#include "widget.h"
#include <QQuickView>
#include <QVBoxLayout>
#include <QQuickWidget>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(300, 300);
// 方式一
// QQuickView *pView = new QQuickView();
// QWidget *pWidget = QWidget::createWindowContainer(pView, this);
// pView->setResizeMode(QQuickView::SizeRootObjectToView);
// pView->setSource(QUrl("qrc:/main.qml"));
// 方式二
QQuickWidget *pWidget = new QQuickWidget();
pWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
pWidget->setSource(QUrl("qrc:/main.qml"));
m_pButton = new QPushButton(this);
m_pButton->setText("Qt Widgets...");
QVBoxLayout *pLayout = new QVBoxLayout();
pLayout->addWidget(pWidget);
pLayout->addWidget(m_pButton);
pLayout->setSpacing(10);
pLayout->setContentsMargins(10, 10, 10, 10);
setLayout(pLayout);
// QML 与 Qt Widgets 通信
// QObject *pRoot = (QObject*)pView->rootObject();
QObject *pRoot = (QObject*)pWidget->rootObject();
if (pRoot != NULL) {
connect(pRoot, SIGNAL(qmlSignal()), this, SLOT(receiveFromQml()));
connect(m_pButton, SIGNAL(clicked(bool)), pRoot, SIGNAL(cSignal()));
}
}
void Widget::receiveFromQml()
{
m_pButton->setText("Call the C++ slot");
}
结合之后,少不了通信,这里采用信号槽的方式,通过 QML 的根元素 root 来发送和接收信号。