思勤无邪

上学时,因我年龄最小,个头也最小,上课时,就像大猩猩堆里的猴一般。如今,这猴偶尔也把最近的一些情况写在这里。

   :: 首页 :: 联系 :: 聚合  :: 管理
  132 Posts :: 1 Stories :: 178 Comments :: 0 Trackbacks

公告

     吾日常三省吾身,曰思、曰勤、曰无邪。

积分与排名

  • 积分 - 157358
  • 排名 - 142

最新随笔

最新评论

阅读排行榜

评论排行榜


    闲时顺手翻了翻《Windows Graphics Programming》,发现里面的示例代码很不错,对设计应用程序框架和理解现有的应用程序框架很有帮助(尤其是MFC)。先来看一个很简单的用面向对象的思想包装API函数的KWindow类。示例代码贴出来,申明一下,代码不是我写的,但有可能做一些改动,加了很多罗嗦的注释,只是想节约以后阅读的时间。

    下载示例project

    KWindow类需要完成注册窗口、创建窗口、处理窗口消息等用API编写程序时要处理的任务。由于每个窗口类对不同的消息会有不同的处理,所以首先想到了消息处理函数采用虚函数来实现(这种方式缺点是消息太多会使虚函数表过大,MFC采用消息映射,这里只是为了简单),因为虚函数肯定是成员函数,有this指针,Win32 API不能把一个虚函数作为窗口消息处理函数。通常的解决办法是采用静态函数,在这个静态函数里在想办法产生一个指向代表当前窗口的KWindow实例的指针来调用对应窗口的消息处理函数。
// win.h
#pragma once
// 以K开头来命名类,是希望与MFC有明显区别
class KWindow
{
protected:
    
// 处理WM_PAINT消息,由WndProc调用
    virtual void OnDraw(HDC hDC)
    
{
    }

    
// 处理WM_KEYDOWN消息,由WndProc调用
    virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
    
{
    }

    
// 真正的消息分发/处理函数
    virtual LRESULT WndProc(HWND hWnd, UINT uMsg,
        WPARAM wParam, LPARAM lParam);
    
// API中注册的消息处理函数,不能是成员函数,因为成员函数有this指针
    static LRESULT CALLBACK WindowProc(HWND hWnd,
        UINT uMsg, WPARAM wParam, LPARAM lParam);
    
// 派生类可以在这里修改窗口的属性,如图标、菜单等
    virtual void GetWndClassEx(WNDCLASSEX & wc);
public:
    
// 保存该窗口对应的HWND
    HWND  m_hWnd;
    
// m_hWnd 由CreateEx成员函数调用API函数CreateWindowEx赋值
    KWindow(void)
    
{
        m_hWnd 
= NULL;
    }

    
// destructor
    virtual ~KWindow(void)
    
{
    }

    
// 调用API函数CreateWindowEx创建窗口
    virtual bool CreateEx(DWORD dwExStyle,
        LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
        
int x, int y, int nWidth, int nHeight, HWND hParent,
        HMENU hMenu, HINSTANCE hInst);
    
// 注册窗口
    bool RegisterClass(LPCTSTR lpszClass, HINSTANCE hInst);
    
// 消息循环
    virtual WPARAM MessageLoop(void);

    BOOL ShowWindow(
int nCmdShow) const
    
{
        
return ::ShowWindow(m_hWnd, nCmdShow);
    }


    BOOL UpdateWindow(
voidconst
    
{
        
return ::UpdateWindow(m_hWnd);
    }

}
;

// win.cpp
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include 
<windows.h>
#include 
<assert.h>
#include 
<tchar.h>
#include 
".\win.h"

// 真正的消息分发/处理函数
LRESULT KWindow::WndProc(HWND hWnd, UINT uMsg,
                         WPARAM wParam, LPARAM lParam)
{
    
switch( uMsg )
    
{
    
case WM_KEYDOWN:
        OnKeyDown(wParam, lParam);
        
return 0;
    
case WM_PAINT:
        
{
            PAINTSTRUCT ps;

            BeginPaint(m_hWnd, 
&ps);
            OnDraw(ps.hdc);
            EndPaint(m_hWnd, 
&ps);
        }

        
return 0;
    
case WM_DESTROY:
        PostQuitMessage(
0);
        
return 0;
    }


    
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


// API中注册的消息处理函数,将操作系统的消息分发到正确的KWindow对象
LRESULT CALLBACK KWindow::WindowProc(HWND hWnd, UINT uMsg,
                                     WPARAM wParam, LPARAM lParam)
{
    KWindow 
* pWindow;

    
if ( uMsg == WM_NCCREATE )    // 窗口创建时收到的第一个消息
    {
        
// 通过lParam找出该窗口对应的KWindow指针,并调用
        
// SetWindowLong(GWL_USERDATA)保存
        assert( ! IsBadReadPtr((void *) lParam,
            
sizeof(CREATESTRUCT)) );
        MDICREATESTRUCT 
* pMDIC = (MDICREATESTRUCT *)
            ((LPCREATESTRUCT) lParam)
->lpCreateParams;
        pWindow 
= (KWindow *) (pMDIC->lParam);

        assert( 
! IsBadReadPtr(pWindow, sizeof(KWindow)) );
        SetWindowLong(hWnd, GWL_USERDATA, (LONG) pWindow);
    }

    
else
    
{
        
// 调用GetWindowLong(GWL_USERDATA)找回在WM_NCCREATE消息中保存的
        
// KWindow指针
        pWindow=(KWindow *)GetWindowLong(hWnd, GWL_USERDATA);
    }


    
if ( pWindow )
    
{
        
return pWindow->WndProc(hWnd, uMsg, wParam, lParam);
    }

    
else
    
{
        
return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }

}


bool KWindow::RegisterClass(LPCTSTR lpszClass, HINSTANCE hInst)
{
    WNDCLASSEX wc;

    
if ( ! GetClassInfoEx(hInst, lpszClass, &wc) )
    
{
        GetWndClassEx(wc);

        wc.hInstance     
= hInst;
        wc.lpszClassName 
= lpszClass;
        
if ( !RegisterClassEx(&wc) )
            
return false;
    }


    
return true;
}


bool KWindow::CreateEx(DWORD dwExStyle,
                       LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
                       
int x, int y, int nWidth, int nHeight, HWND hParent,
                       HMENU hMenu, HINSTANCE hInst)
{
    
if ( ! RegisterClass(lpszClass, hInst) )
        
return false;

    
// use MDICREATESTRUCT to pass this pointer, support MDI child window
    MDICREATESTRUCT mdic;
    memset(
& mdic, 0sizeof(mdic));
    mdic.lParam 
= (LPARAM) this;
    m_hWnd 
= CreateWindowEx(dwExStyle, lpszClass, lpszName,
        dwStyle, x, y, nWidth, nHeight,
        hParent, hMenu, hInst, 
& mdic);

    
return m_hWnd != NULL;
}


// 派生类中可以改写默认属性
void KWindow::GetWndClassEx(WNDCLASSEX & wc)
{
    memset(
& wc, 0sizeof(wc));

    wc.cbSize        
= sizeof(WNDCLASSEX);
    wc.style         
= 0;
    wc.lpfnWndProc   
= WindowProc;
    wc.cbClsExtra    
= 0;
    wc.cbWndExtra    
= 0;
    wc.hInstance     
= NULL;
    wc.hIcon         
= NULL;
    wc.hCursor       
= LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground 
= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  
= NULL;
    wc.lpszClassName 
= NULL;
    wc.hIconSm       
= NULL;
}


// Message Loop
WPARAM KWindow::MessageLoop(void)
{
    MSG msg;

    
while ( GetMessage(&msg, NULL, 00) )
    
{
        TranslateMessage(
&msg);
        DispatchMessage(
&msg);
    }


    
return msg.wParam;
}


// Hello.cpp
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include 
<windows.h>
#include 
<assert.h>
#include 
<tchar.h>

#include 
"win.h"

const TCHAR szMessage[] = _T("Hello, World !");
const TCHAR szFace[]    = _T("Times New Roman");
const TCHAR szHint[]    = _T("Press ESC to quit.");
const TCHAR szProgram[] = _T("HelloWorld3");

// copy CenterText from Hello2.cpp

class KHelloWindow : public KWindow
{
    
void CenterText(HDC hDC, int x, int y, LPCTSTR szFace,
        LPCTSTR szMessage, 
int point)
    
{
        HFONT hFont 
= CreateFont(
            point 
* GetDeviceCaps(hDC, LOGPIXELSY) / 72,
            
000, FW_BOLD, TRUE, FALSE, FALSE,
            ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
            PROOF_QUALITY, VARIABLE_PITCH, szFace);
        assert(hFont);

        HGDIOBJ hOld 
= SelectObject(hDC, hFont);

        SetTextAlign(hDC, TA_CENTER 
| TA_BASELINE);

        SetBkMode(hDC, TRANSPARENT);
        SetTextColor(hDC, RGB(
000xFF));
        TextOut(hDC, x, y, szMessage, _tcslen(szMessage));
        SelectObject(hDC, hOld);
        DeleteObject(hFont);
    }


    
void OnKeyDown(WPARAM wParam, LPARAM lParam)
    
{
        
if (wParam==VK_ESCAPE )
        
{
            PostMessage(m_hWnd, WM_CLOSE, 
00);
        }

    }


    
void OnDraw(HDC hDC)
    
{
        TextOut(hDC, 
00, szHint, lstrlen(szHint));
        CenterText(hDC, GetDeviceCaps(hDC, HORZRES)
/2,
            GetDeviceCaps(hDC, VERTRES)
/2,
            szFace, szMessage, 
72);
    }


    
// 修改默认窗口属性
    void GetWndClassEx(WNDCLASSEX & wc)
    
{
        memset(
& wc, 0sizeof(wc));

        wc.cbSize        
= sizeof(WNDCLASSEX);
        wc.style         
= 0;
        wc.lpfnWndProc   
= WindowProc;
        wc.cbClsExtra    
= 0;
        wc.cbWndExtra    
= 0;
        wc.hInstance     
= NULL;
        wc.hIcon         
= NULL;
        wc.hCursor       
= LoadCursor(NULL, IDC_ARROW);
        
// 将背景画刷改为透明
        wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
        wc.lpszMenuName  
= NULL;
        wc.lpszClassName 
= NULL;
        wc.hIconSm       
= NULL;
    }


public:

}
;

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE,
                   LPSTR lpCmd, 
int nShow)
{
    KHelloWindow win;

    win.CreateEx(
0, szProgram, szProgram, WS_POPUP, 00,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        NULL, NULL, hInst);

    win.ShowWindow(nShow);
    win.UpdateWindow();

    
return win.MessageLoop();
}

posted on 2007-06-02 12:36 思勤无邪 阅读(1758) 评论(1)  编辑 收藏 引用 所属分类: C++

Feedback

# re: 一个简单的不依靠MFC的面向对象的Windows程序 2008-05-20 20:00 路过
基本上没有封装,消息处理的太难看了  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理