在不少狀況,咱們開發應用的時候常常會用到顏色選擇器,大一的時候我作一個塗鴉軟件的時候遇到的一個問題,就是如何在qt上作一個圓盤的
顏色選擇器,此次作一個例子來讓你們瞭解這種控件是怎麼作的。
首先咱們要理解顏色中的hsv的概念,你們能夠直接百度hsn color 的顏色分佈原理
首先給你們介紹hsv顏色選擇器的原理:css
看上圖是qt文檔中qcolor的幫助文檔,我就是用這個類來實現顏色數據轉換的,圖中的點對應的是hsv中的h(Hue)的值,值範圍爲(0,360)整形,並且它的顏色區間對應着這個值如上圖所示。很好,就這裏咱們能
聯想到360恰好是一個顏色圓盤選擇器的起點。android
接下來咱們要理解hsv中的s的值,如上圖,咱們看到無論圓盤的角度怎麼樣,你們發現越靠近中間顏色是否是越白?對,s的值就是這裏的奧妙。s值是顏色的飽和度,它的值範圍是0~255整形。經過這個咱們應該大體知道顏色圓盤選擇起是怎麼實現了吧?c++
最後一步就是理解v值,v值的意思就是顏色的深度值,從上圖咱們就能夠知道
好了基本的概念都有了,咱們就能夠在qt中作這個顏色圓盤選擇器了!看下圖效果:算法
對於QColor這個類就不詳細介紹了,你們能夠本身在幫助文檔中參考參考,耐心半個小時就能活用這個類啦!
因爲在使用顏色選擇器的時候須要用到Hsv 轉換RGB,qt友好的幫咱們解決了這個麻煩的公式問題,就在qcolor中!
咱們先寫一個專門轉換顏色格式的類:
colortransformer.hide
#ifndef COLORTRANSFORMER_H #define COLORTRANSFORMER_H #include "jni.h" #include <QObject> #include <QColor> class ColorTransFormer: public QObject { Q_OBJECT public: ColorTransFormer(); ~ColorTransFormer(); Q_INVOKABLE void set_hsv(int h,int s,int v){ mcolor.setHsv(h,s,v); } Q_INVOKABLE int get_red(){ return mcolor.red(); } Q_INVOKABLE int get_blue(){ return mcolor.blue(); } Q_INVOKABLE int get_green(){ return mcolor.green(); } Q_INVOKABLE QColor get_rgb(){ return mcolor.toRgb(); } Q_INVOKABLE int get_h(){ return mcolor.hue(); } Q_INVOKABLE int get_s(){ return mcolor.saturation(); } Q_INVOKABLE void set_rgb(int r,int g,int b){ mcolor.setRgb(r,g,b); } private: QColor mcolor; }; #endif // COLORTRANSFORMER_H
colortransformer.cpp函數
#include "colortransformer.h" ColorTransFormer::ColorTransFormer() { } ColorTransFormer::~ColorTransFormer() { }
main.cppui
#include <QApplication> #include <QAndroidJniEnvironment> #include <QAndroidJniObject> #include <jni.h> #include <QDebug> #include <QFile> #include <QDir> #include <QDebug> #include <QQmlApplicationEngine> #include <QtQml> //qml object //#include "wifimanager.h" #include "colortransformer.h" //#include "mymediaplayer.h" //#include "datasbase.h" #include "playlist.h" #include "testandroidlib.h" //elian #include "C:\elian.h" //debug #include <QDebug> int main(int argc, char *argv[]) { QApplication a(argc, argv); //qmlRegisterType<WifiManager>("WifiManager",1,0,"MWifiManager"); qmlRegisterType<ColorTransFormer>("ColorTransFormer",1,0,"MColorTransFormer"); //qmlRegisterType<MyMediaPlayer>("MyMediaPlayer",1,0,"TomMediaPlayer"); //qmlRegisterType<DatasBase>("MDatabase",1,0,"MyDatabase"); //qmlRegisterType<PlayList>("MusicFileScanner",1,0,"MyMusicFileScanner"); //int proversion=0; // int libversion=0; //elianGetVersion(&proversion,&libversion); // TestAndroidLib aa; //for(int a=0;a<100;a++){ // aa.testPrint(); // } QQmlApplicationEngine engine; // qDebug()<<"elian test <<<<<<<"<<proversion<<","<<libversion; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return a.exec(); }
ColorPage.qmlspa
import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 import QtQuick 2.4 import ColorTransFormer 1.0 import QtGraphicalEffects 1.0 Rectangle { property var angle; property int pointx; property int pointy; property int red:255 property int blue:255 property int green:255 property int groupR:ma.width/2 property int lightness:100 property int cv:255 property int cs; property int ch; anchors.fill: parent MColorTransFormer{ id:color_hsv } function caculate_angle(){ var r=Math.sqrt((pointx*pointx+pointy*pointy)) if(pointx>=0&&pointy>=0){ angle=Math.asin(pointy/r) } if(pointx<0&&pointy>=0){ angle=Math.PI-Math.asin(pointy/r) } if(pointx<0&&pointy<0){ angle=Math.PI+Math.asin(Math.abs(pointy)/r) } if(pointx>=0&&pointy<0){ angle=2*Math.PI-Math.asin(Math.abs(pointy)/r) } caculate_h_s(r) } function caculatx(angle,r){ if(angle>=0&&angle<=Math.Pi/2){ return Math.cos(angle)*r } if(angle>Math.Pi/2&&angle<=Math.Pi){ return -Math.cos(Math.PI-angle)*r } if(angle>Math.Pi&&angle<=Math.Pi*3/2){ return -Math.cos(angle-Math.PI)*r } if(angle>Math.Pi*3/2&&angle<=Math.Pi*2){ return Math.cos(Math.PI*2-angle)*r } } function caculaty(angle,r){ if(angle>=0&&angle<=Math.Pi/2){ return Math.sin(angle)*r } if(angle>Math.Pi/2&&angle<=Math.Pi){ return Math.sin(Math.PI-angle)*r } if(angle>Math.Pi&&angle<=Math.Pi*3/2){ return -Math.sin(angle-Math.PI)*r } if(angle>Math.Pi*3/2&&angle<=Math.Pi*2){ return -Math.sin(Math.PI*2-angle)*r } } function caculate_h_s(r){ ch=Math.round(360*angle/(2*Math.PI)) cs=Math.round(255*(1-(groupR-r)/groupR)) color_hsv.set_hsv(ch,cs,cv) red=color_hsv.get_red() blue=color_hsv.get_blue() green=color_hsv.get_green() } function caculatAngleWithH(h){ return 2*Math.PI*h/360 } function caculatRWithS(s){ return 255*groupR/(510-s) } Rectangle{ id:testcolor width: colorimg.width+20 height: width radius: width/2 anchors.centerIn: colorimg color: Qt.rgba(red/255,green/255,blue/255,1.0) border.width: 1 border.color: "#666666" } //顏色選擇器件 Image { id: colorimg source: "../../imgRes/hsv_color_wheel.png" width: parent.width-80*mainWin.dentisty height: width anchors.horizontalCenter: parent.horizontalCenter y:10*mainWin.dentisty transform: Scale { origin.x: colorimg.width/2; origin.y: colorimg.width/2; xScale: -1} } MouseArea{ id:ma anchors.fill: colorimg Rectangle{ id:pointer width: 30 height: 30 color:"#00000000" x:parent.width/2-width/2 y:parent.width/2-width/2 Rectangle{ width: parent.width height: 1 anchors.centerIn: parent color: "#101010" } Rectangle{ width: 1 height: parent.height anchors.centerIn: parent color: "#101010" } } onPositionChanged: { pointx=ma.mouseX-ma.width/2 pointy=-(ma.mouseY-ma.width/2) caculate_angle() if(Math.sqrt((pointx*pointx+pointy*pointy))<=groupR){ pointer.x=pointx+ma.width/2-pointer.width/2 pointer.y=ma.width/2-pointy-pointer.width/2 // console.log("r1:"+Math.sqrt((pointx*pointx+pointy*pointy))+" r2:"+groupR) } } onPressed: { pointx=ma.mouseX-ma.width/2 pointy=-(ma.mouseY-ma.width/2) caculate_angle() if(Math.sqrt((pointx*pointx+pointy*pointy))<=groupR){ pointer.x=pointx+ma.width/2-pointer.width/2 pointer.y=ma.width/2-pointy-pointer.width/2 // console.log("r1:"+Math.sqrt((pointx*pointx+pointy*pointy))+" r2:"+groupR) } } onPressAndHold: { pointx=ma.mouseX-ma.width/2 pointy=-(ma.mouseY-ma.width/2) caculate_angle() if(Math.sqrt((pointx*pointx+pointy*pointy))<=groupR){ pointer.x=pointx+ma.width/2-pointer.width/2 pointer.y=ma.width/2-pointy-pointer.width/2 // console.log("r1:"+Math.sqrt((pointx*pointx+pointy*pointy))+" r2:"+groupR) } } } //亮度設置 Slider{ id:lightnessSetting width: parent.width-60*mainWin.dentisty height: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4) anchors.horizontalCenter: parent.horizontalCenter anchors.top:colorimg.bottom anchors.topMargin: 15*mainWin.dentisty value: 100 onValueChanged: lightness=value stepSize:1 maximumValue: 100 minimumValue: 0 style: SliderStyle { groove: Rectangle { width: lightnessSetting.width height: lightnessSetting.height color: "gray" radius: height/2 Rectangle{ width: Math.round((parent.width-parent.height)*lightnessSetting.value/100)+parent.height height: parent.height color: "#12aadf" radius: height/2 } Text { id: lightnessText text: qsTr("燈光亮度:")+lightness font.pixelSize: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4)-5*mainWin.dentisty color:"#efefef" anchors.centerIn: parent } } handle: Rectangle { anchors.centerIn: parent color: control.pressed ? "white" : "lightgray" border.color: "gray" border.width: 2 width: height height: lightnessSetting.height radius: height/2 } } } //三色調整條 Slider{ id:redSlider width: parent.width-60*mainWin.dentisty height: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4) anchors.horizontalCenter: parent.horizontalCenter anchors.top:lightnessSetting.bottom anchors.topMargin: 15*mainWin.dentisty value: 255 onValueChanged: { red=value } stepSize:1 maximumValue: 255 minimumValue: 0 style: SliderStyle { groove: Rectangle { width: lightnessSetting.width height: redSlider.height color: "gray" radius: height/2 border.width:1 border.color: "#222222" Rectangle{ width: Math.round((parent.width-parent.height)*redSlider.value/255)+parent.height height: parent.height color: "#ff0000" border.width:1 border.color: "#222222" radius: height/2 } Text { text: qsTr("Red"+red) color: "#efefef" anchors.centerIn: parent font.pixelSize: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4)-5*mainWin.dentisty } } handle: Rectangle { anchors.centerIn: parent color: control.pressed ? "white" : "lightgray" border.color: "gray" border.width: 2 width: height height: redSlider.height radius: height/2 } } } Slider{ id:greenSlider width: parent.width-60*mainWin.dentisty height: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4) anchors.horizontalCenter: parent.horizontalCenter anchors.top:redSlider.bottom anchors.topMargin: 15*mainWin.dentisty value: 255 onValueChanged: { green=value } stepSize:1 maximumValue: 255 minimumValue: 0 style: SliderStyle { groove: Rectangle { width: lightnessSetting.width height: greenSlider.height color: "gray" radius: height/2 border.width:1 border.color: "#222222" Rectangle{ width: Math.round((parent.width-parent.height)*greenSlider.value/255)+parent.height height: parent.height color: "#00ff00" border.width:1 border.color: "#222222" radius: height/2 } Text { text: qsTr("Green"+green) color: "#efefef" anchors.centerIn: parent font.pixelSize: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4)-5*mainWin.dentisty } } handle: Rectangle { anchors.centerIn: parent color: control.pressed ? "white" : "lightgray" border.color: "gray" border.width: 2 width: height height: greenSlider.height radius: height/2 } } } Slider{ id:blueSlider width: parent.width-60*mainWin.dentisty height: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4) anchors.horizontalCenter: parent.horizontalCenter anchors.top:greenSlider.bottom anchors.topMargin: 15*mainWin.dentisty value: 255 onValueChanged: blue=value stepSize:1 maximumValue: 255 minimumValue: 0 style: SliderStyle { groove: Rectangle { width: lightnessSetting.width height: blueSlider.height color: "gray" radius: height/2 border.width:1 border.color: "#222222" Rectangle{ width: Math.round((parent.width-parent.height)*blueSlider.value/255)+parent.height height: parent.height color: "#0000ff" border.width:1 border.color: "#222222" radius: height/2 } Text { text: qsTr("Blue"+blue) color: "#efefef" anchors.centerIn: parent font.pixelSize: ((parent.height-(colorimg.y+colorimg.height)-(15*5)*mainWin.dentisty)/4)-5*mainWin.dentisty } } handle: Rectangle { anchors.centerIn: parent color: control.pressed ? "white" : "lightgray" border.color: "gray" border.width: 2 width: height height: blueSlider.height radius: height/2 } } } onRedChanged: { redSlider.value=red color_hsv.set_rgb(red,green,blue) ch=color_hsv.get_h(); cs=color_hsv.get_s(); pointer.x=Math.round(caculatx(caculatAngleWithH(ch),caculatRWithS(cs))) pointer.y=Math.round(caculaty(caculatAngleWithH(ch),caculatRWithS(cs))) } onBlueChanged: { blueSlider.value=blue color_hsv.set_rgb(red,green,blue) ch=color_hsv.get_h(); cs=color_hsv.get_s(); pointer.x=Math.round(caculatx(caculatAngleWithH(ch),caculatRWithS(cs))) pointer.y=Math.round(caculaty(caculatAngleWithH(ch),caculatRWithS(cs))) } onGreenChanged: { greenSlider.value=green color_hsv.set_rgb(red,green,blue) ch=color_hsv.get_h(); cs=color_hsv.get_s(); pointer.x=Math.round(caculatx(caculatAngleWithH(ch),caculatRWithS(cs))) pointer.y=Math.round(caculaty(caculatAngleWithH(ch),caculatRWithS(cs))) } }
好,代碼就提供參考,注意colorpage.qml那裏的那些函數轉換,這只是我本身解決mousearea觸點位置計算角度的算法,你們能夠想更好的解決辦法,我以爲這函數有點弄得複雜的,可是我也是第一次嘗試,因此就懶得標記了。debug