Добавляем дополнительную кнопку в заголовок формы
Добавляем дополнительную кнопку в заголовок формы
Автор: 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г.
Автор: NeNashev nashev@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, а не
всегда... И вычислять координаты по другому... Вдруг размер элементов
заголовка у юзера в системе не стандартный? А это просто настраивается...
Взято с Исходников.ru
Непосредственно такой функции вроде нет, но можно изловчиться. Нарисовать там кнопку вручную и обрабатывать команды нажатия мышки на Caption Bar.
Пример.
unit Main;
interface
uses
Windows, Buttons, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormResize(Sender: TObject);
private
CaptionBtn : TRect;
procedure DrawCaptButton;
procedure WMNCPaint(var Msg : TWMNCPaint); message WM_NCPaint;
procedure WMNCActivate(var Msg : TWMNCActivate); message WM_NCACTIVATE;
procedure WMSetText(var Msg : TWMSetText); message WM_SETTEXT;
procedure WMNCHitTest(var Msg : TWMNCHitTest); message WM_NCHITTEST;
procedure WMNCLButtonDown(var Msg : TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
const
htCaptionBtn = htSizeLast + 1;
{$R *.DFM}
procedure TForm1.DrawCaptButton;
var
xFrame, yFrame, xSize, ySize : Integer;
R : TRect;
begin
//Dimensions of Sizeable Frame
xFrame := GetSystemMetrics(SM_CXFRAME);
yFrame := GetSystemMetrics(SM_CYFRAME);
//Dimensions of Caption Buttons
xSize := GetSystemMetrics(SM_CXSIZE);
ySize := GetSystemMetrics(SM_CYSIZE);
//Define the placement of the new caption button
CaptionBtn := Bounds(Width - xFrame - 4*xSize + 2,
yFrame + 2, xSize - 2, ySize - 4);
//Get the handle to canvas using Form's device context
Canvas.Handle := GetWindowDC(Self.Handle);
Canvas.Font.Name := 'Symbol';
Canvas.Font.Color := clBlue;
Canvas.Font.Style := [fsBold];
Canvas.Pen.Color := clYellow;
Canvas.Brush.Color := clBtnFace;
try
DrawButtonFace(Canvas, CaptionBtn, 1, bsAutoDetect, False, False, False);
//Define a smaller drawing rectangle within the button
R := Bounds(Width - xFrame - 4 * xSize + 2,
yFrame + 3, xSize - 6, ySize - 7);
with CaptionBtn do
Canvas.TextRect(R, R.Left + 2, R.Top - 1, 'W');
finally
ReleaseDC(Self.Handle, Canvas.Handle);
Canvas.Handle := 0;
end;
end;
procedure TForm1.WMNCPaint(var Msg : TWMNCPaint);
begin
inherited;
DrawCaptButton;
end;
procedure TForm1.WMNCActivate(var Msg : TWMNCActivate);
begin
inherited;
DrawCaptButton;
end;
procedure TForm1.WMSetText(var Msg : TWMSetText);
begin
inherited;
DrawCaptButton;
end;
procedure TForm1.WMNCHitTest(var Msg : TWMNCHitTest);
begin
inherited;
with Msg do
if PtInRect(CaptionBtn, Point(XPos - Left, YPos - Top)) then
Result := htCaptionBtn;
end;
procedure TForm1.WMNCLButtonDown(var Msg : TWMNCLButtonDown);
begin
inherited;
if (Msg.HitTest = htCaptionBtn) then
ShowMessage('You hit the button on the caption bar');
end;
procedure TForm1.FormResize(Sender: TObject);
begin
//Force a redraw of caption bar if form is resized
Perform(WM_NCACTIVATE, Word(Active), 0);
end;
end.
Источник:
Автор: Tercio Ferdinando Gaudencio Filho
Приведённый здесь код создаёт кнопку в заголовке окна, создаёт MenuItem в системном меню и создаёт подсказку(Hint) в кнопке. Поместите код в Ваш Unit и замените "FrmMainForm" на Ваше имя формы, а так же некоторые кусочки кода, ткст подсказки и т.д.
Совместимость: Delphi 3.x (или выше)
...
private
{ Private declarations }
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 WMMOUSEMOVE (var Msg: TMessage); message WM_MOUSEMOVE;
procedure WMLBUTTONUP (var msg: Tmessage); message WM_LBUTTONUP;
procedure WNCLBUTTONDBLCLICK (var msg: Tmessage); message WM_NCLBUTTONDBLCLK;
procedure WMNCRBUTTONDOWN (var msg: Tmessage); message WM_NCRBUTTONDOWN;
procedure WMNCHITTEST (var msg: Tmessage); message WM_NCHITTEST;
procedure WMSYSCOMMAND (var msg: Tmessage); message WM_SYSCOMMAND;
...
var
...
Pressed : Boolean;
FocusLost : Boolean;
Rec : TRect;
NovoMenuHandle : THandle;
PT1 : TPoint;
FHintshow : Boolean;
FHint : THintWindow;
FHintText : String;
FHintWidth : Integer;
...
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMSYSCOMMAND(var Msg: TMessage);
begin
if Msg.WParam=LongInt(NovoMenuHandle) then
//*********************************************
//Кнопка была нажата! Добавьте сюда Вашу функцию
//*********************************************
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMNCHITTEST(var Msg: TMessage);
var
Tmp : Boolean;
begin
if Pressed then
begin
Tmp:=FocusLost;
PT1.X := Msg.LParamLo - FrmMainForm.Left;
PT1.Y := Msg.LParamHi - FrmMainForm.Top ;
if PTInRect(Rec, PT1) then
FocusLost := False
else
FocusLost := True;
if FocusLost <> Tmp then
InvalidateRect(FrmMainForm.Handle, @Rec, True);
end;
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMLBUTTONUP(var Msg: TMessage);
var
Tmp : Boolean;
begin
ReleaseCapture;
Tmp := Pressed;
Pressed := False;
if Tmp and PTInRect(Rec, PT1) then
begin
InvalidateRect(FrmMainForm.Handle, @Rec, True);
FHintShow := False;
FHint.ReleaseHandle;
//*********************************************
//Кнопка была нажата! Добавьте сюда Вашу функцию
//*********************************************
end
else
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WNCLBUTTONDBLCLICK(var Msg: TMessage);
begin
PT1.X := Msg.LParamLo - FrmMainForm.Left;
PT1.Y := Msg.LParamHi - FrmMainForm.Top ;
if not PTInRect(Rec, PT1) then
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMNCRBUTTONDOWN(var Msg: TMessage);
begin
PT1.X := Msg.LParamLo - FrmMainForm.Left;
PT1.Y := Msg.LParamHi - FrmMainForm.Top ;
if not PTInRect(Rec, PT1) then
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMNCMOUSEDOWN(var Msg: TMessage);
begin
PT1.X := Msg.LParamLo - FrmMainForm.Left;
PT1.Y := Msg.LParamHi - FrmMainForm.Top ;
FHintShow := False;
if PTInRect(Rec, PT1) then
begin
Pressed := True;
FocusLost := False;
InvalidateRect(FrmMainForm.Handle, @Rec, True);
SetCapture(TWinControl(FrmMainForm).Handle);
end
else
begin
FrmMainForm.Paint;
inherited;
end;
end;
//------------------------------------------------------------------------------
//That function Create a Hint
procedure TFrmMainForm.WMNCMOUSEMOVE(var Msg: TMessage);
begin
PT1.X := Msg.LParamLo - FrmMainForm.Left;
PT1.Y := Msg.LParamHi - FrmMainForm.Top ;
if PTInRect(Rec, PT1) then
begin
FHintWidth := FHint.Canvas.TextWidth(FHintText);
if (FHintShow = False) and (Length(Trim(FHintText)) <> 0) then
FHint.ActivateHint(
Rect(
Mouse.CursorPos.X,
Mouse.CursorPos.Y + 20,
Mouse.CursorPos.X + FHintWidth + 10,
Mouse.CursorPos.Y + 35
),
FHintText
);
FHintShow := True;
end
else
begin
FHintShow := False;
FHint.ReleaseHandle;
end;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMMOUSEMOVE(var Msg: TMessage);
begin
FHintShow := False;
FHint.ReleaseHandle;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMNCACTIVATE(var Msg: TMessage);
begin
InvalidateRect(FrmMainForm.Handle, @Rec, True);
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.WMNCPAINT(var Msg: TMessage);
begin
InvalidateRect(FrmMainForm.Handle, @Rec, True);
inherited;
end;
//------------------------------------------------------------------------------
procedure TFrmMainForm.FormPaint(Sender:TObject);
var
Border3D_Y, Border_Thickness, Btn_Width,
Button_Width, Button_Height : Integer;
MyCanvas : TCanvas;
begin
MyCanvas := TCanvas.Create;
MyCanvas.Handle := GetWindowDC(FrmMainForm.Handle);
Border3D_Y := GetSystemMetrics(SM_CYEDGE);
Border_Thickness:= GetSystemMetrics(SM_CYSIZEFRAME);
Button_Width := GetSystemMetrics(SM_CXSIZE);
Button_Height := GetSystemMetrics(SM_CYSIZE);
//Создаём квадратную кнопку, но если Вы захотите создать кнопку другого размера, то
//измените эту переменную на Вашу ширину.
Btn_Width := Border3D_Y + Border_Thickness + Button_Height - (2 * Border3D_Y) - 1;
Rec.Left := FrmMainForm.Width - (3 * Button_Width + Btn_Width);
Rec.Right := FrmMainForm.Width - (3 * Button_Width + 03);
Rec.Top := Border3D_Y + Border_Thickness - 1;
Rec.Bottom := Rec.Top + Button_Height - (2 * Border3D_Y);
FillRect(MyCanvas.Handle,Rec,HBRUSH(COLOR_BTNFACE+1));
If not Pressed or Focuslost Then
DrawEdge(MyCanvas.Handle, Rec, EDGE_RAISED, BF_SOFT or BF_RECT)
Else If Pressed and Not Focuslost Then
DrawEdge(MyCanvas.Handle, Rec, EDGE_SUNKEN, BF_SOFT or BF_RECT);
//It draw a the application icon to the button. Easy to change.
DrawIconEX(MyCanvas.Handle, Rec.Left+4, Rec.Top+3, Application.Icon, 8, 8, 0, 0, DI_NORMAL);
MyCanvas.Free;
end;
...
procedure TFrmMainForm.FormCreate(Sender: TObject);
...
InsertMenu(GetSystemMenu(Handle,False), 4, MF_BYPOSITION+MF_STRING, NovoMenuHandle,pchar('TEXT OF THE MENU'));
Rec := Rect(0,0,0,0);
FHintText := 'Put the text of your Hint HERE';
FHint := THintWindow.Create(Self);
FHint.Color := clInfoBk; //Вы можете изменить бэкграунд подсказки
...
Взято с Исходников.ru