qml: 画图Demo

2025-08-10  本文已影响0人  xqiiitan
painterDemo.png

C++渲染图像到QML

C++部分:

-继承QQuickPaintedItem
属性设置:Q_PROPERTY, QML_ELEMENT
函数设置:Q_INVOKABLE
-重载 void paint(QPainter *painter)效率低。
-绘制到QImage,效率高。
QPainter--drawLine
QPen
-update paint QImage
-样式设置,QQuickStyle::setStyle

QML部分。

MyPainter:
beginPaint(point)
movePaint(point)
penColor---ColorDialog
penSize---Slider

3.实现绘图板Demo。

1.QML使用到了cpp中定义的开放属性:Q_PROPERTY
value: mypainter.penSize
2.QML调用了cpp定义的方法:Q_INVOKABLE
parent.beginPaint(Qt.point(mouse.x, mouse.y));
3.QML给cpp的属性,设置新值
onValueChanged: mypainter.penSize = value

//mypainter.h

#ifndef MYPAINTER_H
#define MYPAINTER_H
#include <QObject>
#include <QQmlEngine>
#include <QPainter>
#include <QQuickPaintedItem>
#include "QDebug"

//自定义qml组件 MyPainter.
class MyPainter : public QQuickPaintedItem
{
    Q_OBJECT
    //画笔大小和颜色,开放属性让QML调用.
    Q_PROPERTY(int penSize MEMBER penSize_ NOTIFY penSizeChanged FINAL)
    Q_PROPERTY(QColor penColor MEMBER penColor_ NOTIFY penColorChanged FINAL)
    // QML_ELEMENT;

public:
    explicit MyPainter(QQuickPaintedItem *parent = nullptr);
    //开始绘制,记录开始坐标.qml可调用
    Q_INVOKABLE void beginPaint(QPoint pos) {
        last_ = pos; //记录上次坐标
    }
    //移动
    Q_INVOKABLE void movePaint(QPoint pos) {
        if(img_.isNull()){
            img_ = QImage(this->width(),this->height(), QImage::Format_RGB32);
        }
        QPainter painter(&img_);
        QPen pen;
        pen.setStyle(Qt::SolidLine);
        pen.setWidth(penSize_); //画笔宽度/颜色
        pen.setBrush(penColor_);
        pen.setCapStyle(Qt::RoundCap);
        pen.setJoinStyle(Qt::RoundJoin);
        painter.setPen(pen);
        painter.setRenderHints(QPainter::Antialiasing, true);

        painter.drawLine(last_, pos);
        last_ =  pos;
        update();
    }

signals:
    void penSizeChanged();
    void penColorChanged();
private:
    //内联函数,绘制
    void paint(QPainter *painter) override
    {
        //qDebug() << "paint called";
//        painter->setPen(QPen(Qt::red, 1));  // 蓝色,3像素宽
//        painter->drawLine(QPoint(0,0), QPoint(100,100)); // 绘制线条
        if(!img_.isNull()){
            painter->drawImage(QPoint(0,0),img_);
        }
         painter->drawText(QPoint(100, 100), "test painter demo");
    }
    //画图绘制到img中,方便做导出和撤销动作。
    QImage img_;
    QPoint last_;
    int penSize_ = 2; //成员
    QColor penColor_ = QColor("yellow");

public slots:
};
#endif // MYPAINTER_H

//mypainter.cpp

#include "mypainter.h"
MyPainter::MyPainter(QQuickPaintedItem *parent)
    : QQuickPaintedItem{parent}
{
    qDebug() << "create MyPainter 构造函数";
}

//main.cpp

#include "mypainter.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    //将自定义cpp 注册成QML组件,后续版本可以直接用 QML_ELEMENT关键字。
    qmlRegisterType<MyPainter>("com.example", 1, 0, "MyPainter");
    //设置Control样式 Basic,Fusion,Material
    //QQuickStyle::setStyle("Material");

    QQmlEngine eng;
    QQmlComponent com(&eng);
    com.loadUrl(QUrl("qrc:/main.qml"));
    if(com.isError()) qDebug() << com.errorString();//解析代码
    //auto comwin =  static_cast<QQuickWindow*>(com.create());
    //智能指针,用完之后,ct会自动释放.
    std::unique_ptr<QQuickWindow> ct(
                static_cast<QQuickWindow*>(com.create()));
    if(com.isError()) qDebug() << com.errorString();//运行代码
    return app.exec();
}

//mypainter.h

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.0
import com.example 1.0 //使用自定义的cpp组件 MyPainter
import QtQuick.Dialogs 1.0

Window {
    id:root
    visible: true
    width: 640
    height: 480
    title: qsTr("cpp渲染到扩展的QML类型中:绘图demo")

    //cpp 扩展qml的类型MyPainter。
    MyPainter {
        id: mypainter
        anchors.fill: parent
        MouseArea {
            Row{ //设置画笔粗细+颜色
                spacing:10
                Slider{ //修改penSize
                    width: 220
                    minimumValue:1
                    maximumValue:100
                    value: mypainter.penSize
                    onValueChanged: mypainter.penSize = value
                }
                ColorDialog{ //弹框,选中了颜色 onAccepted
                    id:colorDialog
                    color:"lightblue"
                    onAccepted: mypainter.penColor = color;
                }
                Rectangle{ //字体颜色选择。
                    width: 30; height: 30;
                    color: colorDialog.color
                    MouseArea{
                        anchors.fill: parent
                        onClicked: colorDialog.open()
                    }
                }
            }

            anchors.fill: parent
            hoverEnabled: true
            //鼠标按下,记录开始位置。
            onPressed: (mouse) =>
            {
                parent.beginPaint(Qt.point(mouse.x, mouse.y));
                console.log("onPressed "+ mouse.x+" :"+ mouse.y);
            }
            //鼠标位置按下移动。
            onPositionChanged: (mouse)=>
            {   //左键未按住
                if(!mouse.buttons & Qt.LeftButton)  return;

                parent.movePaint(Qt.point(mouse.x, mouse.y));
                console.log("onMove "+ mouse.x+" :"+ mouse.y);
            }
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读