在现代图形用户界面(GUI)开发中,为用户提供一个直观的颜色选择工具是很常见的需求。本文将介绍一个与Direct2D一起工作的单文件库,它提供了一个现代的接口来选择颜色。
使用这个库非常简单,只需要一个函数调用。首先,需要包含头文件:
#include "colorpick.hpp"
然后,可以创建一个COLORPICK对象并初始化:
COLORPICK p;
D2D1_COLOR_F c1 = {1.0f, 0, 0, 1.0f}; // 以红色初始化
HRESULT hr = p.Show(0, c1);
if (hr == S_OK) {
// 颜色已设置
}
此外,还可以通过可选的结构体传递更多的选项:
struct COLORPICKOPT {
bool Alpha = true;
int Mode = 1;
float rsl = 0.1f;
bool Dlg = true;
bool LUpdate = false;
bool AlsoUseSystem = true;
bool UsePicker = true;
float Resolution = 0.1f;
};
库中包含了从RGB到HSL以及从HSL到RGB的转换函数。这些转换是通过fromRGBtoHSL
和fromHSLtoRGB
函数实现的。
所有的绘制都是通过ID2D1HwndRenderTarget
完成的,它将在WM_PAINT
消息中创建。根据使用的模式,它将:
以下是如何使用线性画刷绘制色调条的示例:
std::vector gst(360);
for (int i = 0; i < 360; i++) {
float hsl[3] = {1, 1, L};
hsl[0] = (360 - i) / 360.0f;
hsl[0] *= 6.0f;
float rgb[3] = {};
fromHSLtoRGB(hsl, rgb);
gst[i].position = i / 360.0f;
gst[i].color.r = rgb[0];
gst[i].color.g = rgb[1];
gst[i].color.b = rgb[2];
gst[i].color.a = 1.0f;
}
p->CreateGradientStopCollection(gst.data(), 360, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &pGradientStops);
p->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2D1::Point2F(LRect.left, LRect.top), D2D1::Point2F(LRect.right, LRect.bottom)), pGradientStops, &lbr);
处理WM_COMMAND
和WM_KEYDOWN
消息以处理IDOK/IDCANCEL和VK_RETURN/VK_ESCAPE,以提交或取消颜色选择。
点击Alpha值、RGB(在RGB模式下)或HSL(在HSL模式下)值会显示一个内联编辑框(带有ES_NUMBER),允许输入一个值(H为0-350,Alpha为0-100,其他为0-255)。当编辑处于活动状态时,VK_RETURN/VK_ESCAPE将作用于编辑值。
点击:
拖动:
轮动作:
对于习惯使用系统对话框的用户,按下"S"按钮将显示系统对话框并设置/获取选定的值。
很多时候,可能想要选择看到的颜色,但无法命名它。控件包括一个拾色器,可以点击它,然后在屏幕上(颜色选择器外部)拖动它,它会捕获它下面的任何颜色。它使用SetCapture API。
bool Alpha = true; // 默认情况下,颜色选择器还显示Alpha控件。如果不想更改Alpha,传递0。返回的颜色将具有1.0f的Alpha。
int Mode = 1; // 从RGB开始。如果为0,则从HSL开始。
bool Dlg = true; // 如果为0,则为窗口而不是对话框。
bool LUpdate = false; // 如果为1,则在设置L时更新颜色轮(较慢)
bool AlsoUseSystem = true; // 显示"S"按钮,允许使用系统公共控件
bool UsePicker = true; // 显示用于启用拾色器的十字
float Resolution = 0.1f; // 颜色轮的分辨率(较小的值->较慢的速度->更好的视图)