The avatar of the Qt Quick instance and the avatar of the qtquick instance
The Android mobile phone has a good function. It allows you to place widgets on the desktop. There is a widget called a photo frame, which allows you to select a photo and take a part, put it in the photo frame. I put a few photo frames on my desktop, which are my daughter's photos. This example was inspired by the frame widget. I call it "dig an avatar". Let's first look at the running effect.
Running effect 1 on the computer:
Figure 1 computer Avatar digging Android mobile phone running effect 2:
For details about how to create a project, see "Hello World of Qt Quick". for Android configuration, see Qt 5.2 for Android development in Windows and Qt on Android: the entire process of Hello World. The project name is PickThumb, And the Android package name is an. qt. PickThumb. Source code analysis C ++ code
To enable PickThumb to exit normally, I installed an Event Filter for QGuiApplication and filtered the BACK button. The following is the main. cpp file:
#include <QGuiApplication>#include <QQmlApplicationEngine>#include <QKeyEvent>class KeyBackQuit: public QObject{public: KeyBackQuit(QObject *parent = 0) : QObject(parent) {} bool eventFilter(QObject *watched, QEvent * e) { switch(e->type()) { case QEvent::KeyPress: if( ((QKeyEvent*)e)->key() == Qt::Key_Back ) { e->accept(); return true; } break; case QEvent::KeyRelease: if( ((QKeyEvent*)e)->key() == Qt::Key_Back ) { e->accept(); qApp->quit(); return true; } break; default: break; } return QObject::eventFilter(watched, e); }};int main(int argc, char *argv[]){ QGuiApplication app(argc, argv); app.installEventFilter(new KeyBackQuit); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec();}
The KeyBackQuit class overrides the eventFilter () method to filter the Key_Back key, and calls the quit () method of QCoreApplication to exit the application. The filter is installed on the QGuiApplication instance in the main () function.
QML code analysis is now the main character. The main. qml file contains more than 200 lines of code. The content is as follows:
import QtQuick 2.2import QtQuick.Window 2.1import QtQuick.Controls 1.2import QtQuick.Controls.Styles 1.2import QtQuick.Dialogs 1.1Window { visible: true width: 480; height: 320; minimumHeight: 320; minimumWidth: 480; color: "black"; onWidthChanged: mask.recalc(); onHeightChanged: mask.recalc(); Image { id: source; anchors.fill: parent; fillMode: Image.PreserveAspectFit; visible: false; asynchronous: true; onStatusChanged: { if(status == Image.Ready){ console.log("image loaded"); mask.recalc(); } } } FileDialog { id: fileDialog; title: "Please choose an Image File"; nameFilters: ["Image Files (*.jpg *.png *.gif)"]; onAccepted: { source.source = fileDialog.fileUrl; } } Canvas { id: forSaveCanvas; width: 128; height: 128; contextType: "2d"; visible: false; z: 2; anchors.top: parent.top; anchors.right: parent.right; anchors.margins: 4; property var imageData: null; onPaint: { if(imageData != null){ context.drawImage(imageData, 0, 0); } } function setImageData(data){ imageData = data; requestPaint(); } } Canvas { id: mask; anchors.fill: parent; z: 1; property real w: width; property real h: height; property real dx: 0; property real dy: 0; property real dw: 0; property real dh: 0; property real frameX: 66; property real frameY: 66; function calc(){ var sw = source.sourceSize.width; var sh = source.sourceSize.height; if(sw > 0 && sh > 0){ if(sw <= w && sh <=h){ dw = sw; dh = sh; }else{ var sRatio = sw / sh; dw = sRatio * h; if(dw > w){ dh = w / sRatio; dw = w; }else{ dh = h; } } dx = (w - dw)/2; dy = (h - dh)/2; } } function recalc(){ calc(); requestPaint(); } function getImageData(){ return context.getImageData(frameX - 64, frameY - 64, 128, 128); } onPaint: { var ctx = getContext("2d"); if(dw < 1 || dh < 1) { ctx.fillStyle = "#0000a0"; ctx.font = "20pt sans-serif"; ctx.textAlign = "center"; ctx.fillText("Please Choose An Image File", width/2, height/2); return; } ctx.clearRect(0, 0, width, height); ctx.drawImage(source, dx, dy, dw, dh); var xStart = frameX - 66; var yStart = frameY - 66; ctx.save(); ctx.fillStyle = "#a0000000"; ctx.fillRect(0, 0, w, yStart); var yOffset = yStart + 132; ctx.fillRect(0, yOffset, w, h - yOffset); ctx.fillRect(0, yStart, xStart, 132); var xOffset = xStart + 132; ctx.fillRect(xOffset, yStart, w - xOffset, 132); //see through area ctx.strokeStyle = "red"; ctx.fillStyle = "#00000000"; ctx.lineWidth = 2; ctx.beginPath(); ctx.rect(xStart, yStart, 132, 132); ctx.fill(); ctx.stroke(); ctx.closePath (); ctx.restore(); } } MultiPointTouchArea { anchors.fill: parent; minimumTouchPoints: 1; maximumTouchPoints: 1; touchPoints:[ TouchPoint{ id: point1; } ] onUpdated: { mask.frameX = point1.x; mask.frameY = point1.y; mask.requestPaint(); } onReleased: { forSaveCanvas.setImageData(mask.getImageData()); actionPanel.visible = true; } onPressed: { actionPanel.visible = false; } } Component { id: flatButton; ButtonStyle { background: Rectangle{ implicitWidth: 70; implicitHeight: 30; border.width: control.hovered ? 2: 1; border.color: control.hovered ? "#c0c0c0" : "#909090"; color: control.pressed ? "#a0a0a0" : "#707070"; } label: Text { anchors.fill: parent; font.pointSize: 12; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; text: control.text; color: (control.hovered && !control.pressed) ? "blue": "white"; } } } Row { anchors.horizontalCenter: parent.horizontalCenter; anchors.bottom: parent.bottom; anchors.bottomMargin: 20; id: actionPanel; z: 5; spacing: 8; Button { style: flatButton; text: "Open"; onClicked: fileDialog.open(); } Button { style: flatButton; text: "Save"; onClicked: { forSaveCanvas.save("selected.png"); actionPanel.visible = false; } } Button { style: flatButton; text: "Cancel"; onClicked: actionPanel.visible = false; } }}
The logic of the Code is as follows: click the "Open" button to Open a dialog box. Select an Image and load it with a hidden Image object. After loading, the Canvas object is triggered to draw an Image; when you drag with your fingers (or press the left mouse button), the center of the selected box is moved with your fingers, and the image in the box is normal brightness. When you raise your finger, the Operation menu is displayed, if "Save" is selected, an image of the selected area is saved to the file through a hidden Canvas. I have articles on Row, Button, ButtonStyle, Component, Image, and FileDialog used in QML. For more information, see my column Qt Quick concise tutorial. MultiPointTouchArea and Canvas didn't talk about it, see Qt help. The following figure shows the effect of "the entire photo is dimmed and only the image is displayed normally in the selected box.
I have defined a Canvas with the id of mask, which uses the Image object with the id of source to draw images. The image is drawn at the bottom layer, and then the rectangle filled with transparent colors is drawn on it, so the image is dimmed. The entire Canvas is divided into a "back" shape, with a completely transparent rectangle in the middle and translucent surrounding. The translucent department consists of four rectangles, namely the top, bottom, left, and right.
The image is displayed in proportion. After the image is loaded successfully, the target rectangle required for painting is calculated first, which is directly referenced during painting to avoid repeated calculation. To adapt to window size changes, the desktop version implements two signal processors, onWidthChanged and onHeightChanged, to update the drawing parameters.
When the user selects to save, the pixels in the transparent area of the mask are dug out (getImageData), generate a CanvasImageData object, hand it to another Canvas object for display, and call its save () method To write the content to a file.
This is all.
Review my articles in the Qt Quick series:
- Qt Quick introduction
- QML language basics
- Qt Quick's Hello World graphic explanation
- Simple Qt Quick tutorial
- Signal and slot of Qt Quick event processing
- Qt Quick event processing-mouse, keyboard, and Timer
- Qt Quick event processing-pinch, zoom, and rotate
- Dynamic Creation of Qt Quick components and objects
- Introduction to Qt Quick Layout
- QML and C ++ mixed programming in Qt Quick
- Qt Quick image processing instance meitu xiuxiu (source code download)
- Explanation of Qt Quick PathView
Qt quick is different from qt designer.
Qt designer is used to design the C ++ code interface of Qt. Designer also has the source code, that is ***. ui file. during compilation, the compiler sets ***. ui to moc _****. cpp is merged into the code.
However, the development of the C ++ interface is difficult for some users. Therefore, it adds a QtQuick library based on the existing Qt code. The Code of QtQuick is not C ++, but a qml script (similar to javascript on a webpage ). QtQuick converts qml scripts to c ++ (just as javascript on a webpage does not need to be compiled and can be directly run ). In this way, you can directly modify the script to implement functions without compilation, which is convenient to use in embedded devices.
What are the differences between Qt Widget Based Application and Qt Quick Application?
I wonder if you have used html to write web pages.
Using qml to write Qt programs is the same as using html to write desktop applications. You do not need to consider browser support.
It's very interesting to catch your feet...
Writing with widgets is similar to traditional mfc ..