如何在窗体标题栏上添加一个按钮?

whinformation 2001-07-30 02:25:08
如何在窗体标题栏(蓝色区域上,在最小最大及关闭按钮左边)上添加一个按钮?
...全文
634 29 打赏 收藏 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
cdws222 2002-01-29
  • 打赏
  • 举报
回复
我也想要一个,能发来吗?
zhaosoft@21cn.com
elong518 2001-09-05
  • 打赏
  • 举报
回复
耗子兄,我也想要一个。elong518@sina.com
Spring414 2001-09-05
  • 打赏
  • 举报
回复
谢谢,可否也送我一份?

spring414@8848.net
haoel 2001-08-02
  • 打赏
  • 举报
回复
Delphi中的消息机制用的是message语句。而BCB中的就像VC的一样用的是宏!
我还是喜欢Delphi中的消息映射机制,我不想在这里讲Delphi的消息映射原理,
还请大家去看《delphi人员开发指南》138元的那本书。

另外,juco11@21cn.com,kasuga@263.net,shally5@163.net,dengbcb@263.net 我寄出了。

SSTS 2001-07-31
  • 打赏
  • 举报
回复
//---------------------------------------------------------------------------
#ifndef MAINFORMH
#define MAINFORMH
//---------------------------------------------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\Menus.hpp>
#include <vcl\ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMainMenu *MainMenu1;
TMenuItem *File1;
TMenuItem *Exit1;
TTimer *Timer1;
void __fastcall Exit1Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall FormResize(TObject *Sender);
private: // User declarations
TCanvas *WindowCanvas;
TRect CaptionRect;
AnsiString CustomCaption;
TColor FinalCaptionColor;
int FinalBlueIntensity;
int FinalGreenIntensity;
int FinalRedIntensity;
bool IsNT35;
bool HeartBeat;
bool CanDrawMyCustomCaption(void);
void CalculateCaptionRect(void);
void DrawGradient(void);
void DrawIcon(void);
void DrawCaptionString(void);
void DrawHeartBeatLight(void);
void __fastcall WMNCPaint(TMessage &Msg);
void __fastcall WMNCActivate(TWMNCActivate &Msg);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1(void);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_NCPAINT,TMessage,WMNCPaint)
MESSAGE_HANDLER(WM_NCACTIVATE,TWMNCActivate,WMNCActivate)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern TForm1 *Form1;
//---------------------------------------------------------------------------
#endif





//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "MAINFORM.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
CustomCaption = "Custom Caption";
Caption = "";
WindowCanvas = new TCanvas;
// this code determines if we are running on NT3.X
TOSVersionInfo ver;
ver.dwOSVersionInfoSize = sizeof(TOSVersionInfo);
GetVersionEx( &ver);
if(ver.dwMajorVersion < 4)
{
// if the OS is NT 3.5, the custom caption won't be drawn
// use the Caption property as usual, since the custom
// caption won't be able to draw the string.
IsNT35 = true;
Caption = CustomCaption;
}
else
IsNT35 = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::WMNCActivate(TWMNCActivate &Msg)
{
Msg.Result = true; // always handle this message;
if ((bool)Msg.Active == false) // if non-active draw default
{ // non-active title bar
DefWindowProc( Handle, Msg.Msg, Msg.Active, 0 );
// add code here to draw caption when window is inactive.
// in this example, we leave the inactive caption alone.
return;
}
TMessage PaintMsg; // if active, do same thing as WMNCPaint
PaintMsg.Msg = Msg.Msg; // create a MSG to pass to WMNCPaint and
PaintMsg.WParam = Msg.Active; // call the function directly so painting
WMNCPaint(PaintMsg); // happens now.
}

void __fastcall TForm1::WMNCPaint(TMessage &Msg)
{
// use default processing to draw min/max/close buttons, menu, and the
// frame. the caption bar is drawn too, but we paint over that later.
DefWindowProc(Handle, Msg.Msg,Msg.WParam,Msg.LParam);

// Check for any reason not to draw the custom caption
if(CanDrawMyCustomCaption() == false)
return;

// create a DC for the entire window, then assign
// the handle to the window canvas
HDC WindowDC = GetWindowDC(Handle);
WindowCanvas->Handle = WindowDC;

CalculateCaptionRect(); // calculate size of caption bar
DrawGradient(); // draw the shaded gradient
DrawIcon(); // patch the icon
DrawCaptionString();
DrawHeartBeatLight(); // draw the LED heartbeat

ReleaseDC(Handle, WindowDC); // free resources
WindowCanvas->Handle = 0;
}

bool TForm1::CanDrawMyCustomCaption(void)
{
// under certain conditions we don't want to shade the custom caption.
// this function bundles all of the reasons into one.
if (WindowCanvas == 0) // WMNCPaint can execute after
return false; // destructor has been called.
if(Application->Active == false) //can get WM_NCPAINT messages
return false; // when inactive
if(Width < 150) // shading looks poor at very small
return false; // widths
if(IsNT35 == true) // NT has 3.5 has win3 style system menu
return false; // and centered caption text, so forget it

// shading looks poor if its from black to a very light color, Word actually
// shades from white instead of black for light caption colors, we will just not
// shade for light colored captions. Light colors have high RGB values
FinalCaptionColor = TColor(GetSysColor(COLOR_ACTIVECAPTION));
FinalBlueIntensity = GetBValue(FinalCaptionColor);
FinalGreenIntensity= GetGValue(FinalCaptionColor);
FinalRedIntensity = GetRValue(FinalCaptionColor);
// is at least one of the RGB values dark, if not, don't draw the shading
if ((FinalBlueIntensity < 128) || (FinalGreenIntensity < 128) || (FinalRedIntensity < 128) )
return true;
else
return false;
}

void TForm1::CalculateCaptionRect(void)
{
// determine the coordinates of the custom area of the caption. The left, top,
// and bottom must be calculated precisely. The right value is an arbitrary
// value that keeps us away from the min/max buttons.
CaptionRect.Left = GetSystemMetrics(SM_CXFRAME);
CaptionRect.Right= Width- 4*GetSystemMetrics(SM_CXSIZE); // stay away from btns
CaptionRect.Top = GetSystemMetrics(SM_CYFRAME);
CaptionRect.Bottom=CaptionRect.Top + GetSystemMetrics(SM_CYCAPTION)-1;
}


void TForm1::DrawGradient(void)
{
// Shading involves gradually increasing RGB color values from 0 (black)
// to the final RGB value of the caption color. The Increment values
// will be multiplied by 0,1..31 to create 32 shades. The FinalXXX
// values are calculated inside of CanDrawMyCustomGraphics
int BlueIncrement = (FinalBlueIntensity+1) / 32; // max intensity is 255,
int GreenIncrement= (FinalGreenIntensity+1)/32; // adding 1 makes number
int RedIncrement = (FinalRedIntensity+1)/32; // evenly divisible by 32.

TRect Section = CaptionRect;
// SectionWidth represents the width of each gradient section. Caption
// bar will contain 36 gradient sections, 5 sections will be black, the
// remaining 31 sections will be between black and the caption color
int SectionWidth = (CaptionRect.Right - CaptionRect.Left)/36;
TColor FillColor(clBlack);
Section.Right = Section.Left + 5*SectionWidth; //draw 5 sections of black
WindowCanvas->Brush->Color = FillColor; //configure the brush
WindowCanvas->Brush->Style = bsSolid;
WindowCanvas->FillRect(Section); //fill in black sections
Section.Left+=5*SectionWidth; //move section over

for (int j=1;j<=31;j++) // loop through the shades of color
{ // from black to the caption color
Section.Right = Section.Left + SectionWidth; // size the section
FillColor = (TColor) RGB((RedIncrement*j), // create dithered color
(GreenIncrement*j), // based on loop index.
(BlueIncrement*j));
WindowCanvas->Brush->Color = FillColor; // set brush to new color
WindowCanvas->FillRect(Section); // brush fill the section
Section.Left += SectionWidth; // move section over
}
}


void TForm1::DrawIcon(void)
{
// Need to redraw the system icon because DrawGradient just painted
// over it with black. DrawGradient painted over it because the icon
// had the caption color surrounding it.
int IconWidth = GetSystemMetrics(SM_CXSMICON); // calculate width and
int IconHeight= GetSystemMetrics(SM_CYSMICON); // height of icon
TRect Section;
Section.Left=CaptionRect.Left+2; // determine where the icon belongs
Section.Top =CaptionRect.Top +1;
Section.Right=Section.Left + IconWidth; // size the rect to hold the icon
Section.Bottom=Section.Top + IconHeight;

// paint the application icon, could avoid stretching by
// supplying a 16 by 16 icon.
DrawIconEx(WindowCanvas->Handle, Section.Left, Section.Top, // api call
Application->Icon->Handle,IconWidth,IconHeight,0,NULL,DI_NORMAL);
}


void TForm1::DrawCaptionString(void)
{
// need to draw our own caption string. must avoid using the Caption
// form member to avoid flicker
RECT r; // need an API style rect
r.left=CaptionRect.Left + 2 + 16 + 4; // size the rect
r.right=CaptionRect.Right-20;
r.top = CaptionRect.Top;
r.bottom = CaptionRect.Bottom;
SetBkMode(WindowCanvas->Handle,TRANSPARENT); // transparent mode so text
WindowCanvas->Font->Color=clWhite; // does not wipe out shading
WindowCanvas->Font->Style = WindowCanvas->Font->Style << fsBold;
DrawText(WindowCanvas->Handle,CustomCaption.c_str(),CustomCaption.Length(),
&r,DT_SINGLELINE|DT_VCENTER); // draw with vert centered text
}


void TForm1::DrawHeartBeatLight(void)
{
// draw a little LED style heartbeat indicator. this is just an
// ellipse with varying fill color
TRect Section = CaptionRect;
int cYCaption = GetSystemMetrics(SM_CYCAPTION);
if(HeartBeat == true)
WindowCanvas->Brush->Color = (TColor) RGB(0,255,0); // bright green
else
WindowCanvas->Brush->Color = clBlack;
WindowCanvas->Pen->Color=clBlack;
WindowCanvas->Ellipse(Section.Right-cYCaption/2,
Section.Top +cYCaption/4,
Section.Right,
Section.Bottom-cYCaption/4);
}

__fastcall TForm1::~TForm1(void)
{
delete WindowCanvas;
WindowCanvas = 0; // zero canvas so CanDrawMyCustomCaption can
// block use of an invalid pointer.
}

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
HeartBeat = !HeartBeat;
Perform(WM_NCPAINT,1,0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
Perform(WM_NCPAINT,1,0);
}
//---------------------------------------------------------------------------
hzg115 2001-07-31
  • 打赏
  • 举报
回复
hzg115@sina.com
来一个
chzhli186858 2001-07-31
  • 打赏
  • 举报
回复
我学习一下
ExitWindows 2001-07-31
  • 打赏
  • 举报
回复
up
gqxs 2001-07-31
  • 打赏
  • 举报
回复
up
VSaber 2001-07-30
  • 打赏
  • 举报
回复
to 耗子!
而且Delphi中的消息处理机制和C++Builder中的不一样,有天大的不一样。


请教一下,有什么不一样,我不明白什么意思呢?呵呵 :)
ddeng 2001-07-30
  • 打赏
  • 举报
回复
算我一个,学习学习haoel(耗子)高人的东东,先谢了。dengbcb@263.net
shally5 2001-07-30
  • 打赏
  • 举报
回复
我也想要一份
shally5@163.net
kyosuke 2001-07-30
  • 打赏
  • 举报
回复
我也想看看,谢谢。
kasuga@263.net
Chxis 2001-07-30
  • 打赏
  • 举报
回复
haoel(耗子)
那是a.eml可是没有代码啊?
haoel 2001-07-30
  • 打赏
  • 举报
回复
寄给你了。juco11@21cn.com
Chxis 2001-07-30
  • 打赏
  • 举报
回复
haoel(耗子) 兄,
我想要个
juco11@21cn.com
wangxd 2001-07-30
  • 打赏
  • 举报
回复
我的技巧大全中有,请到wangxd.21tt.com下栽
haoel 2001-07-30
  • 打赏
  • 举报
回复
楼上那位仁兄给出的delphi程序不错。

只不过他是以控件的方式给出的,看起来倒反会让人很难懂。
而且Delphi中的消息处理机制和C++Builder中的不一样,有天大的不一样。

所以,我还是把程序寄给你了,那个程序在BCB5.0下运行通过。如果还有别的网友要,请告诉我。
haoel 2001-07-30
  • 打赏
  • 举报
回复
好了,我把程序发到你的邮箱了。请查收。
aningstar 2001-07-30
  • 打赏
  • 举报
回复
给你一篇Delphi的
-- 大家在使用某些软件的过程中,有没有注意到有些软件有一些很有趣的东西。比如说在主窗口的标题栏上居然有一个按钮。在Internet中随处可见这样的小控件。按钮怎么可以加入到非客户区(Client)呢?

---- 在这里,最关键的一点就是,大家不要被传统知识误导:真的认为它是一个按钮。有名柄(handle)的控件当然不能放在标题栏上了。有经验的程序员用Spy++跟踪一下的话,马上就会发现其中的秘密。它并不是一个按钮,只不过是处理成按钮的样子罢了。

---- 既然知道了所以然,那么我们为什么不能自己来做一个呢,当然没问题,下面我们就用Delphi来实现它,讲注意我的注解。

---- 在具体实例之前,我们应该知道几个关于标题栏的重要的消息:

---- WM_NCPAINT:重画标题栏消息。我们必须截住它,可以在这里重画按钮;

---- WM_NCLBUTTONDOWN:在标题栏上按下鼠标左键消息。我们可以截住它,在标题栏上画出按钮按下的样子,并且可以在其中进行自已的单击事件的处理,使得它像一个按钮;

---- WM_NCLBUTTONUP:在标题栏上释放鼠标左键消息。我们可以截住它,在标题栏上画出按钮弹起的样子;

---- WM_NCLBUTTONDBLCLK:在标题栏上双击鼠标左键消息。我们可以截住它,当在按钮区域双击时,我们就该使其无效,从而避免窗体执行最大化和还原操作。

---- WM_NCRBUTTONDOWN:在标题栏上按下鼠标右键消息。我们可以截住它,当在按钮区域双击时,我们就该使其无效,从而避免弹出窗体按制菜单。

---- WM_NCMOUSEMOVE:在标题栏上移动鼠标消息。我们可以截住它,当鼠标移出按钮区域时,我们就必须画出按钮没有被按下,即凸起时的样子。

---- WM_NCACTIVATE:当标题栏在激活与非激活之间切换时收到该消息。我们可以截住它,当该窗口处理激活状态时,我们可以做一些事情,比如说将我们的标题栏按钮上的字体变灰或变黑来指示该窗口的当前状态。下面我没有加入该项功能,如果大家感兴趣的话,可以自己完成。

---- (大家从这里可以发现,标题栏的消息都是WM_NC开头的)
////////////////////////////////////////////////////////////////////////////////
unit Capbtn;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Buttons;

type
TTitleBtnForm = class(TForm)
procedure FormResize(Sender: TObject);
private
TitleButton : TRect;
procedure DrawTitleButton;
{Paint-related messages}
procedure WMSetText(var Msg : TWMSetText); message WM_SETTEXT;
procedure WMNCPaint(var Msg : TWMNCPaint); message WM_NCPAINT;
procedure WMNCActivate(var Msg : TWMNCActivate); message WM_NCACTIVATE;
{Mouse down-related messages}
procedure WMNCHitTest(var Msg : TWMNCHitTest); message WM_NCHITTEST;
procedure WMNCLButtonDown(var Msg : TWMNCLButtonDown); message

WM_NCLBUTTONDOWN;
function GetVerInfo : DWORD;
end;

var
TitleBtnForm: TTitleBtnForm;

const
htTitleBtn = htSizeLast + 1;

implementation
{$R *.DFM}

procedure TTitleBtnForm.DrawTitleButton;
var
bmap : TBitmap; {Bitmap to be drawn - 16 X 16 : 16 Colors}
XFrame, {X and Y size of Sizeable area of Frame}
YFrame,
XTtlBit, {X and Y size of Bitmaps in caption}
YTtlBit : Integer;
begin
{Get size of form frame and bitmaps in title bar}
XFrame := GetSystemMetrics(SM_CXFRAME);
YFrame := GetSystemMetrics(SM_CYFRAME);
XTtlBit := GetSystemMetrics(SM_CXSIZE);
YTtlBit := GetSystemMetrics(SM_CYSIZE);

{$IFNDEF WIN32}
TitleButton := Bounds(Width - (3 * XTtlBit) - ((XTtlBit div 2) - 2),
YFrame - 1,
XTtlBit + 2,
YTtlBit + 2);

{$ELSE} {Delphi 2.0 positioning}
if (GetVerInfo = VER_PLATFORM_WIN32_NT) then
TitleButton := Bounds(Width - (3 * XTtlBit) - ((XTtlBit div 2) - 2),
YFrame - 1,
XTtlBit + 2,
YTtlBit + 2)
else
TitleButton := Bounds(Width - XFrame - 4*XTtlBit + 2,
XFrame + 2,
XTtlBit + 2,
YTtlBit + 2);
{$ENDIF}


Canvas.Handle := GetWindowDC(Self.Handle); {Get Device context for drawing}
try
{Draw a button face on the TRect}
DrawButtonFace(Canvas, TitleButton, 1, bsAutoDetect, False, False, False);
bmap := TBitmap.Create;
bmap.LoadFromFile('help.bmp');
with TitleButton do
{$IFNDEF WIN32}
Canvas.Draw(Left + 2, Top + 2, bmap);
{$ELSE}
if (GetVerInfo = VER_PLATFORM_WIN32_NT) then
Canvas.Draw(Left + 2, Top + 2, bmap)
else
Canvas.StretchDraw(TitleButton, bmap);
{$ENDIF}

finally
ReleaseDC(Self.Handle, Canvas.Handle);
bmap.Free;
Canvas.Handle := 0;
end;
end;

{Paint triggering events}
procedure TTitleBtnForm.WMNCActivate(var Msg : TWMNCActivate);
begin
Inherited;
DrawTitleButton;
end;

procedure TTitleBtnForm.FormResize(Sender: TObject);
begin
Perform(WM_NCACTIVATE, Word(Active), 0);
end;

{Painting events}
procedure TTitleBtnForm.WMNCPaint(var Msg : TWMNCPaint);
begin
Inherited;
DrawTitleButton;
end;

procedure TTitleBtnForm.WMSetText(var Msg : TWMSetText);
begin
Inherited;
DrawTitleButton;
end;

{Mouse-related procedures}
procedure TTitleBtnForm.WMNCHitTest(var Msg : TWMNCHitTest);
begin
Inherited;
{Check to see if the mouse was clicked in the area of the button}
with Msg do
if PtInRect(TitleButton, Point(XPos - Left, YPos - Top)) then
Result := htTitleBtn;
end;

procedure TTitleBtnForm.WMNCLButtonDown(var Msg : TWMNCLButtonDown);
begin
inherited;
if (Msg.HitTest = htTitleBtn) then
ShowMessage('You pressed the new button');
end;

function TTitleBtnForm.GetVerInfo : DWORD;
var
verInfo : TOSVERSIONINFO;
begin
verInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
if GetVersionEx(verInfo) then
Result := verInfo.dwPlatformID;
{Returns:
VER_PLATFORM_WIN32s Win32s on Windows 3.1
VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95
VER_PLATFORM_WIN32_NT Windows NT }
end;

end.
加载更多回复(9)

13,871

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧