如何更改启用主题的控件的字体颜色?

发布于 2024-08-23 21:32:28 字数 517 浏览 6 评论 0原文

是的,这又是这个问题:

如何在启用主题的应用程序上使用 Delphi7->Delphi2007 更改 TCheckBox(或任何已处理控件)的字体颜色?

在互联网和这个网站上阅读了大量内容后,我发现了 4 种答案:

  1. 最受欢迎(甚至来自 QC):你不能,它是微软设计的。
  2. 创建一个组件,让您可以按照自己的意愿进行绘制。
  3. 购买昂贵的组件集,绘制出您想要的效果。
  4. 不要使用主题。

好吧,但我对此仍然不满意。

在我看来,向用户提供有关表单上的属性/数据状态的彩色反馈似乎是合法的。

然后我刚刚安装了MSVC# 2008 Express版本,令人惊讶的是,他们可以改变字体的颜色(复选框的属性ForeColor)然后呢?

它似乎并不是“微软就是这样设计的”。那么现在又是一个问题:

如何在启用主题的应用程序上使用 Delphi 7 到 Delphi 2007 更改 TCheckBox(或任何已处理控件)的字体颜色?

Yes, this is again this question:

How can I change the font color of a TCheckBox (or any handled control) with Delphi7->Delphi2007 on a themes enabled application?

After reading a lot on the internet and on this site, I found 4 kinds of answer:

  1. and Most populare (even from QC): You can't, it's designed like that by Microsoft.
  2. Create a component that let you draw it like you want.
  3. Buy expensive component set that draws like you want.
  4. Do not use themes.

OK, but I am still unhappy with that.

Giving a user colored feedback for the status of a property/data he has on a form, seems legitimate to me.

Then I just installed the MSVC# 2008 Express edition, and what a surprise, they can change the color of the font (property ForeColor of the check box) Then what?

It does not seem to be a "it's designed like that, by Microsoft." then now the question again:

How can I change the font color of a TCheckBox (or any handled control) with Delphi 7 through Delphi 2007 on a theme-enabled application?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

燃情 2024-08-30 21:32:28

这需要一些调整才能成为完美的解决方案,但对我有用:

向您的复选框组件添加 2 个方法

    FOriginalCaption: string;
    _MySetCap: Boolean;
    procedure WMPaint(var msg: TWMPaint); message WM_PAINT;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;

并以这种方式实现:

procedure TMyCheckbox.CMTextChanged(var Message: TMessage);
begin
  inherited;
  if _MySetCap then Exit;
  FOriginalCaption := Caption;
end;

procedure TMyCheckbox.WMPaint(var msg: TWMPaint);
var
  BtnWidth: Integer;
  canv: TControlCanvas;
begin
  BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);

  _MySetCap := True;
  if not (csDesigning in ComponentState) then
    Caption := '';
  _MySetCap := False;
  inherited;
  canv := TControlCanvas.Create;
  try
    canv.Control := Self;
    canv.Font := Font;
    SetBkMode(canv.Handle, Ord(TRANSPARENT));
    canv.TextOut(BtnWidth + 1, 2, FOriginalCaption);
  finally
    canv.Free;
  end;
end;

This needs some tweak to be perfect solution but worked for me:

Add 2 method to your checkbox component

    FOriginalCaption: string;
    _MySetCap: Boolean;
    procedure WMPaint(var msg: TWMPaint); message WM_PAINT;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;

and implement this way:

procedure TMyCheckbox.CMTextChanged(var Message: TMessage);
begin
  inherited;
  if _MySetCap then Exit;
  FOriginalCaption := Caption;
end;

procedure TMyCheckbox.WMPaint(var msg: TWMPaint);
var
  BtnWidth: Integer;
  canv: TControlCanvas;
begin
  BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);

  _MySetCap := True;
  if not (csDesigning in ComponentState) then
    Caption := '';
  _MySetCap := False;
  inherited;
  canv := TControlCanvas.Create;
  try
    canv.Control := Self;
    canv.Font := Font;
    SetBkMode(canv.Handle, Ord(TRANSPARENT));
    canv.TextOut(BtnWidth + 1, 2, FOriginalCaption);
  finally
    canv.Free;
  end;
end;
厌倦 2024-08-30 21:32:28

哦,但是你可以!

只需将其放在表单声明之前即可:

TCheckBox = class(StdCtrls.TCheckBox)
public
  procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
end;

TCheckBox 的重新声明现在在运行时用作从表单的 DFM 流式传输的类型。现在实现如下消息:

procedure TCheckBox.CNCtlColorStatic(var Message: TWMCtlColorStatic);
begin
  SetTextColor(Message.ChildDC, ColorToRGB(clRed)); // or RGB(255,0,0));
  SetBkMode(Message.ChildDC, TRANSPARENT);
  Message.Result := GetStockObject(NULL_BRUSH);
end;

这将捕获 WM_CTLCOLORSTATIC 消息并将文本颜色更改为红色。这对我来说适用于非主题模式(使用 WinXP classic) - 但不适用于主题模式。

您应该知道,为了让主题控件向您发送此消息,控件应向主题绘制 API 提供 DTPB_USECTLCOLORSTATIC 标志。可悲的是,这不是默认行为,我也不知道该怎么做。看看 这个问题也是如此。

Oh, but you can!

Just place this before the declaration of your form :

TCheckBox = class(StdCtrls.TCheckBox)
public
  procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
end;

This re-declaration of TCheckBox is now used at runtime as the type streamed from your form's DFM. Now implement the message like this :

procedure TCheckBox.CNCtlColorStatic(var Message: TWMCtlColorStatic);
begin
  SetTextColor(Message.ChildDC, ColorToRGB(clRed)); // or RGB(255,0,0));
  SetBkMode(Message.ChildDC, TRANSPARENT);
  Message.Result := GetStockObject(NULL_BRUSH);
end;

This traps the WM_CTLCOLORSTATIC message and changes the text color to red. This works in non-themed mode for me (using WinXP classic) - but not in themed mode.

You should know that in order to let themed controls send you this message, the control should supply the DTPB_USECTLCOLORSTATIC flag to the Theme-drawing API's. Sadly, that's not default behaviour, and I don't know how to do it either. Look at this question too.

云醉月微眠 2024-08-30 21:32:28

以下是我在应用程序中解决此问题的方法:

  1. 从复选框中删除标题并将其变小 - 足够大以显示没有标题的实际复选框。
  2. 在复选框旁边放置一个 TLabel 作为标题。
  3. 在标签的 OnClick 事件中,切换复选框的状态。
  4. 如果标签具有 Alt+字母键盘快捷键,则使表单处理 CM_DIALOGCHAR 消息。从 TLabel 源代码复制消息处理程序并添加一行以切换复选框的状态。

它不是一个真正的复选框,而且比我想要的要多做一些工作,但它在我的应用程序中运行得足够好(它只有一个复选框需要这种处理)。

Here's how I solved this in my app:

  1. Remove the caption from the checkbox and make it smaller--just big enough to show the actual checkbox without the caption.
  2. Put a TLabel next to the checkbox to act as the caption.
  3. In the Label's OnClick event, toggle the state of the checkbox.
  4. If the label has an Alt+letter keyboard accelerator, make the form handle the CM_DIALOGCHAR message. Copy the message handler from the TLabel source code and add a line to toggle the state of the checkbox.

It's not a real checkbox, and it's a bit more work than I'd like, but it works well enough in my app (which has only one checkbox that needs this treatment).

爱已欠费 2024-08-30 21:32:28

选项 5. 使用您喜欢的控件作为基本选项,并覆盖控件中的所有绘画消息(是的,您可以将其称为组件,但控件是可见组件的名称,因此您应该使用它)。只需捕获 WM_PAINT,可能是 WM_NCPAINT,您就可以按照自己的风格绘制控件。至少您可以重用控件的整个功能。只要您不更改布局,只需更改点击测试的颜色即可。 注意:我有重写 TCustomEdit 以允许所有类型的颜色、背景文本、额外按钮等

的经验。我花了相当长的时间才把它弄好并阅读了 MSDn 和 KB 中的所有文档以确保控件做了我想要它做的事情。

Option 5. Use the control tyou like as a base option and override all the painting messages in the control (yes you can call it a component but control is the name for visible components so you should rather use that). Simply catch the WM_PAINT, possibly the WM_NCPAINT you can draw the control in your own style. At least you can reuse the whole functionality from the control. As long as you do not change the lay-out, only the colors you won't need to change the hittests mousedowns. up moves etc etc.

Note: I have the experience with overriding TCustomEdit to allow for all kind of colors, background text, extra buttons etc. It took quite some time to get it right and read all the documents from MSDn and KB to make sure the control did what I wanted it to do.

甩你一脸翔 2024-08-30 21:32:28

此代码是 @FLICKER 的改进代码,支持 BidiMode 和文本的正确位置:

interface
  TMSCheckBox = class(TCheckBox)
  private
    FOriginalCaption: string;
    _MySetCap: Boolean;
    procedure WMPaint (var Message: TWMPaint); message WM_PAINT;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  end;

implementation

procedure TMSCheckBox.CMTextChanged(var Message: TMessage);
begin
  inherited;
  if _MySetCap then Exit;
  FOriginalCaption := Caption;
end;

procedure TMSCheckBox.WMPaint(var Message: TWMPaint);
const
  SPACE   :Integer = 2;
var
  txtW, txtH, txtX,
  BtnWidth: Integer;
  canv: TControlCanvas;
begin
  BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);

  _MySetCap := True;
  if not (csDesigning in ComponentState) then
    Caption := '';
  _MySetCap := False;
  inherited;
  canv := TControlCanvas.Create;
  try
    canv.Control := Self;
    canv.Font := Font;
    txtW:= canv.TextWidth(FOriginalCaption);
    txtH:= canv.TextHeight(FOriginalCaption);
    if BiDiMode in [bdRightToLeft, bdRightToLeftReadingOnly] then
      txtX:= Width - BtnWidth - SPACE - txtW
    else
      txtX:= BtnWidth + SPACE;
    SetBkMode(canv.Handle, Ord(TRANSPARENT));
    canv.TextOut(txtX, (Height - txtH) div 2 + 1, FOriginalCaption);
  finally
    canv.Free;
  end;
end;

this code is improved code from @FLICKER than support BidiMode and the correct position of the text:

interface
  TMSCheckBox = class(TCheckBox)
  private
    FOriginalCaption: string;
    _MySetCap: Boolean;
    procedure WMPaint (var Message: TWMPaint); message WM_PAINT;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  end;

implementation

procedure TMSCheckBox.CMTextChanged(var Message: TMessage);
begin
  inherited;
  if _MySetCap then Exit;
  FOriginalCaption := Caption;
end;

procedure TMSCheckBox.WMPaint(var Message: TWMPaint);
const
  SPACE   :Integer = 2;
var
  txtW, txtH, txtX,
  BtnWidth: Integer;
  canv: TControlCanvas;
begin
  BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);

  _MySetCap := True;
  if not (csDesigning in ComponentState) then
    Caption := '';
  _MySetCap := False;
  inherited;
  canv := TControlCanvas.Create;
  try
    canv.Control := Self;
    canv.Font := Font;
    txtW:= canv.TextWidth(FOriginalCaption);
    txtH:= canv.TextHeight(FOriginalCaption);
    if BiDiMode in [bdRightToLeft, bdRightToLeftReadingOnly] then
      txtX:= Width - BtnWidth - SPACE - txtW
    else
      txtX:= BtnWidth + SPACE;
    SetBkMode(canv.Handle, Ord(TRANSPARENT));
    canv.TextOut(txtX, (Height - txtH) div 2 + 1, FOriginalCaption);
  finally
    canv.Free;
  end;
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文