qt android 开发篇之如何实现圆盘(hsv)颜色选择器

在很多情况,我们开发应用的时候经常会用到颜色选择器,大一的时候我做一个涂鸦软件的时候遇到的一个问题,就是如何在qt上做一个圆盘的
颜色选择器,这次做一个例子来让大家了解这种控件是怎么做的。
首先我们要理解颜色中的hsv的概念,大家可以直接百度hsn color 的颜色分布原理
首先给大家介绍hsv颜色选择器的原理:

qt android 开发篇之如何实现圆盘(hsv)颜色选择器_第1张图片
看上图是qt文档中qcolor的帮助文档,我就是用这个类来实现颜色数据转换的,图中的点对应的是hsv中的h(Hue)的值,值范围为(0,360)整形,而且它的颜色区间对应着这个值如上图所示。很好,就这里我们能
联想到360刚好是一个颜色圆盘选择器的起点。

qt android 开发篇之如何实现圆盘(hsv)颜色选择器_第2张图片

接下来我们要理解hsv中的s的值,如上图,我们看到不管圆盘的角度怎么样,大家发现越靠近中间颜色是不是越白?对,s的值就是这里的奥妙。s值是颜色的饱和度,它的值范围是0~255整形。通过这个我们应该大致知道颜色圆盘选择起是怎么实现了吧?

clipboard.png
最后一步就是理解v值,v值的意思就是颜色的深度值,从上图我们就可以知道
好了基本的概念都有了,我们就可以在qt中做这个颜色圆盘选择器了!看下图效果:

qt android 开发篇之如何实现圆盘(hsv)颜色选择器_第3张图片
qt android 开发篇之如何实现圆盘(hsv)颜色选择器_第4张图片

对于QColor这个类就不详细介绍了,大家可以自己在帮助文档中参考参考,耐心半个小时就能活用这个类啦!
由于在使用颜色选择器的时候需要用到Hsv 转换RGB,qt友好的帮我们解决了这个麻烦的公式问题,就在qcolor中!
我们先写一个专门转换颜色格式的类:
colortransformer.h

#ifndef COLORTRANSFORMER_H
#define COLORTRANSFORMER_H
#include "jni.h"

#include 

#include 

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.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//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 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //qmlRegisterType("WifiManager",1,0,"MWifiManager");
    qmlRegisterType("ColorTransFormer",1,0,"MColorTransFormer");
    //qmlRegisterType("MyMediaPlayer",1,0,"TomMediaPlayer");
    //qmlRegisterType("MDatabase",1,0,"MyDatabase");
    //qmlRegisterType("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 <<<<<<<"<

ColorPage.qml

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触点位置计算角度的算法,大家可以想更好的解决办法,我觉得这函数有点弄得复杂的,但是我也是第一次尝试,所以就懒得标记了。

你可能感兴趣的:(qml,qt5)