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; } //=============================================================================
相关文章推荐
- 在低版本android系统上实现Material design应用
- 枚举类(一)
- Java JDBC基本操作(增,删,改,查)总结
- HDU5584(lcm&gcd)
- 《自控力》读书笔记
- 个人感想之“需求分析”
- Bootstrip 的select的数据绑定问题
- APIO2016 游(gun cu)记
- spring4 4000 +springmvc4+hibernate4集成框架流程:
- JavaScript 检查某元素是否有某属性 elementSupportAttribute(elementName,attribute) JavaScript扩展
- NYOJ 1009 So Easy[Ⅰ]
- 【HTTP指南】杂
- 链表——删除链表中倒数第n个结点(时间复杂度为O (n))
- 并发编程 - Guarded Suspension模式
- duplicate 数据库 from active database [oracle 11.2.0.3 + asm] => [oracle 11.2.0.3 + asm]
- 软件体系结构 UML设计
- XMG Quartz2D 设置裁剪区域
- Spark中文手册4:Spark之基本概念(2)
- C++第五次上机作业
- 用递归写排列组合问题