新定义的Hint中字体的颜色为什么不能改变?(50分)

  • 主题发起人 主题发起人 j5203
  • 开始时间 开始时间
J

j5203

Unregistered / Unconfirmed
GUEST, unregistred user!
我写了一个改变Hint的控件,但是Hint中字的颜色却始终是初始值,无法改变,请问大家这是为什么?
以下是我写的代码。

unit coolhint;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TMyHintWindow = class(THintWindow)
private
FRegion: THandle;
FColor: TColor; //Hint中字体的颜色
procedure FreeCurrentRegion;
{ Private declarations }
public
procedure ActivateHint(Rect: TRect; const AHint: string);override;
procedure Paint;override;
procedure Createparams(var Params: TCreateParams);override;
constructor Create(AOwner: TComponent);override ;
destructor Destroy; override;
{ Public declarations }

published

end;

type
Tp = class(Tcomponent)
private
FMyHintWindow: TMyHintWindow;
FEnabled: Boolean;
procedure ChangHint(Enabled: Boolean);
procedure SetEnabled(const Value: Boolean);
function GetColor: TColor;
procedure SetColor(const Value: TColor);//改变Hint字体的颜色
protected
procedure Loaded;override;
public
constructor Create(AOwner: TComponent);override ;
destructor Destroy; override;
published
property Enabled: Boolean read FEnabled write SetEnabled;
property Color: TColor read GetColor write SetColor;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Ke', [Tp]);
end;


{ TMyHintWindow }

procedure TMyHintWindow.ActivateHint(Rect: TRect; const AHint: string);
begin
with Rect do
Right := Right + Canvas.TextWidth('wwww');
BoundsRect := Rect;
FreeCurrentRegion;
with BoundsRect do
Fregion := CreateRoundRectRgn(0,0,width,height,width,height);
if FRegion <> 0 then
SetWindowRgn(Handle, FRegion, True);
inherited;
end;

constructor TMyHintWindow.Create(AOwner: TComponent);
begin
inherited;
FColor := clRed;
end;

procedure TMyHintWindow.createparams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style and not ws_Border;
end;

destructor TMyHintWindow.Destroy;
begin
FreeCurrentRegion;
inherited;
end;

procedure TMyHintWindow.FreeCurrentRegion;
begin
if FRegion <> 0 then
begin
SetWindowRgn(Handle, 0, True);
DeleteObject(FRegion);
FRegion := 0;
end;
end;

procedure TMyHintWindow.paint;
var
R: TRect;
begin
r := ClientRect;
Inc(R.left,1);
Canvas.Font.Color:= FColor;
DrawText(Canvas.Handle,Pchar(Caption),Length(Caption),R,
DT_NOPREFIX OR DT_WORDBREAK OR DT_CENTER OR DT_VCENTER);
end;

{ Tp }

destructor Tp.Destroy;
begin
FMyHintWindow.Free;
inherited;
end;

procedure Tp.SetEnabled(const Value: Boolean);
begin
if Value<>FEnabled then
begin
FEnabled := Value;
changHint(FEnabled);
end;
end;

procedure Tp.Loaded;
begin
inherited;
changHint(FEnabled);
end;

procedure Tp.ChangHint(Enabled: Boolean);
begin
if not (csDesigning in ComponentState) then
if Enabled then
begin
Application.ShowHint := False;
HintWindowClass := TMyHintWindow;
Application.ShowHint := True;
end
else
begin
Application.ShowHint := False;
HintWindowClass := THintWindow;
Application.ShowHint := True;
end;
end;

constructor Tp.Create(AOwner: TComponent);
begin
inherited;
FMyHintWindow := TMyHintWindow.Create(self);
end;

function Tp.GetColor: TColor;
begin
Result := FMyHintWindow.FColor;
end;

procedure Tp.SetColor(const Value: TColor);
begin
FMyHintWindow.FColor := Value;
end;

end.
 
呵呵,试了一下。开始的时候也是什么改也不对,后来跟踪发现:
TMyHintWindow.Create被调用了两遍:
第一次是在
FMyHintWindow的Create过程中:
代码:
constructor Tp.Create(AOwner: TComponent);
begin
  inherited;
  FMyHintWindow := TMyHintWindow.Create(self);
end;
呵呵,这次很正常,没问题
第二次就怪了:
代码:
procedure Tp.ChangHint(Enabled: Boolean);
begin
  if not (csDesigning in ComponentState) then
    if Enabled then
    begin
      Application.ShowHint := False;
      HintWindowClass := TMyHintWindow;
  ...
居然在这里!
再一看HintWindowClass的说明与相关的源码,问题果然在这里:
在Delphi的帮助中有这样一句话:
Applications can customize this window by creating a descendant
of THintWindow and assigning it to the HintWindowClass variable at
application startup.
HintWindowClass在这里传入的其实是类名!再看:
代码:
procedure TApplication.SetShowHint(Value: Boolean);
begin
  if FShowHint <> Value then
  begin
    FShowHint := Value;
    if FShowHint then
    begin
      FHintWindow := HintWindowClass.Create(Self);//问题就在这里!
...
也就是说,在改变HintWindowClass后Application对象又自己建立了一个
TMyHintWindow。这样,你所做的改变都是针对自己的FMyHintWindow,而
系统真正用的是Application自己建的那个,你的改变当然没有用了!
找到了问题的所在就好办了!我想了一下有两个办法:
1、改FHintWindow的指针,将它指到TP对象的FMyHintWindow上!
2、改TP对象与TMyHintWindow对象的封装,使它们能共享一个Color对象!
第一种方法我试了一下,没有成功(呵呵,水平有限,还得再想想)。
第二种方法成功了。

1、删除TP对象中所有关于FMyHintWindow的东西(反正没有用了嘛)!
2、删除TMyHintWindow对象中的FColor的所有东西
3、在单元中增加一个PColor:TColor的变量
代码:
  var PColor:TColor;
implementation
procedure Register
4、改TMyHintWindow的OnPaint事件:
代码:
procedure TMyHintWindow.paint;
var
  R: TRect;
begin
  r := ClientRect;
  Inc(R.left,1);
  Canvas.Font.Color:= PColor;//这里,由FColor改为PColor
  DrawText(Canvas.Handle,Pchar(Caption),Length(Caption),R,
           DT_NOPREFIX OR DT_WORDBREAK OR DT_CENTER OR DT_VCENTER);
end;
5、改TP对象的SetColor和GetColor函数
代码:
function Tp.GetColor: TColor;
begin
  Result := PColor;
end;
procedure Tp.SetColor(const Value: TColor);
begin
  PColor := Value;
end;
 
谢谢!不过我还想问一下,对控件,怎样进行跟踪?
 
小小的De一下BUG:
代码:
...
//  var 
//    PColor:TColor;
implementation
  var
     PColor:TColor;//申明放在这里更好一些!
procedure Register
...
>>对控件,怎样进行跟踪?
什么意思?还不是与一般程序的调试一样嘛!没什么特别的啊?
 
是设断点然后按F7跟踪吗?可是我跟踪不到控件内部呀。
实在不好意思,本人纯菜鸟,还望指点一二。多谢!
 
杜宝 的耐心让人佩服。
我在 delphi5 程序员指南 中见过一个这样的例子,你可以看一下,与你的非常的相似。
 
to J5203:
谢谢你的分!说实话我真不明白你的:
>>对控件,怎样进行跟踪?
是什么意思,所以你在10:22把贴子顶起来我没回答,没想到下午你就把问题结束了。
我是在你的控件的Create事件的第一行用F5设了一个断点,这样程序只要一运行
这里就中断了,这时候再跟踪什么的都可以以啊!
相关的东东我想你找一本Delphi的全面一点的参考书上都有,这类的问题书上讲
的都比这回答的详细一些。这里只适合解决——疑难杂症!
 
后退
顶部