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

时间:2010-03-01 14:28:08

标签: delphi themes

是的,这也是这个问题:

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

在网上和本网站上阅读了很多内容后,我找到了4种答案:

  1. 和大多数人(甚至来自QC):你不能,它的设计就像微软那样。
  2. 创建一个组件,让您可以按照自己的意愿绘制它。
  3. 购买可以随意绘制的昂贵组件集。
  4. 不要使用主题。
  5. 好的,但我仍然不满意。

    向用户提供有关他在表单上拥有的财产/数据状态的彩色反馈,对我来说似乎是合法的。

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

    似乎并不是“微软这样设计的”。那么现在又回答了问题:

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

5 个答案:

答案 0 :(得分:4)

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

将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;

答案 1 :(得分:2)

哦,但你可以!

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

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经典版) - 但不适用于主题模式。

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

答案 2 :(得分:1)

以下是我在我的应用中解决这个问题的方法:

  1. 从复选框中删除标题并将其缩小 - 只要大到足以显示没有标题的实际复选框。
  2. 在复选框旁边放置一个TLabel作为标题。
  3. 在Label的OnClick事件中,切换复选框的状态。
  4. 如果标签有Alt +字母键盘加速器,请使表单处理CM_DIALOGCHAR消息。从TLabel源代码复制消息处理程序,并添加一行以切换复选框的状态。
  5. 这不是一个真正的复选框,它比我想要的工作多一点,但它在我的应用程序中运行得很好(它只有一个需要这种处理的复选框)。

答案 3 :(得分:0)

选项5.使用控件tyou作为基本选项并覆盖控件中的所有绘制消息(是的,您可以将其称为组件,但控件是可见组件的名称,因此您应该使用它)。只需捕获WM_PAINT,可能是WM_NCPAINT,您可以按照自己的风格绘制控件。至少你可以重用控件的整个功能。只要你不改变布局,只有你不需要改变命中测试的颜色。向上移动等等。

注意:我有覆盖TCustomEdit的经验,允许所有类型的颜色,背景文本,额外的按钮等。它需要相当长的时间才能正确读取MSDn和KB中的所有文档以确保控件做了我想做的事。

答案 4 :(得分:0)

此代码是@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;