1. 程式人生 > >基於qml創建最簡單的圖像處理程序(1)-基於qml創建界面

基於qml創建最簡單的圖像處理程序(1)-基於qml創建界面

cep font mes quit vid www 習慣 image ble

為什麽使用QT,包括進一步使用QML?兩個主要原因,一是因為我是一個c++程序員,有語言使用慣性;二是我主要做圖像處理方面工作,使用什麽平臺對於我來說不重要,我只需要在不同平臺上面能夠運行我的圖像處理程序(而主要是和OpenCV有關系的)。所以選擇QT,它能夠在win/linux/android,包括PI上面都提供不錯的GUI支持;而如果我想在Android上編寫圖像處理程序,又主要遇到兩個問題,一是相機的獲取。OpenCV的videocapture在Android上支持不好,在最新版本的OpenCV裏面已經把這個部分相關內容去掉了,同時QCamera(基於widget的camera)支持也不好,Qml是目前對Android支持最好的。這個地方QML提供的camera功能就類似windows中的dshow一樣,是一個基礎類庫;二是界面的創建,在windows下面,基於ribbon等,我能夠創建還說的過去的界面,但是在Android中,目前沒有很好的工具。特別是在手機這個小小界面中,如果界面有問很影響使用。

我需要的是一個界面說的過去(有官方控件),對相機支持好,能夠支持各種平臺的這麽一個工具,不求最好,但是要能用。在不多的選擇中,QML(qtquick)是最合適的。當然如果要掌握QML也要跨越一些學習曲線,但是付出是值得的。 本文中參考了一些資料(主要是《qtquick核心編程》),我們基於qml創建最簡單的圖像處理程序。兩個主要內容,一個是直接使用qml自己的能力進行圖像處理;二個是引用並且使用OpenCV。只求實現主要功能,很多細節還需打磨,但我相信瑕不掩瑜。 新建工程,最新默認的界面main.qml代碼為 import QtQuick 2.9

import QtQuick.Window 2.2

Window {
visible: true
width: 640
height: 480
}
我就直接在這個QML上進行修改 import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Controls.Styles 1.1
Window {
visible: true
width: 640
height: 480
//RGB
color: "#0000FF";

//忙等控件,包含在QtQuick.Controls中

BusyIndicator {
id: busy;
running: false;
anchors.centerIn: parent;
z: 2;
}
//狀態顯示Label
Label {
id: stateLabel;
visible: false;
anchors.centerIn: parent;
}
//主要界面
Image {
objectName: "imageViewer";
id: imageViewer;
asynchronous: true;
anchors.fill: parent;
fillMode: Image.PreserveAspectFit;
//根據imageviewer狀態判斷,控制控件表現出不同狀態
onStatusChanged: {
if (imageViewer.status === Image.Loading) {
busy.running = true;
stateLabel.visible = false;
}
else if(imageViewer.status === Image.Ready){
busy.running = false;
}
else if(imageViewer.status === Image.Error){
busy.running = false;
stateLabel.visible = true;
stateLabel.text = "ERROR";
}
}
}

//打開文件界面,包含在 QtQuick.Dialogs 中。固然在Android中使用這個方法打開圖片不是最佳方法,但是可用方法
FileDialog {
id: fileDialog;
title: "Please choose a file";
nameFilters: ["Image Files (*.jpg *.png *.gif)"];
onAccepted: {
console.log(fileDialog.fileUrl);
imageViewer.source = fileDialog.fileUrl;
}
}

//以下用於創建button,其中ButtonStyle來自QtQuick.Controls.Styles
//其中所謂Component就是可重用構建的意思,這個用於Button的Componet是可以復用的
Component{
id: btnStyle;
ButtonStyle {
background: Rectangle {
implicitWidth: 140;
implicitHeight: 50;
border.width: control.pressed ? 2 : 1;
border.color: (control.pressed || control.hovered) ? "#00A060" : "#888888";
radius: 12;
gradient: Gradient {
GradientStop { position: 0 ; color: control.pressed ? "#cccccc" : "#e0e0e0"; }
GradientStop { position: 1 ; color: control.pressed ? "#aaa" : "#ccc"; }
}
}
}
}
//就是做了個黑色的框子,用於放button的
Rectangle {
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: openFile.bottom;
anchors.bottomMargin: -6;
anchors.right: quit.right;
anchors.rightMargin: -6;
color: "#404040";
opacity: 0.7;
}

//打開按鈕
Button {
id: openFile;
text: "打開";
anchors.left: parent.left;
anchors.leftMargin: 6;
anchors.top: parent.top;
anchors.topMargin: 6;
onClicked: {
fileDialog.visible = true;
}
//直接使用了btnStyle
style: btnStyle;
z: 1;
}
//退出就是退出
Button {
id: quit;
text: "退出";
anchors.left: openFile.right;
anchors.leftMargin: 4;
anchors.bottom: openFile.bottom;
onClicked: {
Qt.quit()
}
style: btnStyle;
z: 1;
}

//另外一個黑色框子,註意用到了op,也就是上面的4個按鈕

Rectangle {
anchors.left: parent.left;
anchors.top: op.top;
anchors.topMargin: -4;
anchors.bottom: parent.bottom;
anchors.right: op.right;
anchors.rightMargin: -4;
color: "#404040";
opacity: 0.7;
}

//以另一種方式將幾個按鈕連在一起
//我們實現4個比較簡單的效果
Grid {
id: op;
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
rows: 2;
columns: 2;
rowSpacing: 4;
columnSpacing: 4;
z: 1;
//柔化效果
Button {
text: "柔化";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Soften);
}
}
//灰度效果
Button {
text: "灰度";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Gray);
}
}
//浮雕效果
Button {
text: "浮雕";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Emboss);
}
}
//黑白效果
Button {
text: "黑白";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Binarize);
}
}
}

} 雖然代碼代碼看上去有點多,但是好在還算有結構。 1、頭文件,不多說。用在哪裏的看註釋; 2、全部的界面都包含在Windos{}中的 Window {
visible: true
width: 640
height: 480
//RGB
color: "#0000FF";
…… 在這段代碼中width和height已經沒有什麽實際價值了。需要註意的是color為背景色,而qml是按照RGB來定義的。 3、控件控件,全部都是控件的定義。我們使用QML就要習慣直接使用代碼定義的方式精確地進行界面定位,包含以下:
//忙等控件,包含在QtQuick.Controls中
BusyIndicator {
id: busy;
running: false;
anchors.centerIn: parent;
z: 2;
}
//狀態顯示Label
Label {
id: stateLabel;
visible: false;
anchors.centerIn: parent;
}
//主要圖片顯示
Image {
objectName: "imageViewer";
id: imageViewer;
asynchronous: true;
anchors.fill: parent;
fillMode: Image.PreserveAspectFit;
//根據imageviewer狀態判斷,控制控件表現出不同狀態
onStatusChanged: {
if (imageViewer.status === Image.Loading) {
busy.running = true;
stateLabel.visible = false;
}
else if(imageViewer.status === Image.Ready){
busy.running = false;
}
else if(imageViewer.status === Image.Error){
busy.running = false;
stateLabel.visible = true;
stateLabel.text = "ERROR";
}
}
}
//打開文件界面,包含在 QtQuick.Dialogs 中。固然在Android中使用這個方法打開圖片不是最佳方法,但是可用方法
FileDialog {
id: fileDialog;
title: "Please choose a file";
nameFilters: ["Image Files (*.jpg *.png *.gif)"];
onAccepted: {
console.log(fileDialog.fileUrl);
imageViewer.source = fileDialog.fileUrl;
}
} 4、按鈕控件,但是使用了一些可重用思想
//以下用於創建button,其中ButtonStyle來自QtQuick.Controls.Styles
//其中所謂Component就是可重用構建的意思,這個用於Button的Componet是可以復用的
Component{
id: btnStyle;
ButtonStyle {
background: Rectangle {
implicitWidth: 140;
implicitHeight: 50;
border.width: control.pressed ? 2 : 1;
border.color: (control.pressed || control.hovered) ? "#00A060" : "#888888";
radius: 12;
gradient: Gradient {
GradientStop { position: 0 ; color: control.pressed ? "#cccccc" : "#e0e0e0"; }
GradientStop { position: 1 ; color: control.pressed ? "#aaa" : "#ccc"; }
}
}
}
}


//打開按鈕
Button {
id: openFile;
text: "打開";
anchors.left: parent.left;
anchors.leftMargin: 6;
anchors.top: parent.top;
anchors.topMargin: 6;
onClicked: {
fileDialog.visible = true;
}
//直接使用了btnStyle
style: btnStyle;
z: 1;
}
//退出就是退出
Button {
id: quit;
text: "退出";
anchors.left: openFile.right;
anchors.leftMargin: 4;
anchors.bottom: openFile.bottom;
onClicked: {
Qt.quit()
}
style: btnStyle;
z: 1;
} 5、將按鈕放在一起,我們使用grid //以另一種方式將幾個按鈕連在一起
//我們實現4個比較簡單的效果
Grid {
id: op;
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
rows: 2;
columns: 2;
rowSpacing: 4;
columnSpacing: 4;
z: 1;
//柔化效果
Button {
text: "柔化";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Soften);
}
}
//灰度效果
Button {
text: "灰度";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Gray);
}
}
//浮雕效果
Button {
text: "浮雕";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Emboss);
}
}
//黑白效果
Button {
text: "黑白";
style: btnStyle;
onClicked: {
//busy.running = true;
//processor.process(fileDialog.fileUrl, ImageProcessor.Binarize);
}
}
}


6、兩個黑色框子,沒有其它用途,就是美觀 //就是做了個黑色的框子,用於放button的
Rectangle {
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: openFile.bottom;
anchors.bottomMargin: -6;
anchors.right: quit.right;
anchors.rightMargin: -6;
color: "#404040";
opacity: 0.7;
} //另外一個黑色框子,註意用到了op,也就是上面的4個按鈕
Rectangle {
anchors.left: parent.left;
anchors.top: op.top;
anchors.topMargin: -4;
anchors.bottom: parent.bottom;
anchors.right: op.right;
anchors.rightMargin: -4;
color: "#404040";
opacity: 0.7;
} 這個時候已經有以下界面,能夠打開顯示圖片了 技術分享圖片 打開圖片,顯示圖片 技術分享圖片技術分享圖片 到這個部分請查看 階段代碼1



來自為知筆記(Wiz)



附件列表

基於qml創建最簡單的圖像處理程序(1)-基於qml創建界面