wtl界面2

CreateStatusWindowOnCreate中创建状态窗口.在处理WM_SIZE时,调整大小.atl未包装绘画.
atl通过宏处理了WM_COMMAND/WM_NOTIFY.用COMMAND_ID_HANDLER处理菜单命令.
atl未注册类及窗口过程.
atl允许但不支持mdi,多sdi,文管应用,常见控件,ddx,gdi,等,因而用wtl.
sdi三步:1,继承CFrameWindowImpl,2,加DECLARE_FRAME_WND_CLASS宏,指定工具栏和菜单的资标,3,加(消息映射,处理器,且链至基类).

class CMainFrame : public CFrameWindowImpl<CMainFrame> {
public:
  DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
  BEGIN_MSG_MAP(CMainFrame)
    MESSAGE_HANDLER(WM_PAINT,OnPaint)
    MESSAGE_HANDLER(WM_CREATE,OnCreate)
    COMMAND_ID_HANDLER(ID_FILE_EXIT,OnFileExit)
    COMMAND_ID_HANDLER(ID_HELP_ABOUT,OnAbout)
    CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
  END_MSG_MAP()
  LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
    CreateSimpleToolBar();
    CreateSimpleStatusBar();
    return 0;
  }
  LRESULT OnFileExit(WORD,WORD wID, HWND,BOOL&) {
    SendMessage(WM_CLOSE);//框架发送提交退出消息
    return0L;
  }
...
};

你可关联串表中的串与资标.以用作帧标题/菜单资源/加速表/图标.创建帧时,除工具栏外,自动加载带常见资标资源.状态栏不需要关联资源.
CHAIN_MSG_MAP链至基类,基类处理WM_SIZE(调整大小)/WM_DESTROY(退出).
CAppModule继承CComModule,并加了可变数量消息循环.用用常见资标来加载资源.
atl允许一线程一消息队列.工具/菜单栏过时了,用命令栏.

LRESULT CMainFrame::OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
  //m_CmdBar :在AtlCtrlw.h中定义的C命令栏控件,
  HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,0,ATL_SIMPLE_CMDBAR_PANE_STYLE);
  //命令栏替换当前目录
  m_CmdBar.AttachMenu(GetMenu());//附加菜单
  m_CmdBar.LoadImages(IDR_MAINFRAME);
  SetMenu(NULL);
  //创建简单工具栏
  HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd,IDR_MAINFRAME,FALSE,ATL_SIMPLE_TOOLBAR_PANE_STYLE);//父窗口为主框架
  CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
  AddSimpleReBarBand(hWndCmdBar);
  AddSimpleReBarBand(hWndToolBar,NULL, TRUE);
  CreateSimpleStatusBar();
  return 0;
}

命令栏用工具栏位图,并映射到命令标识.
SetMenu(NULL)去掉默认菜单.wtl客户区视图是独立子窗口.视图展现.同分割栏/mdi一起用时,这种抽象很方便.
HWND就是视图.WM_CREATEm_hWndClient=HWND.

class CBitmapView : public CWindowImpl<CBitmapView>
{
public:
    CBitmapView();
    ~CBitmapView();
    BEGIN_MSG_MAP(CBitmapView)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
    END_MSG_MAP()
    LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&);
private:
    HBITMAP m_hBmp;
};

移动我们简单sdi绘画功能给视图,则如上.使用时:

LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
    ...
    // 创建视图View (m_view是CBitmapView类型)
    m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE, WS_EX_CLIENTEDGE);
    return 0;
}

这样,视图与周围完美整合.
如果你想按继承atl窗口包装类,有C++方法和窗口方法.WTLDocView示例中可参考相应类.
加最近文档:

LRESULT CMainFrame::OnFileOpen(WORD, WORD, HWND, BOOL&)
{
    if (m_dlgOpen.DoModal(m_hWnd) == IDOK)
    {
        // 试着打开文件
        ...
        if (bFileOpened)
        {
            m_mru.AddToList(m_dlgOpen.m_bstrName);
        }
    }
    return 0;
}

mru区间为ID_FILE_MRU_FIRST->ID_FILE_MRU_LAST,用COMMAND_RANGE_HANDLER来处理区间.用GetFromList取名.再调用MoveToTop/RemoveFromList(是否打开).

LRESULT CMainFrame::OnOpenUsingMRU(WORD, WORD wID, HWND, BOOL&)
{
    TCHAR szDocument[MAX_PATH];
    m_mru.GetFromList(wID, szDocument);
    //试打开
    ...
    if (bFileOpened)
    m_mru.MoveToTop(wID);
    else
    m_mru.RemoveFromList(wID);
    return 0;
}

关闭时,写入注册表.

void CMainFrame::OnFinalMessage(HWND /*hWnd*/)
{
    m_mru.WriteToRegistry(_T("Software\\MyCompany\\MyCoolApp"));
    ::PostQuitMessage(0);
}

wtl的线管:

class CThreadManager
{
public:
    struct _RunData // 线程初始化参数
    {
        LPTSTR lpstrCmdLine;
        int nCmdShow;
    };
    DWORD m_dwCount; // 线程数
    HANDLE m_arrThreadHandles[MAXIMUM_WAIT_OBJECTS - 1];
    CThreadManager() : m_dwCount(0) {}
    DWORD AddThread(LPTSTR lpstrCmdLine, int nCmdShow);
    void RemoveThread(DWORD dwIndex);
    int Run(LPTSTR lpstrCmdLine, int nCmdShow);
};
//主中实例化
int WINAPI WinMain(...)
{
    hRes = _Module.Init(NULL, hInstance);
    CThreadManager mgr;
    int nRet = mgr.Run(lpstrCmdLine, nCmdShow);//在其完成后,就退出
    _Module.Term();
    return nRet;
}
//跑
int CThreadManager::Run(LPTSTR lpstrCmdLine, int nCmdShow){
    MSG msg;
    ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // 强迫创建消息队列
    AddThread(lpstrCmdLine, nCmdShow);//传递地址,创建线程
    int nRet = m_dwCount;DWORD dwRet;
    while(m_dwCount > 0){
        dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles, FALSE, INFINITE, QS_ALLINPUT);
        if(dwRet == 0xFFFFFFFF){
            ::MessageBox(NULL, _T("ERROR: Wait for multiple objects failed!!!"), _T("MultiSDI_HTMLView"), MB_OK);
        }
        else if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1))
        {
            RemoveThread(dwRet - WAIT_OBJECT_0);
        }
        else if(dwRet == (WAIT_OBJECT_0 + m_dwCount))
        {
            ::GetMessage(&msg, NULL, 0, 0);
            if(msg.message == WM_USER)
                AddThread("", SW_SHOWNORMAL);
            else
                ::MessageBeep((UINT)-1);
        }
        else
            ::MessageBeep((UINT)-1);
    }
    return nRet;
}

RunThread是线管的静态成员函数.其创建SDI框架窗口,用传递给WinMain()的显式命令参数调用::ShowWindow()函数,并运行循环.
OnFinalMessage中调用来删自身(允许子窗口释放资源).
CMDIFrameWindowImpl类实现MDI框架窗口和MDI子窗口.

class CMainFrame : public CMDIFrameWindowImpl<CMainFrame>
{
public:
DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
BEGIN_MSG_MAP(CMainFrame)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
    COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
    COMMAND_ID_HANDLER(ID_WINDOW_CASCADE, OnWindowCascade)
    ...
    CHAIN_MSG_MAP(CMDIFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
    LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
    {
        // 创建命令条窗口,工具条和状态条
        ...
        // 创建MDI客户
        CreateMDIClient();//创建
        m_CmdBar.SetMDIClient(m_hWndMDIClient);//置客户
        ...
        return 0;
    }
    LRESULT OnFileNew(WORD, WORD, HWND, BOOL&)
    {
        // 创建MDI子窗口
        CChildFrame* pChild = new CChildFrame;
        pChild->CreateEx(m_hWndMDIClient);//创建,加入父窗口
        return 0;
    }
    LRESULT OnWindowCascade(WORD,WORD,HWND, BOOL&)
    {
        MDICascade();
        return 0;
    }
    ...
};
template <class T, bool t_bVertical = true>
class CSplitterImpl
{...
    BEGIN_MSG_MAP(thisClass)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
        MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
        if(IsInteractive())
        {
        MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
        MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
        MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
        MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
        }
        MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
        MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
        MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
    END_MSG_MAP()
    ...
};
//
class CMainFrame :
public CFrameWindowImpl<CMainFrame>,
public CSplitterImpl<CMainFrame,true>
{
public:
    DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
    typedef CFrameWindowImpl<CMainFrame> winbaseClass;
    typedef CSplitterImpl< CMainFrame,true> splitbaseClass;
    BEGIN_MSG_MAP(CMainFrame)
        ...
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
        MESSAGE_HANDLER(WM_SIZE, OnSize)
        CHAIN_MSG_MAP(splitbaseClass)
    END_MSG_MAP()
    //...
private: //分隔窗口的2个窗格
    CHtmlView m_ViewLeft;
    CHtmlView m_ViewRight;
    ...
};

SetSplitterPanes分隔,SetSplitterPos来初化.

LRESULT CMainFrame::OnCreate(UINT, WPARAM,LPARAM, BOOL& bHandled)
{
    ...
    // 首先是2个视图(窗格)
    m_ViewLeft.Create(m_hWnd, rcDefault, _T("http://www.sellsbrothers.com/tools"), WS_CHILD |WS_VISIBLE | WS_CLIPSIBLINGS, WS_EX_STATICEDGE);
    m_ViewRight.Create(m_hWnd, rcDefault, _T("http://www.sellsbrothers.com/comfun"), WS_CHILD |WS_VISIBLE | WS_CLIPSIBLINGS|WS_VSCROLL | WS_CLIPCHILDREN, WS_EX_STATICEDGE);//创建视图
    SetSplitterPanes(m_ViewLeft, m_ViewRight); // 链接分隔窗口与窗格
    RECT rc;GetClientRect(&rc);//设置初化位置
    SetSplitterPos((rc.right - rc.left) / 4);
    bHandled = FALSE;
    return 0;
}
LRESULT CMainFrame::OnSize(UINT, WPARAM wParam, LPARAM, BOOL& bHandled)
{
    if(wParam != SIZE_MINIMIZED)
    {
        RECT rc;
        GetClientRect(&rc);
        RECT rcBar;
        ::GetClientRect(m_hWndToolBar,&rcBar);
        rc.top = rcBar.bottom;
        SetSplitterRect(&rc);
    }
    bHandled = FALSE;
    return 1;
}

削除调整大小时抖动,处理WM_ERASEBKGND时,屏蔽默认消息处理.其用窗口类背景刷来删除背景,带来不必要的抖动.OnEraseBackground返回1即可.用CSplitterWindowImpl类帮我们处理WM_ERASEBKGND和WM_SIZE.链入CSplitterImpl消息,WM_NOTIFY,WM_COMMAND,WM_*SCROLL并前向通知给父窗口.

template <class T, bool t_bVertical = true, class TBase = CWindow, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CSplitterWindowImpl :
public CWindowImpl< T, TBase, TWinTraits >,
public CSplitterImpl< CSplitterWindowImpl<T , t_bVertical, TBase, TWinTraits >, t_bVertical>
{
public:
    DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
    typedef CSplitterWindowImpl< T , t_bVertical, TBase, TWinTraits > thisClass;
    typedef CSplitterImpl< CSplitterWindowImpl<T,t_bVertical,TBase, TWinTraits >, t_bVertical>baseClass;
    BEGIN_MSG_MAP(thisClass)
        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
        MESSAGE_HANDLER(WM_SIZE, OnSize)
        CHAIN_MSG_MAP(baseClass)
        FORWARD_NOTIFICATIONS()
    END_MSG_MAP()
    LRESULT OnEraseBackground(UINT,WPARAM, LPARAM, BOOL&){return 1;}
    LRESULT OnSize(UINT, WPARAM wParam, LPARAM, BOOL& bHandled)
    {
        if(wParam != SIZE_MINIMIZED)SetSplitterRect();
        bHandled = FALSE;
        return 1;
    }
};

CSplitterWindow和CHorSplitterWindow分割器来包含窗口控件.

class ATL_NO_VTABLE CFooControl : public CComObjectRootEx<CComSingleThreadModel>,
public CComControl<CFooControl>,...
{//com控件.
    CFooControl()
    {
        m_bWindowOnly = TRUE;
    }
    BEGIN_MSG_MAP(CFooControl)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        CHAIN_MSG_MAP(CComControl<CFooControl>)
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()
    // 消息处理和其它手动操作
private:
    CSplitterWindow m_splitter;
    CHtmlView m_LeftView;
    CHtmlView m_RightView;
};

创建方法:

LRESULT CFooControl::OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
    AtlAxWinInit();
    // 创建左边与右边视图
    m_LeftView.Create(m_hWnd, rcDefault, _T("http://www.microsoft.com"),WS_CHILD | WS_VISIBLE |WS_CLIPSIBLINGS | WS_CLIPCHILDREN,WS_EX_STATICEDGE);
    m_RightView.Create(m_hWnd, rcDefault, _T("http://www.microsoft.com"),WS_CHILD | WS_VISIBLE |WS_CLIPSIBLINGS | WS_CLIPCHILDREN,WS_EX_STATICEDGE);
    RECT rect;
    GetClientRect(&rect);
    // 创建分隔窗口对象
    m_splitter.Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
    m_splitter.SetSplitterPanes(m_LeftView, m_RightView);//置2个
    m_splitter.SetSplitterPos((rect.right - rect.left) / 4);//
    return 0L;
}

m_cxyMin/SetSplitterPos限制分割器位置.

typedef CFontT<false> CFontHandle;
typedef CFontT<true> CFont;
template <bool t_bManaged>class CFontT
{
public:
    HFONT m_hFont; // 数据成员
    // 构造函数/析构函数/操作符
    CFontT(HFONT hFont = NULL) : m_hFont(hFont){}
    ~CFontT()
    {
        if(t_bManaged && m_hFont != NULL)
        DeleteObject();
    }//析构中检查
    CFontT<t_bManaged>& operator=(HFONT hFont)
    {
        m_hFont = hFont;
        return *this;
    }
    ...
};
class CPaintDC : public CDC
{
public:
    HWND m_hWnd;PAINTSTRUCT m_ps;
    CPaintDC(HWND hWnd)
    {
        m_hWnd = hWnd;
        m_hDC = ::BeginPaint(hWnd, &m_ps);
    }
    ~CPaintDC()
    {
        ::EndPaint(m_hWnd, &m_ps);
        Detach();
    }
};
//使用管理GDI封装类可相当简化GDI代码.举例来说,我们的位图视图可以简化为如下所示:
class CBitmapView : public CWindowImpl<CBitmapView>
{
public:
    CBitmapView()
    {
        m_bmp.LoadBitmap(MAKEINTRESOURCE(IDB_ATLWINDOWING));
    }
    BEGIN_MSG_MAP(CBitmapView)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
    END_MSG_MAP()
    LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&)
    {
        CPaintDC dc(m_hWnd);
        RECT rect;
        GetClientRect(&rect);
        CDC dcMem;
        dcMem.CreateCompatibleDC(dc);
        CBitmap bmpOld = dcMem.SelectBitmap(m_bmp);
        BITMAP bm;
        m_bmp.GetBitmap(&bm);
        SIZE size = { bm.bmWidth, bm.bmHeight };
        dc.BitBlt(rect.left, rect.top, size.cx, size.cy, dcMem, 0, 0, SRCCOPY);
        // 清除
        dcMem.SelectBitmap(bmpOld);
        return 0;
    }
private:
    CBitmap m_bmp;
};

动数交:

template <class T> class CWinDataExchange
{
public:
    //Dataexchange方法–在你的派生类中重载
    BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
    {
        // 这个函数从来不会调用,在你类中通过实现DDX映射重载它
        ATLASSERT(FALSE);
        return FALSE;
    }//继承该类并实现该函数
    ...
};

再映射:

class CStringDialog :
public CDialogImpl<CStringDialog>,
public CWinDataExchange<CStringDialog>
{//继承交换<T>,有个编辑框
public:
    CStringDialog() { *m_sz = 0; }
    enum { IDD = IDD_STRING };
    BEGIN_MSG_MAP(CStringDialog)
        COMMAND_ID_HANDLER(IDOK, OnOK)
        COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
        MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
    END_MSG_MAP()
    BEGIN_DDX_MAP(CMainDlg)
        DDX_TEXT(IDC_STRING, m_sz)
    END_DDX_MAP()
    LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
    {//初化时调用
        DoDataExchange(FALSE); // 转化到控件
        return 0;
    }
    LRESULT OnOK(WORD, WORD wID, HWND, BOOL&)
    {
        DoDataExchange(TRUE);//转化到数据成员
        EndDialog(wID);//好时,同步
        return 0L;
    }
    LRESULT OnCancel(WORD, WORD wID, HWND, BOOL&)
    {
        EndDialog(wID);
        return 0L;
    }
    public:
    enum { MAX_STRING = 128 };
    char m_sz[MAX_STRING+1];
};
LRESULT CMainFrame::OnFileTitle(WORD,WORD wID, HWND,BOOL&)
{
    CStringDialog dlg;
    GetWindowText(dlg.m_sz, dlg.MAX_STRING);
    if( dlg.DoModal() == IDOK )
    SetWindowText(dlg.m_sz);//类似这样
    return 0L;
}

WTL的DDX支持正/整/浮.wtl的ddx通过调用DoDataExchange手动触发.可只传递标识来同步单个控件,有灵活性.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值