赞
踩
工作中,有的老版本代码是用QtWidgets来实现的,在后期的OTA实现中,由于种种原因,比如用qml来实现更方便等原因,某些功能的开发确用qml语言来实现,这就涉及到了QWidget与Qml文件的相互嵌入,以及交互问题。
笔者遇到的需求是,做一个语音助手,窗口会实时显示自己说的话,以及一些对话内容,比如听故事界面,要实现一种无边框,圆角的对话框:
按照常规做法,因为代码是QtWidget框架写的,所以我应该也用QWidgets来实现就好了,但是考虑到也写效果的实现和最近一直在用qml开发,就尝试用qml语言来实现了。
加载qml文件,有几种方式:
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
其中main.qml 可以以Window作为根元素,这个时候QML就完全拥有了控制权,可以直接设置窗体的标题、尺寸等信息;
QQuickView最常见的用法如下:
QQuickView view;
view.setResizeMode (QQuickView::SizeRootObjectToView);
view.setSource (QUrl("qrc:/main.qml"));
view.show ();
注意:其中qml文件不能以Window作为根元素,最佳选择是使用Item为根元素,否则会警告:
QQuickView does not support using windows as a root item.
If you wish to create your root window from QML, consider using QQmlApplicationEngine instead.
官网自带的说明例子.一般用来在QWidget界面上加载QML界面
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();
最主要的是qml的嵌入以及与QWidget的交互
1 通过信号槽的方式创建连接
2 通过QMetaObject::invokeMethod(方法调用
这里直接把代码贴在这里,供大家参考,效果如下
代码结构如下:
main.cpp
#include <QApplication>
#include "dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
dialog.h
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> QT_BEGIN_NAMESPACE namespace Ui { class Dialog; } QT_END_NAMESPACE class Dialog : public QDialog { Q_OBJECT public: Dialog(QWidget *parent = nullptr); ~Dialog(); void setTitle(const QString &title); void setTotal(const long v); void setCurValue(const long v); signals: void sigPalyProgress(qreal v); public slots: void onSliderMoved(qreal v); void onPlay(); void onPause(); private: Ui::Dialog *ui; }; #endif // DIALOG_H
dialog.cpp
#include "dialog.h" #include "ui_dialog.h" #include<QQuickItem> #include<QTimer> Dialog::Dialog(QWidget *parent) : QDialog(parent) , ui(new Ui::Dialog) { setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); ui->setupUi(this); QUrl source("qrc:/listen.qml"); ui->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView ); ui->quickWidget->setSource(source); ui->quickWidget->setClearColor(QColor(Qt::transparent)); QQuickItem *item=ui->quickWidget->rootObject(); connect(item,SIGNAL(sliderMoved(qreal)),this,SLOT(onSliderMoved(qreal))); connect(item,SIGNAL(playClicked()),this,SLOT(onPlay())); connect(item,SIGNAL(pauseClicked()),this,SLOT(onPause())); connect(this,SIGNAL(sigPalyProgress(qreal)),item,SIGNAL(updatePlayProgress(qreal))); if(item) QMetaObject::invokeMethod(item,"setPlayState"); int inum=0; QTimer *p = new QTimer; p->setInterval(10); connect(p,&QTimer::timeout,[=]()mutable{ inum+=10; sigPalyProgress(inum); }); p->start(); } Dialog::~Dialog() { delete ui; } void Dialog::setTitle(const QString &title) { QQuickItem *item=ui->quickWidget->rootObject(); if(item) QMetaObject::invokeMethod(item,"setTitle",Q_ARG(QVariant,title)); } void Dialog::setTotal(const long v) { QQuickItem *item=ui->quickWidget->rootObject(); if(item) QMetaObject::invokeMethod(item,"setTotalTime",Q_ARG(long,v)); } void Dialog::setCurValue(const long v) { QQuickItem *item=ui->quickWidget->rootObject(); if(item) QMetaObject::invokeMethod(item,"setCurTime",Q_ARG(long,v)); } void Dialog::onSliderMoved(qreal v) { qDebug() << "onslidermoved:" << v; } void Dialog::onPlay() { qDebug() << "onPlay"; } void Dialog::onPause() { qDebug() << "onPause"; }
listen.qml
import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.3 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 Item { id:control visible: true width: 736 height: 290 // color: "#00000000" // modality: Qt.WindowModal // flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint signal sliderMoved(real v); signal playClicked(); signal pauseClicked(); signal updatePlayProgress(real v); property string title: qsTr("《一起来听红楼梦》") property var totalTimeValue: 20000 property var curTimeValue : 100 function setPlayState() { playbtn.source ="qrc:/pause96.png"; } function setTitle(str) { title = str; } function setTotalTime(v) { totalTimeValue = v; } function setCurTime(v) { curTimeValue = v; } function currentTimeMMSS(time) { var sec= Math.floor(time/1000); var hours=Math.floor(sec/3600); var minutes=Math.floor((sec-hours*3600)/60); var seconds=sec-hours*3600-minutes*60; var hh,mm,ss; if(hours.toString().length<2) hh="0"+hours.toString(); else hh=hours.toString(); if(minutes.toString().length<2) mm="0"+minutes.toString(); else mm=minutes.toString(); if(seconds.toString().length<2) ss="0"+seconds.toString(); else ss=seconds.toString(); if(hh !== "00") { return hh + ":" + mm+":"+ss; } else { return mm+":"+ss; } } Rectangle { id:root anchors.fill: parent color: "#101A24" radius: 40 clip:true Text { id: name text: title anchors.verticalCenter: playbtn.verticalCenter anchors.left: parent.left anchors.leftMargin: 48 width: 520 elide: Text.ElideRight font.pixelSize: 52 font.family: "PingFang SC" font.weight: Font.Medium; color: "#FFFFFF"; //lineHeight: 64 } ParallelAnimation{ //点击动画 id: clickedAnimation PropertyAnimation{ target: playbtn property: "opacity" to: 0.5 //from: 0 duration: 300 } PropertyAnimation{ target: playbtn property: "scale" to: 1.3 //from: 1 duration: 300 } } ParallelAnimation{ //取消点击动画 id: releaseAnimation PropertyAnimation{ target: playbtn property: "opacity" //from: 0.5 to: 1 duration: 300 } PropertyAnimation{ target: playbtn property: "scale" //from: 1.3 to: 1 duration: 300 } } Image { id:playbtn source: "qrc:/play96.png" anchors.right: parent.right anchors.rightMargin: 48 anchors.top: parent.top anchors.topMargin: 48 width:96 height: 96 MouseArea { id:mouse anchors.fill: parent anchors.margins: -16 onClicked: { console.log("clicked") if(playbtn.source == "qrc:/pause96.png") { playbtn.source = "qrc:/play96.png"; pauseClicked(); } else { playbtn.source = "qrc:/pause96.png" playClicked(); } } onPressed: { clickedAnimation.start(); } onReleased: { releaseAnimation.start() } } } Slider{ id: slider anchors.left: parent.left anchors.leftMargin: 48 anchors.bottom: curTime.top anchors.bottomMargin: 16 implicitWidth: 640; implicitHeight: 16; orientation:Qt.Horizontal padding: 0 from: 0 value: curTimeValue to:totalTimeValue stepSize: 1 onMoved: { sliderMoved(slider.value) } background: Rectangle { id:bg implicitWidth: slider.implicitWidth implicitHeight: slider.implicitHeight color: "#2D4247" radius: 16 layer.enabled: true layer.effect: OpacityMask { maskSource: Rectangle { width: bg.width height: bg.height radius: bg.radius } } Rectangle { y: slider.horizontal ? 0 : slider.visualPosition * parent.height width: slider.horizontal ? slider.position * parent.width : parent.width height: slider.horizontal ? parent.height : slider.position * parent.height // color: "#12CFA7" opacity: 1 radius:16 LinearGradient { ///--[Mark] anchors.fill: parent start: Qt.point(0, 0) end: Qt.point(parent.width, 0) ///1.横向渐变 //end: Qt.point(0, height) ///2.竖向渐变 //end: Qt.point(width, height) ///3.斜向渐变 gradient: Gradient { GradientStop { position: 0.0; color: "#618CFF" } GradientStop { position: 1.0; color: "#FF7A6A" } } } } } handle: Item { x: slider.leftPadding + (slider.horizontal ? slider.visualPosition * (slider.availableWidth - width) : (slider.availableWidth - width) / 2) y: slider.topPadding + (slider.horizontal ? (slider.availableHeight - height) / 2 : slider.visualPosition * (slider.availableHeight - height)) implicitWidth: 28 implicitHeight: 28 Rectangle{ id:rect_out anchors.fill: parent radius: width/2 color:"#ffffff" } } } Text { id: curTime text: currentTimeMMSS(curTimeValue) color: "#ffffff" font.pixelSize: 28 anchors.left: parent.left anchors.leftMargin: 48 anchors.bottom: parent.bottom anchors.bottomMargin: 48 } Text { id: totalTime text: currentTimeMMSS(totalTimeValue) color: "#ffffff" font.pixelSize: 28 anchors.right: parent.right anchors.rightMargin: 48 anchors.bottom: parent.bottom anchors.bottomMargin: 48 } } Component.onCompleted: { control.updatePlayProgress.connect(control.setCurTime) } Component.onDestruction:{ control.updatePlayProgress.disconnect(control.setCurTime) } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。