纯QML实现画图工具

来源:互联网 发布:Ubuntu grub引导 编辑:程序博客网 时间:2024/05/21 10:01

        前言,QT5 版本较Qt4 新增了Canvas(画布),可以通过Js实现2D绘图,与HTML5提供的API保持一致,使用非常灵活。下面将介绍使用QML制作简单的画图工具。

    首先,介绍整体布局为。最上侧是菜单,下面是工具条,中间是Canvas(画布),最底侧是状态栏。

    1.菜单栏设计

     为实现分页显示不同的工具,采用TabView进行布局。代码如下:

import QtQuick 2.0import QtQuick.Controls 1.2import QtQuick.Controls.Styles 1.2import QtQuick.Window 2.0import QtQuick.Dialogs 1.2//菜单选项Rectangle{    id:root    height: 120    width: appWindow.width    property color paintColor //绘制颜色    property string picPath:""//图片路径    TabView{        width: appWindow.width        id:tabView        Tab{            title: "文件"            Rectangle {                id: see                width: appWindow.width                anchors {                    horizontalCenter: parent.horizontalCenter                    top: parent.top                    topMargin: 8                }                color: "transparent"                Row{                    spacing: 5                    Column{                        Row{                            spacing: 5                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/new.png"                                rectColor: "transparent"                                describle: "新建"                                onClicked: {                                    messageDialog.text="是否保存?"                                    messageDialog.standardButtons=StandardButton.Yes | StandardButton.No                                    messageDialog.icon=StandardIcon.Question                                    messageDialog.open()                                }                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/open.png"                                rectColor: "transparent"                                describle: "打开"                                onClicked: {                                    fileDialog.open()                                    fileDialog.selectExisting=true                                }                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/save.png"                                rectColor: "transparent"                                describle: "保存"                                onClicked:{                                    fileDialog.selectExisting=false                                    fileDialog.open()                                }                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/saveOther.png"                                describle: "另存"                                onClicked:{                                    fileDialog.selectExisting=false                                    fileDialog.open()                                }                            }                        }                        Rectangle{                            width: parent.width                            height: 25                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"文件操作"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                    //分隔符                    Rectangle{height: 64;width: 1;color:"#E2E3E4";}                    Column{                        Row{                            spacing: 5                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/print.png"                                rectColor: "transparent"                                describle: "打印"                                onClicked: appWindow.showFullScreen()                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/exit.png"                                rectColor: "transparent"                                describle: "退出"                                onClicked:  Qt.quit()                            }                        }                        Rectangle{                            width: parent.width                            height: 25                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"操作"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                }                FileDialog {                    id: fileDialog;                    title: qsTr("Please choose an image file");                    nameFilters:["PNG(*.png)","JPEG(*.jpg *.jpeg *.jpe)","GIF(*.gif)","位图(*.bmp)"]                    property int isSave: 1 //判断是打开还是保存操作                    onAccepted: {                        if(!fileDialog.selectExisting)                            if(canvas.saveImage(picPath))                            {                                messageDialog.title="提示"                                messageDialog.text="保存成功!"                                messageDialog.icon=StandardIcon.Information                                messageDialog.standardButtons=StandardButton.Ok                                messageDialog.open()                            }                        var filepath = new String(fileUrl);                        if(Qt.platform.os == "windows")                            root.picPath= filepath.slice(8);                        else                            root.picPath = filepath.slice(7);                    }                }                //弹窗提示                MessageDialog {                    id: messageDialog                    onAccepted: {                        console.log("do samething")                    }                    onYes: {fileDialog.selectExisting=false;fileDialog.open();}                    onNo: canvas.newImage()                }            }        }        Tab{            title: "设置"            Rectangle {                id: colorTools                width: appWindow.width                anchors {                    horizontalCenter: parent.horizontalCenter                    top: parent.top                    topMargin: 8                }                color: "transparent"                Row{                    spacing: 5                    anchors.left: parent.left                    anchors.leftMargin: 15                    Column{                        Row{                            spacing: 5                            //设置线宽                            PicButton{                                id:selectWeight                                width:50                                height: grid.height                                imagePath: "res/weight.png"                                describle: "粗细"                                isImageVisible:true                                onClicked: {                                    listWeight.visible=listWeight.visible==true?false:true;                                    listWeight.z=3                                }                            }                            //分隔符                            Rectangle{height: grid.height;width: 1;color:"#E2E3E4";}                            //选中的颜色                            PicButton{                                id:selectRect                                width:50                                height: grid.height                                describle: "颜色"                            }                            //分隔符                            Rectangle{height: grid.height;width: 1;color:"#E2E3E4";}                            //色彩网格                            Grid{                                id:grid                                columns: 7                                rows:2                                spacing: 2                                Repeater {                                    model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444","#DD6644","#AA4444","#FFBB33", "#FF4444","#DD6644","#AA4444","#FFBB33", "#FF4444","#DD6644","#AA4444"]                                    ColorGrid {                                        id: red                                        color: modelData                                        onClicked:{                                            selectRect.rectColor=color                                            root.paintColor = color                                        }                                    }                                }                            }                            //分隔符                            Rectangle{height: grid.height;width: 1;color:"#E2E3E4";}                            //颜色对话框                            PicButton{                                id:editRect                                width:50                                height: grid.height                                isImageVisible: true                                imagePath: "res/pic.png"                                rectColor: "transparent"                                describle: "编辑"                                onClicked: colorD.open()                                ColorDialog{                                    id:colorD                                    onColorChanged: {selectRect.rectColor=color;root.paintColor=color;}                                }                            }                            //分隔符                            Rectangle{height: grid.height;width: 1;color:"#E2E3E4";}                        }                        Rectangle{                            width: grid.width                            height: 30                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"颜色"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                    //形状设置                    Column{                        Grid{                            id:xz                            width: 200                            height: 60                            Repeater{                                model:[]                            }                        }                        Rectangle{                            width: xz.width                            height: 30                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"形状"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                }            }        }        Tab{            title: "查看"            Rectangle {                id: show                width: appWindow.width                anchors {                    horizontalCenter: parent.horizontalCenter                    top: parent.top                    topMargin: 8                }                color: "transparent"                Row{                    spacing: 5                    Column{                        Row{                            spacing: 5                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/increase.png"                                rectColor: "transparent"                                describle: "放大"                                onClicked: {                                    if( statusbar.sliderValue+0.25>1)                                        statusbar.sliderValue=1;                                    else                                        statusbar.sliderValue= statusbar.sliderValue+0.25                                }                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/decrease.png"                                rectColor: "transparent"                                describle: "缩小"                                onClicked: {                                    if( statusbar.sliderValue-0.25<-1)                                        statusbar.sliderValue=-1;                                    else                                        statusbar.sliderValue= statusbar.sliderValue-0.25                                }                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/big.png"                                describle: "100%"                                onClicked: statusbar.sliderValue=0;                            }                        }                        Rectangle{                            width: parent.width                            height: 25                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"缩放"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                    //分隔符                    Rectangle{height: 64;width: 1;color:"#E2E3E4";}                    Column{                        Row{                            spacing: 5                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/fullScreen.png"                                rectColor: "transparent"                                describle: "全屏"                                onClicked: appWindow.showFullScreen()                            }                            PicButton{                                width: 50                                height: 64                                isImageVisible: true                                imagePath: "res/exitFull.png"                                rectColor: "transparent"                                describle: "退出"                                onClicked: appWindow.showNormal()                            }                        }                        Rectangle{                            width: parent.width                            height: 25                            color:"#F5F6F7"                            anchors.horizontalCenter: parent.horizontalCenter                            Text{                                text:"显示"                                color:"#929292"                                anchors.centerIn: parent                            }                        }                    }                }            }        }        style:TabViewStyle{            frameOverlap: 1            tab: Rectangle {                color: styleData.selected ? "#F5F6F7" :"#FFFFFF"                implicitWidth: Math.max(text.width + 4, 100)                implicitHeight: 30                radius: 1                Text {                    id: text                    anchors.centerIn: parent                    text: styleData.title                    color: "black"                    font.pixelSize: 12                }            }            frame: Rectangle {                width: appWindow.width                color: "#F5F6F7"            }        }    }}    2.工具栏,采用ToolBar设计。代码如下:     ToolBar{        id:toolBar        anchors.top: menuBar.bottom        Row{            anchors.verticalCenter: parent.verticalCenter            spacing: 5            ToolButton{                width:25                height: 25                tooltip: "保存"                iconSource: "./res/save.png"            }            ToolButton{                width:25                height: 25                tooltip: "撤销"                iconSource: "./res/revoke.png"            }            ToolButton{                width:25                height: 25                tooltip: "恢复"                iconSource: "./res/undo.png"            }            Rectangle{                width:25                height: 25                color: menuBar.paintColor                border.color: "gray"                border.width: 1            }        }    }    3. 中间画布使用QML自己的Canvas 实现代码如下:import QtQuick 2.3import QtQml 2.0import QtQuick.Controls 1.2import QtQuick.Controls.Styles 1.2import QtQuick.Window 2.0import QtGraphicalEffects 1.0Rectangle{    id:root    width:500*statusbar.rate    height: 300*statusbar.rate    property alias mouseX: area.mouseX    property alias mouseY: area.mouseY    property string imgPath: menuBar.picPath    signal save(string str)    property double lineWidth: 1 //线宽    property color paintColor: menuBar.paintColor //画笔颜色    property var ctx: canvas.getContext('2d')    function saveImage(imgName)    {        return canvas.save(imgName)    }    //新建画布,清除画布    function newImage()    {         ctx.clearRect(0,0,canvas.width,canvas.height)         canvas.requestPaint()    }    function rePaint()    {    }    Image{        id:imgP        source:{            if(imgPath!="")                "file:///"+imgPath;            else                "";        }        visible: false        width:canvas.width        height: canvas.height    }    //    Timer{        interval: 100        running: true        triggeredOnStart: true        repeat: true        onTriggered: canvas.requestPaint()    }//    Image{//        id:picImg//        anchors.fill: parent//    }    //画板    Canvas {        id: canvas        anchors.fill: parent        antialiasing: true        property real lastX //画笔的终止位置        property real lastY        //opacity: 0        onImageLoaded: {            if(canvas.isImageLoaded(imgP.source))            {                console.log("imps")            }            if(canvas.isImageError(imgP.source))            {                console.log("impE")            }        }        onPaint: {            if(imgP.source!="")                ctx.drawImage(imgP,0,0)            ctx.lineWidth = lineWidth            ctx.strokeStyle = paintColor            ctx.beginPath()            ctx.moveTo(lastX, lastY)            lastX = area.mouseX            lastY = area.mouseY            ctx.lineTo(lastX, lastY)            ctx.stroke()        }        MouseArea {            id: area            anchors.fill: parent            acceptedButtons: Qt.AllButtons            onPressed: {                canvas.lastX = mouseX                canvas.lastY = mouseY            }            onPositionChanged: {                canvas.requestPaint()            }            onClicked: {                if(mouse.button==Qt.RightButton)                    contentMenu.popup();//                var url=canvas.toDataURL('image/png');//                picImg.source=url;            }            //鼠标形状改变            cursorShape: (containsMouse? (pressed? Qt.CrossCursor: Qt.ArrowCursor): Qt.ArrowCursor);            Menu { // 右键菜单                //title: "Edit"                id: contentMenu                MenuItem {                    text: "新建"                    shortcut: "Ctrl+N"                    onTriggered: {}                }                MenuItem {                    text: "保存"                    shortcut: "Ctrl+S"                    onTriggered: {}                }                MenuItem {                    text: "粘贴"                    shortcut: "Ctrl+V"                    onTriggered: {}                }                MenuSeparator { }                Menu {                    title: "More Stuff"                    MenuItem {                        text: "Do Nothing"                    }                }            }        }    }    //左侧    Rectangle{        width: 5        height: 5        x:parent.width        y:parent.height/2        border.color: "black"        border.width: 1        MouseArea{            id:xRate            anchors.fill: parent            cursorShape: (containsMouse? (pressed? Qt.SizeHorCursor: Qt.ArrowCursor): Qt.ArrowCursor);            drag.target: parent            onPositionChanged: {                root.width=parent.x            }        }    }    //下侧    Rectangle{        width: 5        height: 5        border.color: "black"        border.width: 1        x:parent.width/2        y:parent.height        Drag.active: yRate.drag.active        Drag.hotSpot.x: 10        Drag.hotSpot.y: 10        MouseArea{            id:yRate            anchors.fill: parent            cursorShape: (containsMouse? (pressed? Qt.SizeVerCursor: Qt.ArrowCursor): Qt.ArrowCursor);            drag.target: parent            onPositionChanged: {                root.height=parent.y            }        }    }    //对角    Rectangle{        width: 5        height: 5        x:parent.width        y:parent.height        border.color: "black"        border.width: 1        Drag.active: xyRate.drag.active        Drag.hotSpot.x: 10        Drag.hotSpot.y: 10        MouseArea{            id:xyRate            anchors.fill: parent            cursorShape: (containsMouse? (pressed? Qt.SizeFDiagCursor: Qt.ArrowCursor): Qt.ArrowCursor);            drag.target: parent            onPositionChanged: {                root.width=parent.x                root.height=parent.y            }        }    }}3.底部状态栏设计,左侧为鼠标坐标,中间为图像大小,右侧为缩放比例调整。代码如下:import QtQuick 2.0import QtQuick.Controls 1.2import QtQuick.Controls.Styles 1.2Rectangle {    color: "#F0F0F0";    implicitHeight: 30;    width: parent.width;    property string position: "" //位置坐标    property int pWidth: 0  //图像宽度    property int pHeight: 0 //图像高度    property alias sliderValue:pslider.value //放大缩小值    //放大倍数    property double  rate: {        if(pslider.value==0)1;        else            (1+pslider.value).toFixed(2)    }    Row{        anchors.left: parent.left        anchors.leftMargin: 10        anchors.verticalCenter: parent.verticalCenter        Image{            width: 20            height: 20            source: "./res/pic.png"            anchors.verticalCenter: parent.verticalCenter        }        Text{            id:pos            anchors.verticalCenter: parent.verticalCenter            text:" "+position        }    }    Row{        anchors.verticalCenter: parent.verticalCenter        anchors.horizontalCenter: parent.horizontalCenter        Image{            width: 20            height: 20            source: "./res/pic.png"            anchors.verticalCenter: parent.verticalCenter        }        Text{            id:pix            text:" "+pWidth+" x "+pHeight+"像素"            anchors.verticalCenter: parent.verticalCenter        }    }    Row{        anchors.right: parent.right        anchors.rightMargin: 10        anchors.verticalCenter: parent.verticalCenter        spacing: 5        Text{            id:pre //百分比            color: "black"            anchors.verticalCenter: parent.verticalCenter            text:{                if(pslider.value==0)                    "100%"                else                    (1+pslider.value).toFixed(2)*100+"%"            }        }        Image{            width: 20            height: 20            source: "./res/decrease.png"            MouseArea{                anchors.fill: parent                onClicked: {                    if( pslider.value-0.25<-1)                        pslider.value=-1;                    else                        pslider.value=pslider.value-0.25                }            }        }        Slider {            id:pslider            minimumValue: -1            maximumValue: 1            value:0            style: SliderStyle {                groove: Rectangle {                    implicitWidth: 150                    implicitHeight: 5                    color: "#F0F0F0"                    border.color: "lightgray"                    border.width: 1                }                handle: Rectangle {                    anchors.centerIn: parent                    color: control.pressed ? "blue" : "lightgray"                    implicitWidth: 12                    implicitHeight: 20                }            }            onValueChanged: {                var img=canvas.ctx.getImageData(0, 0, canvas.width, canvas.height)                  canvas.ctx.putImageData(img, 0, 0)            }        }        Image{            width: 20            height: 20            source: "./res/increase.png"            MouseArea{                anchors.fill: parent                onClicked: {                    if( pslider.value+0.25>1)                        pslider.value=1;                    else                       pslider.value= pslider.value+0.25                }            }        }    }}
最终的设计效果如下:

1 0