скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Добавляем дополнительную кнопку в заголовок формы



Автор: Vimil Saju

Чтобы добавить дополнительную кнопку, нам прийдётся создать обработчики для следующих событий:
WM_NCPAINT;//вызывается, когда перерисовывается не клиентская область формы
WM_NCACTIVATE; вызывается, когда заголовок формы становится активныи
WM_NCLBUTTONDOWN; вызывается, когда кнопка мыши нажимается на не клиентской области
WM_NCMOUSEMOVE; вызывается, когда курсор мыши передвигается по не клиентской области
WM_MOUSEMOVE;вызывается, когда курсор мыши передвигается по клиентской области
WM_LBUTTONUP; вызывается, когда кнопка мыши отпушена в клиентской области
WM_NCLBUTTONUP; вызывается, когда кнопка мыши отпушена в не клиентской области
WM_NCLBUTTONDBLCLK; вызывается при двойном щелчке мышкой в не клиентской области

Приведённый ниже код модифицирован, чтобы избавиться от нежелательного мерцания кнопки
будем использовать следующие переменные:

h1(Thandle) : хэндл контекста устройства всего окна, включая не клиентскую область.
pressed(boolean): индикатор, показывающий, нажата кнопка или нет.
focuslost(boolean): индикатор, показывающий, находится ли фокус на кнопке или нет.
rec(Trect): размер кнопки.

Собственно сам исходник:

type
  TForm1 = class(TForm)
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private { Private declarations
  } public procedure
    WMNCPAINT(var msg: tmessage); message WM_NCPAINT;
    procedure WMNCACTIVATE(var
      msg: tmessage); message WM_NCACTIVATE;
    procedure
      WMNCMOUSEDOWN(var msg: tmessage); message WM_NCLBUTTONDOWN;
    procedure WMNCMOUSEMOVE(var
      msg: tmessage); message WM_NCMOUSEMOVE;
    procedure WMMOVE(var msg: tmessage); message
      WM_MOUSEMOVE;
    procedure WMLBUTTONUP(var
      msg: tmessage); message WM_LBUTTONUP;
    procedure
      WMNCMOUSEUP(var msg: tmessage); message WM_NCLBUTTONUP;
    procedure WNCLBUTTONDBLCLICK(var
      msg: tmessage); message WM_NCLBUTTONDBLCLK;
  end;
var
  Form1: TForm1;
  h1: thandle;
  pressed: boolean;
  focuslost: boolean;
  rec: trect;
implementation{$R *.DFM}

procedure tform1.WMLBUTTONUP(var msg: tmessage);
begin
  pressed := false;
  invalidaterect(form1.handle, @rec, true);
  inherited;
end;

procedure tform1.WMMOVE(var msg: tmessage);
var
  tmp: boolean
begin
  tmp := focuslost;
  focuslost := true;
  if tmp <> focuslost then
    invalidaterect(form1.handle, @rec, true);
  inherited;
end;

procedure tform1.WMNCMOUSEMOVE(var msg: tmessage);
var
  pt1: tpoint;
  tmp: boolean;
begin
  tmp := focuslost;
  pt1.x := msg.LParamLo - form1.left;
  pt1.y := msg.LParamHi - form1.top;
  if not (ptinrect(rec, pt1)) then
    focuslost := true
  else
    focuslost := false;
  if tmp <> focuslost then
    invalidaterect(form1.handle, @rec, true);
end;

procedure tform1.WNCLBUTTONDBLCLICK(var msg: tmessage);
var
  pt1: tpoint;
begin
  pt1.x := msg.LParamLo - form1.left;
  pt1.y := msg.LParamHi - form1.top;
  if not (ptinrect(rec, pt1)) then
    inherited;
end;

procedure
  tform1.WMNCMOUSEUP(var msg: tmessage);
var
  pt1: tpoint;
begin
  pt1.x := msg.LParamLo - form1.left;
  pt1.y := msg.LParamHi - form1.top;
  if (ptinrect(rec, pt1)) and (focuslost = false) then
  begin
    pressed := false; {
    enter your code here when the button is
   clicked  }
    invalidaterect(form1.handle, @rec, true);
  end
  else
  begin
    pressed := false;
    focuslost := true;
    inherited;
  end;
end;

procedure tform1.WMNCMOUSEDOWN(var msg: tmessage);
var
  pt1: tpoint;
begin
  pt1.x := msg.LParamLo - form1.left;
  pt1.y := msg.LParamHi - form1.top;
  if ptinrect(rec, pt1) then
  begin
    pressed := true;
    invalidaterect(form1.handle, @rec, true);
  end
  else
  begin
    form1.paint;
    inherited;
  end;
end;

procedure
  tform1.WMNCACTIVATE(var msg: tmessage);
begin
  invalidaterect(form1.handle, @rec, true);
  inherited;
end;

procedure tform1.WMNCPAINT(var msg: tmessage);
begin
  invalidaterect(form1.handle, @rec, true);
  inherited;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  h1 := getwindowdc(form1.handle);
  rec.left := form1.width - 75;
  rec.top := 6;
  rec.right := form1.width - 60;
  rec.bottom := 20;
  selectobject(h1, getstockobject(ltgray_BRUSH));
  rectangle(h1, rec.left, rec.top, rec.right, rec.bottom);
  if
    (pressed = false) or (focuslost = true) then
    drawedge(h1, rec, EDGE_RAISED, BF_RECT)
  else if
    (pressed = true) and (focuslost = false) then
    drawedge(h1, rec, EDGE_SUNKEN, BF_RECT);
  releasedc(form1.handle, h1);
end;

procedure
  TForm1.FormResize(Sender: TObject);
begin
  form1.paint;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  rec.left := 0;
  rec.top := 0;
  rec.bottom := 0;
  rec.right := 0;
end;
Комментарии специалистов:

Дата: 25 Августа 2000г.
Автор: NeNashevnashev@mail.ru

InvalidateRect на событие Resize ничего не даёт. Но даже без него
кнопка всё равно моргает при Resize формы... Надо ещё где-то убрать

Для рисования кнопок на заголовке окна лучше пользоваться
DrawFrameControl а не DrawEdge... Так и с не серыми настройками
интерфейса всё правильно будет. Да и проще так.

Названия функций, констант и т.п лучше писать так, как они в описаниях
даются, а не подряд маленькими буквами. Особенно для публикации. Так
оно и читается по большей части лучше, и в С такая привычка Вам не
помешает...

Сравнивать логическое значение с логической константой чтоб получить
логическое значение глупо, так как логическое значение у Вас уже есть.
тоесь вместо
if (pressed=true) and (focuslost=false)
лучше писать
if Pressed and not FocusLost

Для конструирования прямоугольников и точек из координат есть две
простые функции Rect и Point.


В общем Ваша процедура FormPaint может выглядеть так:

procedure
  TMainForm.FormPaint(Sender:
  TObject);
var
  h1: THandle;
begin
  h1 := GetWindowDC(MainForm.Handle);
  rec := Rect(MainForm.Width - 75, 6, MainForm.Width - 60, 20);
  if
    Pressed and not FocusLost then
    DrawFrameControl(h1, rec, DFC_BUTTON,
      DFCS_BUTTONPUSH or DFCS_PUSHED)
  else
    DrawFrameControl(h1, rec,
      DFC_BUTTON,
      DFCS_BUTTONPUSH);
  ReleaseDC(MainForm.Handle, h1);
end;
Но вообще-то рисовать эту кнопку надо только при WM_NCPAINT, а не
всегда... И вычислять координаты по другому... Вдруг размер элементов
заголовка у юзера в системе не стандартный? А это просто настраивается...





Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook