![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Во время показа hints мелькает фоном стандартная подсказка. [D7, WinXP]
Dr. Andrew © (2007-07-09 19:08:00)Доброго дня, Мастера!
Я использую свой собственный формат всплывающей подсказки hint объявленной в процедуре onFormCreate^
{* установить собственный формат подсказок *}
Application.ShowHint := False;
HintWindowClass := SGGraphicHint.TSGGraphicHintWindow;
FHintWindow := HintWindowClass.Create(self);
Application.ShowHint := True;
Проблема: во время показа hints мелькает фоном стандартная подсказка (желтое поле).
Вопрос: как можно отловить (hook или еще каким образом?) системную стандартную подсказку (вернее фоновое отображение ее Canvasа) и запретить ее появление одновременно с моим hint? Пожалуйста, приведите маленький пример. Всем спасибо!
MetalFan (2007-07-10 10:38:00) [21]в примере тупо скопирована часть кода VCL.
и вообще, пример этот (из DWorld), имхо, не совсем удачный.
Инс (2007-07-10 10:06:00) [22]
> В ActivateHint сначала вызывается SetWindowPos с SWP_SHOWWINDOW,
> а потом запрашивается перерисовка вызовом Invalidate. Похоже,
> что стандартная отрисовка происходит в результате вызова
> SetWindowPos, потом перемалывается куча сообщений и только
> после этого дело доходит до перерисовки. То есть, имеем
> то самое мелькание стандартного окна.
В ряд ли, все равно перерисовка осуществляется именно по приходу WM_ERASEBKGND и WM_PAINT, а обработчик у них только один, так что как как при SetWindowPos может происходить какая-то другая обработка? А Invalidate действительно стоит убрать.
> Если это так, то лучший выход - рисовать не в методе Paint,
> а в WndProc, непосредственно при обработке WM_PAINT.
А это не имеет значения. Обработчик WM_PAINT и так вызывает Paint после вызова BeginPaint.
А вот из-за чего может быть проблема - так это из-за обработки WM_ERASEBKGND. Это сообщение имеет бОльший приоритет, чем WM_PAINT (поэтому последнее может быть обработано с задержкой), а в его обработчике по-умолчанию фон заливается определенной кистью (скорее всего - желтой). Такое поведение нужно задавить:
TGraphicHintWindow = class(THintWindow)
constructor Create(AOwner: TComponent); override;
private
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
...
end;
...
procedure TGraphicHintWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
Result:=1; // Перекрываем старый обработчик пустышкой
end;
MetalFan (2007-07-10 08:59:00) [23]+ еще если перекрыть NCPaint, то можно и рамочку нарисовать
TMHintWindow = class( THintWindow )
...
procedure NCPaint(DC: HDC); override;
...
procedure TMHintWindow.NCPaint(DC: HDC);
var
R: TRect;
lCanvas: TCanvas;
begin
lCanvas := TCanvas.Create;
try
lCanvas.Handle := DC;
lCanvas.Brush.Color := clBlack;
lCanvas.Rectangle(0,0,Width, Height);
finally
lCanvas.Free;
end;
end;
MetalFan (2007-07-10 08:53:00) [24]не совсем понятно, зачем в примере перекрыт ActivateHint.
вот набросал небольшой пример, изменяется размер и выводится свой текст другим цветом в хинте.
TMHintWindow = class( THintWindow )
protected
procedure Paint; override;
public
function CalcHintRect(MaxWidth: Integer; const AHint: string;
AData: Pointer): TRect; override;
end;
...
{ TMHintWindow }
function TMHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string;
AData: Pointer): TRect;
begin
Result := inherited CalcHintRect( MaxWidth, AHint, AData );
Inc( Result.Left, 50);
Inc( Result.Bottom, 14);
end;
procedure TMHintWindow.Paint;
var
lRect: TRect;
begin
lRect := ClientRect;
Canvas.Brush.Color := clRed;
Canvas.Font.Color := clWhite;
Canvas.TextRect( lRect, lRect.Left + 2, lRect.Top + 2, 'TEST HINT' );
end;
Dr. Andrew (2007-07-10 02:39:00) [25]вызов в ActivateHint Repaint вместо Invalidate не помогает. Увы!
Dr. Andrew (2007-07-10 02:35:00) [26]Спасибо, но как это можно практически представить, опыта работы с WM_PAINT у меня нет. Можете помочь?
Юрий Зотов (2007-07-10 02:05:00) [27]Не уверен, но одно подозрение есть...
В ActivateHint сначала вызывается SetWindowPos с SWP_SHOWWINDOW, а потом запрашивается перерисовка вызовом Invalidate. Похоже, что стандартная отрисовка происходит в результате вызова SetWindowPos, потом перемалывается куча сообщений и только после этого дело доходит до перерисовки. То есть, имеем то самое мелькание стандартного окна.
Если это так, то лучший выход - рисовать не в методе Paint, а в WndProc, непосредственно при обработке WM_PAINT. Можно попробовать и более простой вариант - в ActivateHint вызывать не Invalidate, а Repaint (чтобы форсировать перерисовку). Но первый способ лучше, поскольку он вообще никакой перерисовки не требует.
Dr. Andrew (2007-07-10 01:28:00) [28]это я показал исходный код, а в моей программе битмап загружается из ресурсов один раз, нет причина не в этом, идет фоновая прорисовка санваса прежней подсказки - стандартной. вот как ее убрать. а можно хуком перехватить и запретить появление стандартного канваса или его прорисовки?
Юрий Зотов (2007-07-10 00:58:00) [29]Зачем перед отрисовкой битмапа создавать его и загружать из файла? Это же задержка отрисовки битмапа - и возможно, что причина в ней и есть.
В любом случае лучше создать и загрузить битмап один раз - притом заранее, в конструкторе. И уничтожить его тоже один раз, в деструкторе.
Dr. Andrew (2007-07-09 23:36:00) [30]Мне кажется, что что-то не так в процедуре procedure TGraphicHintWindow.Paint, но что?
Dr. Andrew (2007-07-09 23:36:00) [31]
{*********************************************************
Mit Hilfe des folgendes Codes lassen sich leicht beliebige
Hints erstellen. Dazu muss nur dir Prozedur "Paint" den
Wьnschen entsprechend angepasst werden.
With the following Code you can simply create custom hints.
You just have to change the procedur "Paint".
*********************************************************}
type
TGraphicHintWindow = class(THintWindow)
constructor Create(AOwner: TComponent); override;
private
FActivating: Boolean;
public
procedure ActivateHint(Rect: TRect; const AHint: string); override;
protected
procedure Paint; override;
published
property Caption;
end;
{...}
constructor TGraphicHintWindow.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{
Hier kцnnen beliebige Schrift Eigenschaften gesetzt
werden.
Here you can set custom Font Properties:
}
with Canvas.Font do
begin
Name := 'Arial';
Style := Style + [fsBold];
Color := clBlack;
end;
end;
procedure TGraphicHintWindow.Paint;
var
R: TRect;
bmp: TBitmap;
begin
R := ClientRect;
Inc(R.Left, 2);
Inc(R.Top, 2);
{*******************************************************
Der folgende Code ist ein Beispiel wie man die Paint
Prozedur nutzen kann um einen benutzerdefinierten Hint
zu erzeugen.
The folowing Code ist an example how to create a custom
Hint Object. :
}
bmp := TBitmap.Create;
bmp.LoadfromFile('D:\hint.bmp');
with Canvas do
begin
Brush.Style := bsSolid;
Brush.Color := clsilver;
Pen.Color := clgray;
Rectangle(0, 0, 18, R.Bottom + 1);
Draw(2, (R.Bottom div 2) - (bmp.Height div 2), bmp);
end;
bmp.Free;
//Beliebige HintFarbe
//custom Hint Color
Color := clWhite;
Canvas.Brush.Style := bsClear;
Canvas.TextOut(20, (R.Bottom div 2) - (Canvas.Textheight(Caption) div 2),
Caption);
{********************************************************}
end;
procedure TGraphicHintWindow.ActivateHint(Rect: TRect; const AHint: string);
begin
FActivating := True;
try
Caption := AHint;
//Hцhe des Hints setzen setzen
//Set the "Height" Property of the Hint
Inc(Rect.Bottom, 14);
//Breite des Hints setzen
//Set the "Width" Property of the Hint
Rect.Right := Rect.Right + 20;
UpdateBoundsRect(Rect);
if Rect.Top + Height > Screen.DesktopHeight then
Rect.Top := Screen.DesktopHeight - Height;
if Rect.Left + Width > Screen.DesktopWidth then
Rect.Left := Screen.DesktopWidth - Width;
if Rect.Left < Screen.DesktopLeft then
Rect.Left := Screen.DesktopLeft;
if Rect.Bottom < Screen.DesktopTop then
Rect.Bottom := Screen.DesktopTop;
SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top, Width, Height,
SWP_SHOWWINDOW or SWP_NOACTIVATE);
Invalidate;
finally
FActivating := False;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
HintWindowClass := TGraphicHintWindow;
Application.ShowHint := False;
Application.ShowHint := True;
end;
ссылка на код: http://delphiworld.narod.ru/base/graphic_hint.html
при быстром перемещении мыши фоном бликом появляется стандартный желтый канвас или ширина санваса этого хинта сначала бликом растягивается до правого края экрана, а затем возвращается в нормально положение и все это за доли секунды, но они видны! спасибо за помощь!
Юрий Зотов (2007-07-09 23:14:00) [32]Показывайте код своего класса. Похоже, что-то там не так.
Dr. Andrew (2007-07-09 19:41:00) [33]Спасибо, FHintWindow.DoubleBuffered:=true; не помогает, какие еще есть мысли? может hook применить, тогда как это сделать - можно пример?
Инс (2007-07-09 19:32:00) [34]
Application.ShowHint := False;
HintWindowClass := SGGraphicHint.TSGGraphicHintWindow;
FHintWindow := HintWindowClass.Create(self);
FHintWindow.DoubleBuffered:=true;
Application.ShowHint := True;
Помогло?
Dr. Andrew (2007-07-09 19:23:00) [35]просто использование Application.ShowHint := False; не справляется. Что делать? Может что-то надо добавить в процедуру Paint своего компонента Hint, чтобы фоновый канвас не показывался на доли секунд перед выводом основного канваса?