qt android 開發篇之如何實現圓盤(hsv)顏色選擇器

在不少狀況,咱們開發應用的時候常常會用到顏色選擇器,大一的時候我作一個塗鴉軟件的時候遇到的一個問題,就是如何在qt上作一個圓盤的
顏色選擇器,此次作一個例子來讓你們瞭解這種控件是怎麼作的。
首先咱們要理解顏色中的hsv的概念,你們能夠直接百度hsn color 的顏色分佈原理
首先給你們介紹hsv顏色選擇器的原理:css

clipboard.png
看上圖是qt文檔中qcolor的幫助文檔,我就是用這個類來實現顏色數據轉換的,圖中的點對應的是hsv中的h(Hue)的值,值範圍爲(0,360)整形,並且它的顏色區間對應着這個值如上圖所示。很好,就這裏咱們能
聯想到360恰好是一個顏色圓盤選擇器的起點。android

clipboard.png

接下來咱們要理解hsv中的s的值,如上圖,咱們看到無論圓盤的角度怎麼樣,你們發現越靠近中間顏色是否是越白?對,s的值就是這裏的奧妙。s值是顏色的飽和度,它的值範圍是0~255整形。經過這個咱們應該大體知道顏色圓盤選擇起是怎麼實現了吧?c++

clipboard.png
最後一步就是理解v值,v值的意思就是顏色的深度值,從上圖咱們就能夠知道
好了基本的概念都有了,咱們就能夠在qt中作這個顏色圓盤選擇器了!看下圖效果:算法

clipboard.png
clipboard.png

對於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

相關文章
相關標籤/搜索