当前位置:   article > 正文

Qt 之 QWidget嵌入Qml文件以及如何交互_qwidget嵌入到qml中

qwidget嵌入到qml中

项目场景:

工作中,有的老版本代码是用QtWidgets来实现的,在后期的OTA实现中,由于种种原因,比如用qml来实现更方便等原因,某些功能的开发确用qml语言来实现,这就涉及到了QWidget与Qml文件的相互嵌入,以及交互问题。


问题描述:

笔者遇到的需求是,做一个语音助手,窗口会实时显示自己说的话,以及一些对话内容,比如听故事界面,要实现一种无边框,圆角的对话框:
在这里插入图片描述

按照常规做法,因为代码是QtWidget框架写的,所以我应该也用QWidgets来实现就好了,但是考虑到也写效果的实现和最近一直在用qml开发,就尝试用qml语言来实现了。

加载qml文件,有几种方式:

第一种 QQmlApplicationEngine

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  • 1
  • 2

其中main.qml 可以以Window作为根元素,这个时候QML就完全拥有了控制权,可以直接设置窗体的标题、尺寸等信息;

第二种 QQuickView

QQuickView最常见的用法如下:

QQuickView view;
view.setResizeMode (QQuickView::SizeRootObjectToView);
view.setSource (QUrl("qrc:/main.qml"));
view.show ();
  • 1
  • 2
  • 3
  • 4

注意:其中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.
  • 1
  • 2

第三种 QQuickWidget

官网自带的说明例子.一般用来在QWidget界面上加载QML界面

	QQuickWidget *view = new QQuickWidget;
    view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
    view->show();
  • 1
  • 2
  • 3

代码示例以及解析:

最主要的是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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

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)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/831258
推荐阅读
相关标签
  

闽ICP备14008679号