您的位置:首页 > 其它

Windows Dev Intro - Subclassed Button Control

2016-05-09 21:13 411 查看
http://winapi.foosyerdoos.org.uk/code/subsuperclass/htm/subclassbtn.php

//=============================================================================
//SUBCLASSED CONTROLS: BUTTON - Copyright © 2000,2006 Ken Fitlike
//=============================================================================
//API functions used: CallWindowProc,CreateWindowEx,DefWindowProc,
//DestroyWindow,DispatchMessage,GetClientRect,GetDC,GetMessage,
//GetSystemMetrics,GetTextExtentPoint32,GetWindowLongPtr,GetWindowText,
//InvalidateRect,LoadImage,MessageBox,PostQuitMessage,RegisterClassEx,
//ReleaseDC,SendMessage,SetFocus,SetWindowLongPtr,SetWindowText,ShowWindow,
//UpdateWindow,TranslateMessage,WinMain.
//=============================================================================
//Demonstrates subclassing of button control. This uses the traditional
//approach to window subclassing by employing the SetWindowLongPtr api
//function to change the default, system window procedure to the user-defined
//one. This technique can be used with win9x and later operating systems.
//=============================================================================
#include <windows.h>  //include all the basics
#include <tchar.h>    //string and other mapping macros
#include <string>
#include <vector>

//define an unicode string type alias
typedef std::basic_string<TCHAR> ustring;
//=============================================================================
//main window message handling function declarations
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int OnCreate(const HWND,CREATESTRUCT*);

//subclassed button message handling function declarations
LRESULT CALLBACK BtnProc(HWND,UINT,WPARAM,LPARAM);
HWND OnRightClick(const HWND);
void OnMouseClick(const HWND,const HWND);

HWND CreateControl(const HWND,const HINSTANCE,DWORD,const RECT&,const int,
const ustring&,const ustring& classname);
inline int ErrMsg(const ustring&);

//setup control id's
enum {
IDC_BUTTON=200,
IDC_EDIT
};
//=============================================================================
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR pStr,int nCmd)
{
ustring classname=_T("SIMPLEWND");
WNDCLASSEX wcx={0};  //used for storing information about the wnd 'class'

wcx.cbSize         = sizeof(WNDCLASSEX);
wcx.lpfnWndProc    = WndProc;             //wnd Procedure pointer
wcx.hInstance      = hInst;               //app instance
//use 'LoadImage' to load wnd class icon and cursor as it supersedes the
//obsolete functions 'LoadIcon' and 'LoadCursor', although these functions will
//still work. Because the icon and cursor are loaded from system resources ie
//they are shared, it is not necessary to free the image resources with either
//'DestroyIcon' or 'DestroyCursor'.
wcx.hIcon         = reinterpret_cast<HICON>(LoadImage(0,IDI_APPLICATION,
IMAGE_ICON,0,0,LR_SHARED));
wcx.hCursor       = reinterpret_cast<HCURSOR>(LoadImage(0,IDC_ARROW,
IMAGE_CURSOR,0,0,LR_SHARED));
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1);
wcx.lpszClassName = classname.c_str();
//the window 'class' (not c++ class) has to be registered with the system
//before windows of that 'class' can be created
if (!RegisterClassEx(&wcx))
{
ErrMsg(_T("Failed to register wnd class"));
return -1;
}

int desktopwidth=GetSystemMetrics(SM_CXSCREEN);
int desktopheight=GetSystemMetrics(SM_CYSCREEN);

HWND hwnd=CreateWindowEx(0,                     //extended styles
classname.c_str(),     //name: wnd 'class'
_T("Subclassed Button Control"), //wnd title
WS_OVERLAPPEDWINDOW,   //wnd style
desktopwidth/4,        //position:left
desktopheight/4,       //position: top
desktopwidth/2,        //width
desktopheight/2,       //height
0,                     //parent wnd handle
0,                     //menu handle/wnd id
hInst,                 //app instance
0);                    //user defined info
if (!hwnd)
{
ErrMsg(_T("Failed to create wnd"));
return -1;
}

ShowWindow(hwnd,nCmd);
UpdateWindow(hwnd);
//start message loop - windows applications are 'event driven' waiting on user,
//application or system signals to determine what action, if any, to take. Note
//that an error may cause GetMessage to return a negative value so, ideally,
//this result should be tested for and appropriate action taken to deal with
//it(the approach taken here is to simply quit the application).
MSG msg;
while (GetMessage(&msg,0,0,0)>0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
//=============================================================================
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
return OnCreate(hwnd,reinterpret_cast<CREATESTRUCT*>(lParam));
case WM_DESTROY:
PostQuitMessage(0);    //signal end of application
return 0;
default:
//let system deal with msg
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
}
//=============================================================================
int OnCreate(const HWND hwnd,CREATESTRUCT *cs)
{
//handles the WM_CREATE message of the main, parent window; return -1 to fail
//window creation
RECT rc={10,10,260,40};
//the various button types are created by simply varying the style bits
HWND hBtn=CreateControl(hwnd,cs->hInstance,BS_DEFPUSHBUTTON,rc,IDC_BUTTON,
_T("Right-click to edit this caption"),_T("button"));

//subclass the button control
WNDPROC OldBtnProc=reinterpret_cast<WNDPROC>(static_cast<LONG_PTR>(
SetWindowLongPtr(hBtn,GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(BtnProc))));

//store the original, default window procedure of the button as the button
//control's user data
SetWindowLongPtr(hBtn,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(OldBtnProc));

SetFocus(hBtn);
return 0;
}
//=============================================================================
HWND CreateControl(const HWND hParent,const HINSTANCE hInst,DWORD dwStyle,
const RECT& rc,const int id,const ustring& caption,
const ustring& classname)
{
dwStyle|=WS_CHILD|WS_VISIBLE;
return CreateWindowEx(0,                            //extended styles
classname.c_str(),            //control 'class' name
caption.c_str(),              //control caption
dwStyle,                      //control style
rc.left,                      //position: left
rc.top,                       //position: top
rc.right,                     //width
rc.bottom,                    //height
hParent,                      //parent window handle
//control's ID
reinterpret_cast<HMENU>(static_cast<INT_PTR>(id)),
hInst,                        //application instance
0);                           //user defined info
}
//=============================================================================
inline int ErrMsg(const ustring& s)
{
return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
}
//=============================================================================
//subclassed button window procedure and message handling functions
//=============================================================================
LRESULT CALLBACK BtnProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
//This is the subclass window procedure for the button. If the mouse is
//right-clicked on the button then a single line, flat edit control is created
//and the button caption copied into it. Any other mouse message (except
//movement) on the button results in the edit's text being copied as the button
//caption. The edit control is then destroyed.
static HWND hEdit;
//retrieve the previously stored original button window procedure
static WNDPROC OrigBtnProc=reinterpret_cast<WNDPROC>(static_cast<LONG_PTR>(
GetWindowLongPtr(hwnd,GWLP_USERDATA)));
switch (uMsg)
{
//if any of the following mouse events occur, check if the edit control
//exists. If it does then copy its text to the button caption before
//destroying the edit control.
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
{
OnMouseClick(hwnd,hEdit);
//ensure default message handling occurs
return CallWindowProc(OrigBtnProc,hwnd,uMsg,wParam,lParam);
}
//mouse button right-click event
case WM_RBUTTONDOWN:
{
if (!IsWindow(hEdit))
{
hEdit=OnRightClick(hwnd);
}
return 0;
}
default:
//call the default system handler for the control (button)
return CallWindowProc(OrigBtnProc,hwnd,uMsg,wParam,lParam);
}
}
//=============================================================================
void OnMouseClick(const HWND hwnd,const HWND hEdit)
{
//event handler for all mouse click messages except WM_RBUTTONDOWN
//(right-click)
//check if the edit control exists. If it does then copy its text to the button
//caption before destroying the edit control.

if (IsWindow(hEdit))
{
const int MAX_TXT_LEN=64;
//get the edit text
std::vector<TCHAR> tmp(MAX_TXT_LEN);
tmp.push_back(_T('\0'));

if (GetWindowText(hEdit,&tmp[0],MAX_TXT_LEN))
{
SetWindowText(hwnd,&tmp[0]);
}
DestroyWindow(hEdit);
InvalidateRect(hwnd,0,1);    //ensure button is completely redrawn
}
}
//=============================================================================
HWND OnRightClick(const HWND hwnd)
{
//mouse button right-click event handler. Return handle of the edit control
//get the button text and its dimensions
const int MAX_TXT_LEN=64;
std::vector<TCHAR> tmp(MAX_TXT_LEN);
tmp.push_back(_T('\0'));

int t=GetWindowText(hwnd,&tmp[0],MAX_TXT_LEN);

SIZE sz={0};
HDC hdc=GetDC(hwnd);
GetTextExtentPoint32(hdc,&tmp[0],t+1,&sz);
ReleaseDC(hwnd,hdc);

//to ensure edit control is created with a usable minimum width
//get width of eg. 4 characters.
int nMin=(sz.cx/(static_cast<int>(tmp.size())))*4;
if (sz.cx<nMin)
{
sz.cx=nMin;
}
sz.cy+=4;    //ensure a decent border around edit control's text
//get button dimensions and adjust those values based on text
//dimensions to calculate edit control's dimensions.
RECT  rc={0};
GetClientRect(hwnd,&rc);
rc.top=(rc.bottom-sz.cy)/2;

rc.left=(rc.right-sz.cx)/2;
rc.right=sz.cx;
rc.bottom=sz.cy;
//create a flat, single line edit control and ensure its width has a
//reasonable minimum value.
HINSTANCE hInst=reinterpret_cast<HINSTANCE>(static_cast<LONG_PTR>(
GetWindowLongPtr(hwnd,GWLP_HINSTANCE)));
HWND hEdit=CreateControl(hwnd,hInst,WS_BORDER|ES_AUTOHSCROLL,rc,IDC_EDIT,
&tmp[0],_T("edit"));
//highlight the text and set focus on the edit control
SendMessage(hEdit,EM_SETSEL,0,static_cast<LPARAM>(-1));
SetFocus(hEdit);
return hEdit;
}
//=============================================================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: