wtl体系结构

应用程序类型 描述
sdi 单文本
多线程sdi 一进程,多窗口
mdi 框架内,多窗口
对话 基于对话框

多线程sdi新建sdi窗口,应用程序,都可作com服务器.钢筋条工具栏等的容器.命令栏可把窗口加至工具栏中.有了rebar,按工具栏实现工具条和菜单.这样,菜单也有关联图标.
可选视:

描述
简单窗口 处理WM_PAINT,直接画时.
表单 对话框模版,应用程序操作
列表框 加串.
编辑框 给你编辑
列表视 控制面板
树视 用于层级关系,
富文本 富文本

程序线程

atl,有个_Module,为CAppModule/CServerAppModule(com)实例.应用程序具1/多ui线程.单ui调用全局Run.

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
    CMessageLoop theLoop;
    _Module.AddMessageLoop(&theLoop);
    CMainFrame wndMain;
    if (wndMain.CreateEx() == NULL)
    {
        ATLTRACE(_T("创建主窗口失败"));
        return 0;
    }
    wndMain.ShowWindow(nCmdShow);
    int nRet = theLoop.Run();
    _Module.RemoveMessageLoop();
    return nRet;
}

CMessageLoop内循环消息.放入全局消息映射组.按线程索引.有过滤消息/处理空闲,界面元素可有自己的空闲处理.将自身加入消息循环的处理器数组中即可.Run包含主消息映射:

MSG m_msg;
int CMessageLoop::Run()
{
    for (;;)
    {
        while (!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
            DoIdleHandlers();//空闲
        bRet = ::GetMessage(&m_msg, NULL, 0, 0);
        if(bRet == -1)continue;
        else if(!bRet)break;
        if (!DoMessageFilters(&m_msg))
        {
            ::TranslateMessage(&m_msg);
            ::DispatchMessage(&m_msg);
        }//分发
    }
    return (int)m_msg.wParam;
}

多界面线程,则用wtl线程管理器.

int nRet = m_dwCount;
DWORD dwRet;
while(m_dwCount > 0)
{
    dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles,
        FALSE, INFINITE, QS_ALLINPUT);
    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(_T(""), SW_SHOWNORMAL);//加线程,加了就启动
    }
}

移出线程/收到WM_USER消息时,断开wait.也可在线管中加入自己的消息处理器.当有多种窗口类型时,要创建窗口,只需要任意窗口执行.

::PostThreadMessage(_Module.m_dwMainThreadID, WM_USER, 0, 0L);

界面线程,有个线程过程.线管用了MsgWaitForMultipleObjects,因而最多MAXIMUM_WAIT_OBJECTS(64)线程,最多63个窗口.

框架

wtl,两类窗口:框架/视图窗口.框架提供标题栏/边框,代码处理工具条/菜单.视图客户区.
线程创建主框架,在WM_CREATE中创建视图.sdi拥有个视图类,调用创建就好了.
MDI,则在CMDIFrameWindowImpl<>::CreateMDIClient()中建立叫MDICLIENT的窗口.将CMDIChildWindowImpl<>作为子窗口(有视图),即mdi1/多窗口(有边框/标题栏等).

LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
    //创建工具栏(命令栏)
    HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,
        NULL, 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();
    m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);//句柄.
    UIAddToolBar(hWndToolBar);//运行时改变
    UISetCheck(ID_VIEW_TOOLBAR, 1);
    UISetCheck(ID_VIEW_STATUS_BAR, 1);
    CMessageLoop* pLoop = _Module.GetMessageLoop();
    pLoop->AddMessageFilter(this);
    pLoop->AddIdleHandler(this);//两个过滤
    return 0;
}
class CMainFrame :
    public CFrameWindowImpl<CMainFrame>,
    public CUpdateUI<CMainFrame>,
    public CMessageFilter,
    public CIdleHandler
//主框架

CUpdateUI<>支持更新界面映射.

视图

class CMyView : public CWindowImpl<CMyView>
{
public:
    DECLARE_WND_CLASS(NULL)
    BOOL PreTranslateMessage(MSG* pMsg)
    {
        pMsg;return FALSE;
    }
    BEGIN_MSG_MAP(CMyView)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
    END_MSG_MAP()
    LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&)
    {
        CPaintDC dc(m_hWnd);//待办:加绘画代码
        return 0;
    }
};

多线程SDI和MDI差不多,但没有PreTranslateMessage方法.sdi利用它,在框架处理前分发处理消息,一般是转发消息给视图类.
要支持鼠标键盘,则加相应消息处理函数至消息映射.如果想基于控件,则加入AtlCtrls.h.
要加入滚动条:

class CMyView : public CScrollWindowImpl<CMyView>
{
public:
    typedef CScrollWindowImpl<CMyView> parent;
    BEGIN_MSG_MAP(CMyView)
        CHAIN_MSG_MAP(parent)//链上.
    END_MSG_MAP()
    void DoPaint(CDCHandle dc)//函数换了.
    {//画整个视图,不是`WM_PAINT`
    }
};

要指定滚动范围,大小或起点,要在WM_CREATE中初化.
框架窗口会改变视图窗口大小.你还可用分割器窗口,这样,一边树视,一边列视.
你要改变框架窗口,让分割器窗口作为视图.如框架中有:

CSplitterWindow m_view;
CTreeViewCtrl m_tree;
CListViewCtrl m_list;

创建时:

RECT rect;
GetClientRect(&rect);//取客户区.
m_hWndClient = m_view.Create(m_hWnd, rect,
    NULL, WS_CHILD | WS_VISIBLE);//视图创建客户
m_tree.Create(m_view, rcDefault, NULL,WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT,WS_EX_CLIENTEDGE);//树视
m_list.Create(m_view, rcDefault,NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT, WS_EX_CLIENTEDGE);//列视
m_view.SetSplitterPanes(m_tree, m_list);
m_view.SetSplitterPos();//无参时,中线为0,出现在最左边,隐藏了左窗口.

分割器视图一样,以框架父窗口,也可用rcDefault.在WM_SIZE时调整.
创建分割器窗口后,要创建子窗口,用SetSplitterPanes确定分割条位置.

更新界面

使能菜单,可带标记,或单选/多选.菜单可有图标和文字.运行时,都可改变.工具栏只是菜单的外化.因而可有效分组.更新界面让你指定哪些界面运行时可改变.通过更新界面宏来实现.

BEGIN_UPDATE_UI_MAP(CMainFrame)
    UPDATE_ELEMENT(ID_FILE_SAVERESULTS, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
    UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
    UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()

wtl建立数组来保存这些信息.
改变状态:

命令
菜单,工具条按钮 UIEnable
勾号 UISetCheck
菜单文字 UISetText
选入选出 UISetRadio/UISetCheck

如:

BOOL bSelected = GetSelected();//条件
//是否选中文本.
UIEnable(ID_EDIT_CUT, bSelected);//是否允许

可放入相应处理函数/OnIdle中,检查类变量来决定元素状态.
还要确定,是否都更新了,调用CUpdateUI<>的某个方法来加入界面元件至列表,已自动加入主菜单.
其他通过UIAddMenuBar()和UIAddToolBar()等来加入菜单/工具栏.
设置工具栏状态后,用UIUpdateToolBar更新状态.而菜单不必这样,因为是动态生成子菜单的.而UIUpdateMenuBar为恢复初始状态.
UISetRadio(多个只单选)很少用,要自己编码.

对话框

wtl加了输入验证和回调函数.如:你想在用户改变打开对话框中文件夹时动作,从CFileDialogImpl<>继承,并实现OnFolderChange函数.

class CMyFileDialog : public CFileDialogImpl<CMyFileDialog>
{
public:
    CMyFileDialog(BOOL b)
        : CFileDialogImpl<CMyFileDialog>(b) { }
    void OnFolderChange(LPOFNOTIFY lpon)
    {
        char strFolder[MAX_PATH];
        if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)//基类的.取路径.
        {
            MessageBox(strFolder);
        }
    }
};

这样,改变文件夹时就执行了.

控件

WTL为所有的Win32和通用控件提供了封装类.
两种使用方法:如对话框中有控件,将控件HWND依附至封装对象,用其方法来访问控件,简化读写控件数据和处理通知消息.
二,把类加入视图类的继承中.

class CMyView : public CWindowImpl<CMyView, CListBox>
//该窗口,从CListBox继承,

GetWndClassName取得窗口类名字.消息会传给你,如未处理由父窗口搞定.
发生事件时,多数窗口控件会发送通知父窗口.由窗口来处理.如要处理按钮点击时,只需处理BN_CLICKED通知,由按钮发送给窗口类.或从CContainedWindow<>继承按钮窗口来处理点击事件.处理通知消息更快,继承麻烦.
wtl还提供了命令栏.其他有用类:

描述
CBitmapButton 位图代替标题,可提供列表,在正常状态,失效, 推入和鼠标落在按钮上等时切换
CHyperLink 超链接,点击时,打开网页.
CWaitCursor 构造时等待,析构时还原.
CCheckListViewCtrl 检查列表框.
CMultiPaneStatusBarCtrl 多面板状态栏.
上一篇:WebSocket基础


下一篇:xlsx-style 行高设置