在很多情况,我们开发应用的时候经常会用到颜色选择器,大一的时候我做一个涂鸦软件的时候遇到的一个问题,就是如何在qt上做一个圆盘的
颜色选择器,这次做一个例子来让大家了解这种控件是怎么做的。
首先我们要理解颜色中的hsv的概念,大家可以直接百度hsn color 的颜色分布原理
首先给大家介绍hsv颜色选择器的原理:
看上图是qt文档中qcolor的帮助文档,我就是用这个类来实现颜色数据转换的,图中的点对应的是hsv中的h(Hue)的值,值范围为(0,360)整形,而且它的颜色区间对应着这个值如上图所示。很好,就这里我们能
联想到360刚好是一个颜色圆盘选择器的起点。
接下来我们要理解hsv中的s的值,如上图,我们看到不管圆盘的角度怎么样,大家发现越靠近中间颜色是不是越白?对,s的值就是这里的奥妙。s值是颜色的饱和度,它的值范围是0~255整形。通过这个我们应该大致知道颜色圆盘选择起是怎么实现了吧?
最后一步就是理解v值,v值的意思就是颜色的深度值,从上图我们就可以知道
好了基本的概念都有了,我们就可以在qt中做这个颜色圆盘选择器了!看下图效果:
对于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触点位置计算角度的算法,大家可以想更好的解决办法,我觉得这函数有点弄得复杂的,但是我也是第一次尝试,所以就懒得标记了。