如何在Delphi的TColorDialog中避免自定义颜色与基础颜色重复
如何在Delphi的TColorDialog中避免自定义颜色与基础颜色重复
我之前做Delphi项目时也碰到过这个头疼的问题——TColorDialog完全不会管你加的自定义颜色是不是和左边的基础色重复,而且还没给我们直接获取基础色列表的接口。不过别慌,我整理了两种解决方案,从简单到进阶都有,看你需要哪种:
一、代码预添加自定义色时的校验(基础方案)
大多数场景下,我们是在代码里预先往对话框的自定义颜色列表里加颜色,这种情况用简单的预定义校验就搞定了。
首先,Windows原生颜色对话框的基础色是固定的16种,我们直接把它们列成常量数组:
const cStandardBasicColors: array[0..15] of TColor = ( clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite );
接着写个小工具函数,用来判断某个颜色是否属于基础色:
function ColorIsBasic(const AColor: TColor): Boolean; var I: Integer; begin Result := False; for I := Low(cStandardBasicColors) to High(cStandardBasicColors) do begin if AColor = cStandardBasicColors[I] then begin Result := True; Exit; end; end; end;
之后添加自定义颜色时,先过一遍这个校验,只有非基础色才加入列表:
procedure AddUniqueCustomColor(ADialog: TColorDialog; AColor: TColor); var ColorHex: string; begin if not ColorIsBasic(AColor) then begin // 把TColor转换成CustomColors要求的RRGGBB格式十六进制字符串 ColorHex := IntToHex(GetRValue(AColor), 2) + IntToHex(GetGValue(AColor), 2) + IntToHex(GetBValue(AColor), 2); ADialog.CustomColors.Add(ColorHex); end; end;
举个实际使用的例子:
with TColorDialog.Create(nil) do try // 尝试添加一个颜色,重复的话会自动跳过 AddUniqueCustomColor(Self, clSkyBlue); if Execute then Form1.Color := Color; // 这里替换成你的颜色处理逻辑 finally Free; end;
二、拦截用户手动添加的重复色(进阶方案)
如果要防住用户在对话框里手动选一个基础色,然后点击「添加到自定义颜色」的操作,就得用Windows钩子来拦截对话框的内部操作了,步骤稍微复杂一点:
- 先声明钩子相关的变量和处理函数:
type TColorDialogHookData = record BasicColors: array[0..15] of TColor; end; var ColorDialogHook: HHOOK; HookData: TColorDialogHookData; function ColorDialogProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var CC: PChooseColor; ColorToAdd: TColor; begin if nCode = HC_ACTION then begin CC := PChooseColor(lParam); // 捕捉添加自定义颜色的操作 if (CC^.Flags and CC_RGBINIT <> 0) and (wParam = BN_CLICKED) then begin ColorToAdd := ColorToRGB(CC^.rgbResult); if ColorIsBasic(ColorToAdd) then begin // 阻止添加操作,这里还可以加个提示框提醒用户 ShowMessage('这个颜色已经在基础颜色面板里啦!'); Result := 1; Exit; end; end; end; Result := CallNextHookEx(ColorDialogHook, nCode, wParam, lParam); end;
- 给TColorDialog的OnShow事件绑定处理逻辑,用来初始化钩子:
procedure TForm1.ColorDialog1Show(Sender: TObject); begin // 把基础色列表传入钩子数据 Move(cStandardBasicColors, HookData.BasicColors, SizeOf(HookData.BasicColors)); // 给当前线程设置CBT钩子,拦截颜色对话框的操作 ColorDialogHook := SetWindowsHookEx(WH_CBT, @ColorDialogProc, 0, GetCurrentThreadId); end;
- 最后在对话框关闭时记得释放钩子,避免内存泄漏:
procedure TForm1.ColorDialog1Close(Sender: TObject); begin if ColorDialogHook <> 0 then begin UnhookWindowsHookEx(ColorDialogHook); ColorDialogHook := 0; end; end;
这样用户在对话框里手动加重复色的操作就会被拦截,还能收到提示。
备注:内容来源于stack exchange,提问作者Veit Zimmermann
相关产品推荐
相关产品推荐

