QT qml入门

效果图:

简单讲解:

创建一个Qt Quick Application - Empty项目,编译器如下,我一般只选择msvc2017 32bit

然后就可以直接运行了,但是一个main跑qml文件,控制起来可能有些麻烦,有些需要C++操作的具体控制可能不好写,于是我将其改成了C++与qml混合编码的样子

先添加一个窗口,用来加载qml文件,qml用来布局样式(刚创建出来的main.qml的根元素是window,现在创建一个窗口加载这个资源,就得把window改为Item了,详见下方main.qml文件内容)

main.cpp

#include <QQmlApplicationEngine>

#include <QApplication>
#include "loginwindow.h"

int main(int argc, char *argv[])
{
//    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

//    QGuiApplication app(argc, argv);

//    QQmlApplicationEngine engine;
//    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
//    if (engine.rootObjects().isEmpty())
//        return -1;

    QApplication app(argc, argv);

    loginWindow login;
    login.show();

    return app.exec();
}

原来是直接加载qml文件当窗口用,现在自己创建了loginWindow窗口

loginwindow.h

#ifndef LOGINWINDOW_H
#define LOGINWINDOW_H

#include <QWidget>
#include <QQuickWidget>
#include <QQmlContext>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QMainWindow>

class loginWindow : public QWidget
{
    Q_OBJECT
public:
    explicit loginWindow(QWidget *parent = nullptr);
    // 带Q_INVOKABLE宏标识,可以从qml中调用这个接口
    Q_INVOKABLE int getVerificationCode();

    // qml中实现无边框窗口拖动有点闪烁,所以干脆放到窗口实现中
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

signals:
    // signal中的函数,可以再qml文件中用Connections响应
    void sendToQml(QString text);

public slots:

private:
    // 加载qml文件用的widget
    QQuickWidget *m_contentView;
    // 记录窗口拖动用的变量
    QPoint startPoint;
    bool bLeftButtonDown;
};

#endif // LOGINWINDOW_H

loginwindow.cpp

#include "loginwindow.h"

loginWindow::loginWindow(QWidget *parent) : QWidget(parent)
{
    // qml布局应用到一个widget中
    m_contentView = new QQuickWidget();
    m_contentView->rootContext()->setContextProperty("theLoginWindow", this); //给qml设置一个可以用的变量,可以不叫theLoginWindow,可以传this以外的对象
    m_contentView->setSource(QUrl("qrc:///main.qml")); //设置对应的qml文件

    // qml对应的widget添加到本窗口
    QVBoxLayout *layout = new QVBoxLayout;
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addWidget(m_contentView);
    setLayout(layout);

    // 设置无边框
    setWindowFlags(Qt::FramelessWindowHint);

    // 发送信号,自己的signal由qml响应
    emit sendToQml("巴扎嘿");
}

int loginWindow::getVerificationCode()
{
    return QMessageBox::information(NULL, "haha", "呵呵呵", QMessageBox::Ok | QMessageBox::Abort);
}

void loginWindow::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::MouseButton::LeftButton)
    {
        startPoint = event->pos();
        bLeftButtonDown = true;
    }
}

void loginWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::MouseButton::LeftButton)
    {
        bLeftButtonDown = true;
    }

}

void loginWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(bLeftButtonDown)
    {
        int offset_x = event->pos().x() - startPoint.x();
        int offset_y = event->pos().y() - startPoint.y();

        move(frameGeometry().x() + offset_x, frameGeometry().y() + offset_y);
    }
}

main.qml

import QtQuick 2.9
import QtQuick.Controls 2.2

Item {
    id:mainWindow
    visible: true
    width: 500
    height: 700
    property string lineColor: "#dcdcdc"

    Image{
        x:0
        y:0
        width:parent.width
        height:width*388/500
        source: "../../res/login_bg.png"
    }

    // 右上角关闭按钮,鼠标悬停离开的时候修改背景图片
    Image{
        id:closeButton
        width:20
        height:width
        y: 10
        x:parent.width - width - y
        source: "../../res/gray_close.png"

        // 支持鼠标进入离开需要设置hoverEnabled: true
        MouseArea{
            anchors.fill: parent
            cursorShape: Qt.PointingHandCursor
            hoverEnabled: true

            onEntered: {
                // id可以直接代表那个元素
                closeButton.source = "../../res/login_close_focus.png"
            }

            onExited: {
                closeButton.source = "../../res/gray_close.png"
            }

            onClicked: {
                // m_contentView->rootContext()->setContextProperty("theLoginWindow", this);使得qml文件中可以使用theLoginWindow对象,也就是那个this
                theLoginWindow.close()
            }
        }
    }

    // Image不支持radius,所以另外写一个qml支持圆角图片
    CircleImage{
        id:userProfileImage
        width:120
        height: 120
        x:(parent.width - width)/2
        y:60
        img_src: "../../res/defaultUser.png"
    }

    // textinput的鼠标不会变成IBeamCursor,不习惯
    // textField无边框要用background: Qt.transparent
    TextField{
        id:phoneNumber
        width: 300
        x:(parent.width - width)/2
        y:400
        inputMethodHints: Qt.ImhFormattedNumbersOnly
        font.pointSize: 14
        placeholderText: qsTr("请输入手机号")
        background: Qt.transparent
        selectByMouse: true
    }

    Rectangle{
        width: 300
        x:(parent.width - width)/2
        y:phoneNumber.y + phoneNumber.height + 12
        height:1
        color:lineColor
    }

    TextField{
        id:verificationCode
        x:phoneNumber.x
        y:phoneNumber.y + phoneNumber.height + 40
        width:150
        placeholderText: qsTr("请输入验证码")
        font.pointSize: 14
        background: Qt.transparent
    }

    Rectangle{
        color:"#ff6321"
        radius: verificationCode.height
        height: verificationCode.height + 10
        width: 120
        x:parent.width - ((parent.width - phoneNumber.width)/2) - width
        y:verificationCode.y - 5
        MouseArea{
            property int ret: -1
            anchors.fill: parent
            cursorShape: Qt.PointingHandCursor
            onClicked: {
                // 可以接收对象接口的返回值
                ret = theLoginWindow.getVerificationCode()
                console.log(ret)
            }
        }
        Text {
            id: getVerificationCode
            text: qsTr("获取验证码")
            font.pointSize: 12
            color: "white"
            anchors.centerIn: parent
        }
    }

    Rectangle{
        width: 300
        x:(parent.width - width)/2
        y:verificationCode.y + verificationCode.height + 12
        height:1
        color:lineColor
    }

    Rectangle{
        x:(parent.width - width)/2
        y:parent.height - height - 80
        width:phoneNumber.width - 40
        height: phoneNumber.height + 20
        color:"#ff6321"
        radius:phoneNumber.height
        MouseArea{
            anchors.fill: parent
            cursorShape: Qt.PointingHandCursor
        }
        Text {
            id: login
            text: qsTr("登录")
            font.pointSize: 14
            font.bold: true
            color: "white"
            anchors.centerIn: parent
        }
    }

    // 响应target的signal函数,加on
    Connections{
        target: theLoginWindow
        onSendToQml:{
            console.log("onSendToQml" + text)
        }
    }
}

CircleImage.qml

import QtQuick 2.0

import QtGraphicalEffects 1.0

Rectangle {
    property string img_src
    radius: width / 2

    Image {
        id: _image
        smooth: true
        visible: false
        anchors.fill: parent
        source: img_src
        sourceSize: Qt.size(parent.size, parent.size)
        antialiasing: true
    }
    Rectangle {
        id: _mask
        color: "black"
        anchors.fill: parent
        radius: width / 2
        visible: false
        antialiasing: true
        smooth: true
    }
    OpacityMask {
        id: mask_image
        anchors.fill: _image
        source: _image
        maskSource: _mask
        visible: true
        antialiasing: true
    }
}

资源图片就自己添加到qrc中去即可,不添加的话,直接source:""不会生效

简单分析:

1.默认创建的Quick Application Empty直接使用qml当窗口,为了混合使用,我将qml的根元素从window替换为item,用来应用到其他窗口中,便于qml写布局,C++写控制代码

2.默认创建的pro文件中第一行,引用的QT +=不够qml与c++混合编码,所以改成了QT += core quickwidgets

3.qml控制C++

C++中

m_contentView = new QQuickWidget();

m_contentView->rootContext()->setContextProperty("theLoginWindow", this);

m_contentView->setSource(QUrl("qrc:///main.qml"));

这样main.qml中就可以使用theLoginWindow变量,访问this中的接口

4.C++控制qml

C++中

signal:

  void sendToQml(QString text);

qml中

Connections{

  target: theLoginWindow

    onSendToQml:{

      console.log("onSendToQml" + text)

    }

}

然后C++中触发事件

emit sendToQml("巴扎嘿");

qml可以再onSendToQml中写入其他控制qml数据的代码

可能还有其他的互相控制的方法,但是目前掌握这么多也够用了,先不探究了

发布项目:

1.windows开始菜单打开qt的命令行工具

2.cd到项目生成目录,debug或relase

3.执行命令windeployqt testQml2.exe --qmldir D:\Qt\Qt5.12.0\5.12.0\msvc2017\qml 参数不一定

**注意** --qmldir后面的参数视情况而定,我用的是Qt5.12.0,mscv,32位编辑程序,其他设备上用的不同版本,不同编译器,不同架构要自己去Qt安装目录下找到对应qml目录才能安装,不写--qmldir参数,或者写错了,可能导致页面空白,

发布了275 篇原创文章 · 获赞 46 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/youyudexiaowangzi/article/details/101055344