Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Во время показа hints мелькает фоном стандартная подсказка. [D7, WinXP]


Страницы:   1 2

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, чтобы фоновый канвас не показывался на доли секунд перед выводом основного канваса?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо