绪论

WTL

最终来了

,

而且

提供了我所希望的功能

.

我在

(译文)的文章列出

WTL

主要特征

.

在本文中

,

我将描述一下

WTL

的体系结构

,

同时我会给出一些简单的例子来演示如何使用它的那些特征

.

希望能够对您有所帮助

.

WTL

应用程序的类型

WTL

有好几种应用程序类型

,

供您在

AppWizard

选取

.

下表对这些应用程序进行了描述

.

这种弹性构成了

WTL

体系结构的一部分

.

应用程序类型

描述

SDI Application

单文本界面

只有一个窗口

Multiple Threads SDI

单个进程拥有一个或多个窗口

MDI Application

多文本界面

在框架内

,

您可以有零个或多个子窗口

Dialog Based

基于对话框模版

你可能还是首次听说多线程SDI应用程序,但是不用担心,它的概念很容易理解.一个多线程SDI程序启动后它会有一个窗口, 窗口显示了一个文档. 当你想要程序要再创建一个文档时,问题就出现了--SDI程序只能显示一个文档.为了解决这个问题,多线程SDI创建了另一个SDI窗口.看起来是一个新的实例在运行,实际上它不过是原来的进程创建了一个新的窗口,并把它依附到进程的一个新线程. IE的新建窗口就是这样做的.

除了多线程SDI,所有这些应用程序都可以作为COM服务器, 并且应用程序向导(AppWizard)为此提供了一个选项.另外应用程序向导还可以让你指定该程序是否主持ActiveX控件.令人费解的是,不同的程序类型,选取"Host ActiveX Controls"的地方不同.除对话框应用程序外的其他类型在第一页上选取,而对话框类型却放到第二页.

第二页的其他选项,对对话框程序以外的类型都是可用的.它们让你指定程序是否需要工具条(toolbar),状态条(status bar)和视窗口(View Window).

如果选取了"Toolbar"选项,你可以通过"Rebar"选择是否将工具条放入IE Rebar控件中. 如果你选取了Rebar, 你就可以通过框架窗口(frame window)的成员m_hWndToolBar(后边会有详细的描述)来访问它.你可以按照你的意愿,在里边加入其他的工具条. 选取了"Rebar"后, 你可以决定是否选取"Command Bar".

Command bar很像CE的command bar控件.只是WTL是用一个类来实现,而在CE, command bar是一个系统窗口类(system window class). Command bar非常有用,它能够把窗口也加入到工具条中去. 如果你选取了这个选项, 工具条和菜单都将被当做toolbar来实现.这使菜单项也可以有关联的图标,并且当你移动鼠标到一个菜单项上时,该菜单项会被置成高亮.从Office 97以来, Office软件的菜单都具有上述特征.

第二页还有指定程序是否使用视的选项(多半你想要使用), 同时你可以决定这些视如何实现. 下表列出了所有可选的视.

描述

Generic Window

一个简单的窗口

.

此类窗口允许程序员编写

WM_PAINT

消息的处理函数

.

适用于需要直接进行

paint

的文档

.

Form

这类视具有一个对话框模版

.

适用于带

ActiveX

控件的窗口

.

应用程序来操作这些控件

.

List Box

这个视是个

list box.

它最简单的形式意味着可以通过调用

AddString()

方法来添加字符串

.

Edit

这个视是个

edit control.

本质上

,

它提供了一个像

Notepad

一样的程序

.

List View

这个视是个

list view

通用控件

.

用这个控件来显示相关的项

(

比如

,

控制面板是一个

Explorer

主持的

List View,

所有的项都是控制面板

applet).

Tree View

这个视是个

tree view

通用控件

.

这个适用于具有层次关系的数据

,

比如

,

可以用它来显示数据库的

schema.

顶层分支为表和存储过程

,

次级的分支为表中的字段

.

Rich Edit

这个视是个

rich edit

控件

,

WordPad.

HTML Page

这个视主持了一个

IE Web Browser

控件

.

它把主持的一个

web page

当成一个视

.

本文的例子需要一个对话框模版

,

同时还需要菜单

,

因此

Form view

是个理想的选择

.

程序线程

跟ATL一样,WTL程序也需要一个_Module全局变量来保存全局数据,方便应用级代码访问.在WTL中,这个变量是CAppModule或CServerAppModule的实例,后者在程序同时作为一个COM服务器时用到.每个应用程序具有一个或者多个UI线程.WTL使用两种方式来管理这些线程.

如果应用程序只有一个UI线程(除了多线程SDI以外,其他程序类型默认只有一个UI线程),线程调用全局函数run():

int Run(LPTSTR /*lpstrCmdLine*/= NULL, int nCmdShow = SW_SHOWDEFAULT)

{

CMessageLoop theLoop;

_Module.AddMessageLoop(&theLoop);

CMainFrame wndMain;

if (wndMain.CreateEx() == NULL)

{

ATLTRACE(_T("Main window creation failed!\n"));

return 0;

}

wndMain.ShowWindow(nCmdShow);

int nRet = theLoop.Run();

_Module.RemoveMessageLoop();

return nRet;

}

线程的消息循环包含在CMessageLoop内部.函数创建了一个CMessageLoop实例, 把它放入全局的消息循环映射(message loop map)数组. 以线程ID为索引,线程中运行的其他的代码可以访问到这个实例. 消息循环对象包含了message filter和idle handler. 运行在这个UI线程的UI元件(UI element)可以有它自己的idle handler,在线程的消息队列为空时运行【译注:通过CMessageLoop::AddIdleHandler()把这个UI元件加入到CMessageLoop的idle handler 数组中】.CMessageLoop::Run()包含了UI线程的主消息映射(main message map).下边是它的伪代码:

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;

}

可以看到,这个函数推动着消息队列. 没有消息时, 运行注册到线程的idle hander. 如果在队列中检测到消息,把它取出来,传给每个message filter. 如果消息没有被这些函数处理,它将按照通常的方式,发送到目标窗口.

如果程序有超过一个的UI线程,可以用WTL的线程管理器,多线程SDI就是这样做的. 主线程作为一个管理者线程,它会为每个新窗口创建一个新的新线程. 主要流程如下:

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);

}

}

那些线程句柄放在一个数组中. 线程通过AddThread()加入到数组(同时启动线程), RemoveThread()从数组移走. wait语句在两种情况下会被打断: 线程死亡(将线程从数组中移出) 或线程收到了WM_USER消息(一个线程在一个新线程里新建了一个窗口). 线程管理者为程序中的一个类,因此可以在循环中加入自己的message handler, 比如,当程序有不止一种窗口类型时. 创建一个新的窗口非常简单,只需在任意一个窗口中调用:

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

这个循环会一直运行下去,直到所有的UI线程都关闭了. UI线程具有一个thread procedure,它跟单UI线程的Run()方法一样.不过,由于线程管理者使用了MsgWaitForMultipleObjects(), 这意味者最多只能有MAXIMUM_WAIT_OBJECTS-1个UI线程,这也意味着最多只能创建63个窗口.

框架

WTL实际上是两类窗口: 框架窗口和视图窗口. 正如名字所暗示的那样, 框架窗口为窗口提供标题栏(caption bar)和边框,你的代码用它来处理工具条(tool bar)和菜单项命令.你看到的程序窗口实际上是视图窗口, 视图覆盖了框架窗口的客户区.客户区是指框架窗口没有被诸如状态条,工具条之类的修饰部件所遮挡的部分.

线程会创建主框架窗口的一个实例,创建视图的工作由主框架窗口的WM_CREATE消息处理函数完成. 对于SDI程序来说,这个过程很简单. 把视图类的一个实例作为主框架类的一个成员,调用视图类的Create()方法即可.MDI程序稍微有些不同, MDI主框架窗口通过CMDIFrameWindowImpl<>::CreateMDIClient()建立一个名为MDICLIENT的窗口. 这个客户窗口将CMDIChildWindowImpl<>窗口当做它的子窗口,子窗口有一个视图.这也反映了这么一个事实,MDI程序可以具有零个或者多个子窗口,每个都有边框和标题栏.

框架窗口的OnCreate()很有意思,让我看看:

LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)

{

// create command bar window

HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,

NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);

// attach menu

m_CmdBar.AttachMenu(GetMenu());

// load command bar images

m_CmdBar.LoadImages(IDR_MAINFRAME);

// remove old menu

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;

}

这是从一个SDI程序拿来的一段代码,该程序有一个基于command bar的工具条和一个状态条. 函数的第一行创建了一个command bar实例,然后对它进行初始化,在其中加入框架窗口的菜单和工具条位图. 这段代码先将菜单取出,把所有的下拉菜单转换为工具条按钮,并将菜单保存在一个变量中,以备后用. 给人的感觉是菜单是由工具条实现的-那我们就把它叫做工具条菜单(menu toolbar)吧. 然后Command Bar将程序工具条的图标装入image list 并将它们的ID保存在数组中. 当点击工具条菜单的按钮时,commandbar会找到对应的子菜单,创建一个弹出菜单. Command bar将子菜单项的ID和它保存的ID进行比较,这些ID跟image list中的工具条按钮图标是相关联的. 如果比较成功, 则将关联的图标加到菜单项上去. 这意味着相同ID的菜单项和工具条按钮具有相同的图标.

接下来, 创建工具条并把它关联到commandbar, 然后创建状态条和视图.可以看到视图的HWND存放在框架窗口的m_hWndClient变量中. 这个窗口句柄在框架窗口的WM_SIZE handler中会用到.当框架窗口改变大小时,它告知视图改变自身,于此同时也要考虑状态条和command bar.

在下来的三行(从调用UIAddToolBar()开始) 用来显示在运行时会改变状态的UI项(UI item).文章后面还会重提这个话题. 最后,访问消息循环(message loop), 你应该还记得该消息循环存放在一全局数组中.GetMessageLoop() 取得当前线程的消息循环,加入框架窗口的message filter和idle handler, 分别默认是PreTranslateMessage()和OnIdle().

框架窗口继承于以下类:

class CMainFrame :

public CFrameWindowImpl,

public CUpdateUI,

public CMessageFilter,

public CIdleHandler

后两个抽象类宣称了框架窗口类实现了PreTranslateMessage()和OnIdle(). 从CUpdateUI<>继承表示框架类支持UI update map.

视图

视图窗口看起来显得很简单:

class CMyView : public CWindowImpl

{

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);

//TODO: Add your drawing code here

return 0;

}

};

上面是一个SDI程序的视图类. 多线程SDI和MDI的视图类在本质上也跟这个一样,但他们没有PreTranslateMessage()方法. SDI程序就是使用这个函数,赶在框架类处理消息之前把消息抓住. PreTranslateMessage()在SDI的框架类中的实现是,直接将消息转发给视图类.

这里显示的视图实际上没有做什么工作.你应该自己在OnPaint()函数中加入画出文档内容的代码.如果需要支持输入,如鼠标的点击和键盘的按键,你应该加入相应消息处理函数到类和映射中. 可以看到这个窗口是从CWindowImpl<>继承下来的,如果你想让它基于一个Win32控件的话,就应该从定义在AtlCtrls.h文件中某个WTL类继承.

如果想在基于CWindowImpl<>的类里加上滚动条,那么你应该把基类换成CScrollWindowImpl<>,同时把消息链给它:

class CMyView : public CScrollWindowImpl

{

public:

typedef CScrollWindowImpl parent;

BEGIN_MSG_MAP(CMyView)

CHAIN_MSG_MAP(parent)

END_MSG_MAP()

void DoPaint(CDCHandle dc)

{

}

};

基类保证窗口具备滚动条,并提供滚动条消息的默认处理.视图类不再有WM_PAINT的处理函数,因为它已被CScrollWindowImpl<>处理.根据滚动条的位置,CScrollWindowImpl<>画出视图相对应的部分. 取而代之的是,在你的类里实现DoPaint(),在这里你需要画出整个视图.如果你想指定滚动的范围,大小或起点,你需要加上处理WM_CREATE消息的函数,把这些初始化代码放到里边.

正如我先前所提到的,框架窗口会改变视图窗口的大小,以使它客户区未被状态条和工具条覆盖的部分为视图所填充. 在大多数情况下,这样就够了.但是当你想要一个具有Windows Explorer样子的程序时,该怎么办呢? Windows Explorer的窗口包含了一个tree view 和一个list view,还有两者之间的分割条. WTL的解决方案很简单:使用splitter窗口!

为此你需要改变一下框架窗口,让它创建splitter窗口的一个实例作为它的视图. 例如, 在你的框架类里有如下的数据成员:

CSplitterWindow m_view;

CTreeViewCtrl m_tree;

CListViewCtrl m_list;

你可以在OnCreate()创建一个splitter窗口:

// get the frame client rect, so that we set the splitter initial size

// and we can get the splitter bar in the centre

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();

Splitter窗口如同一个视图,将框架窗口作为它的父窗口. 在这段代码里,我将框架窗口客户区的实际大小传给了splitter窗口. 我也可以在这里使用 rcDefault,因为一旦框架窗口创建完成,框架窗口就会转发WM_SIZE消息给splitter. 这样splitter可以马上改变自身的大小来填充框架. 然而,当我准备使用不带参数的SetSplitterPos(),把分割条设置于窗口中线时,出现了问题.Splitter窗口使用它的大小来决定中线的位置,由于rcDefault告诉窗口它的大小是0(因此中线的位置也是0),从而意味着分割条将出现在z最左边,将左窗口隐藏了起来.

创建了splitter窗口后,你需要创建那些你想要分割的窗口了.它们将作为splitter窗口的子窗口被创建.最后你将这些子窗口通过SetSplitterPanes()加到splitter窗口中去,并确定分割条的位置所在.

UI Update

菜单项可以被设置为有效或无效,可以带check记号或着像radio按钮一样,在一组菜单项中同时有且只有一个能被check.此外,菜单项还可以带图标和文字. 所有的这些状态都可以在运行时根据程序中的某个值进行改变.工具条在某种程度上可以看做是菜单的易见形态,因为它们的按钮可以个别地,或者作为一组的一部分被置成有效或无效,推入推出. UI update机制允许你指定哪些UI元件(UI element)的状态可以在运行时改变. WTL使用如下的UI update映射来实现这一功能:

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()

这个例子指出三个菜单项在运行时有一个状态需要显示,其中的一个, ID_FILE_SAVERESULTS,还有一个工具条按钮跟它相关联. WTL通过建立一个数组来保存这些信息.为此你需要完成两方面的工作:

首先是UI元件的状态. 如果是菜单项, 你可以使用UIEnable()使能该菜单项, UISetCheck()设置check记号, UISetText()改变菜单的文字.如果是工具条按钮,那么你使用UIEnable()使能该按钮, UISetCheck()或者UISetRadio()决定按钮是推入还是推出.下边的代码根据是否有文本被选中,来使能Cut菜单项和工具条按钮:

BOOL bSelected = GetSelected();

UIEnable(ID_EDIT_CUT, bSelected);

你可以把这样的代码放入相应处理函数中(如一个菜单项的状态依赖于另一个菜单项的动作,将它放入后者的处理函数中),或者放入OnIdle()方法,通过检查某个类变量来决定元件的状态.

其次是确定各个UI元件是否都被更新了,为此你需要调用CUpdateUI<>的某个方法将UI元件加入到列表中.主菜单已被自动加入,但是其他的任何菜单和所有的工具条必须分别通过调用UIAddMenuBar()和UIAddToolBar()手动加入.

其他还有一堆事情要注意. 首先,设置了工具条的状态后,使用UIUpdateToolBar()以使工具条状态更新. 对于菜单,你不需如此,因为子菜单是动态生成的.UIUpdateMenuBar()这个方法也存在,但是它的作用是把菜单恢复到初始状态,如果你改变过某些项的文字,调用UIUpdateMenuBar()的结果可能不是你所期望的(因为菜单项的文字会变成老的).

尽管还有一个方法UISetRadio(),但是还没有一个把几个菜单项或者工具条按钮当做radio按钮组(也就是说,有一个而且只有一个被选中)的机制.如果你希望得到这样效果,你必须自己编码,不过它并不难.

对话框

ATL的对话框支持一向很好,对此WTL新增了通用对话框的封装. 本质上是为对话框加入了输入验证和回调函数. 比如, 你想在用户改变年Open对话框中的文件夹时有所动作,那么你应该从CFileDialogImpl<>继承一个类,实现OnFolderChange():

class CMyFileDialog : public CFileDialogImpl

{

public:

CMyFileDialog(BOOL b)

: CFileDialogImpl(b) { }

void OnFolderChange(LPOFNOTIFY lpon)

{

char strFolder[MAX_PATH];

if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)

{

MessageBox(strFolder);

}

}

};

当文件夹的路径改变时,CFileDialogImpl<>调用OnFolderChange().该函数使用基类的GetFolderPath(),来取得新路径.

控件

WTL为所有的Win32和通用控件提供了封装类,包括Windows 2000新加入的. 虽然只是简单的包装,但是它们使这些控件更加容易访问.譬如,你能记清楚从List View读出当前选定项的文字的消息和需要传的参数吗?(实际上, 你需要发送两个消息, 一个是得到选定项的索引,另一个是读出它的文字.) WTL的作者为你完成了这些烦人的工作, 提供了一个简单的封装函数供你使用.

使用这些控件类有两种方法. 如果你的对话框里有一个控件, 你可以将控件的HWND依附到一个封装对象,使用封装类的方法来访问控件.这种方法简化了你读写控件数据和处理notification消息的代码.

另外的用法是把这些类加到你的视图类的继承层次中去:

class CMyView : public CWindowImpl

这表示CWindowImpl<>是从CListBox继承而来,因此创建的窗口将是一个list box (因为窗口类的名字是通过调用

CListBox::GetWndClassName()得到的). 另外, ATL的窗口机制会子类化这个窗口,将发给它的消息路由到你的消息映射中去. 它保留了老的窗口函数,这样,你没有处理的消息将由老的窗口函数来处理.当你的视图类从控件类继承时,WTL就会使用这一技术.

在notification消息和子类化这个主题上,有一点很值得指出,那就是当某事件发生时,绝大多数窗口控件都会发送notification消息给它们的父窗口.让你窗口来处理这些notification消息要比子类化一个已存在控件窗口(或子类化一个已存在的类,然后建立一个实例),从而在控件之前取得消息好得多. 譬如, 你想处理按钮的click事件,你所需要做的只是处理BN_CLICKEDnotification.它将由按钮发送给你的窗口类.另外的一种方法是从CContainedWindow<>子类化BUTTON窗口来处理click消息.

我之所以说这个是因为一个知名的ATL鼓吹者给我一份代码里就是这么做的.他的代码取得一个简单的按钮click事件所花的时间是别人的3到4倍,因为他子类化了按钮控件,而不是简单的处理BN_CLICKEDnotification.

WTL还提供了一些新的控件,在win32中没有对等者. 你已经看到过一个--command bar, 实际上还有其他一些非常有用类:

描述

CBitmapButton

这是一个用位图替代标题的按钮.你可以提供一个image list,里边包含按钮在正常状态,失效, 推入和鼠标落在按钮上的图表.

CHyperLink

让你建立一个static控件,它代表一个hyperlink,这样当用户点击它时,默认的web浏览器打开该链接.

CWaitCursor

这不过是在它的构造函数中把鼠标图标改成等待状态,而在析构函数中还原.

CCheckListViewCtrl

在每一项边上都有一个check box的list box.

CMultiPaneStatusBarCtrl

具有多个pane的状态条

wtl单文档选项_WTL体系结构相关推荐

  1. wtl单文档选项_Vite 中文文档翻译

    前言 由于对vite的喜爱,所以本人首次尝试英文文档的翻译,由于本人英文水平有限.如果有哪里翻译错误或是无法get到原文的准确意思请指出会及时修正.为了更好的阅读体验强烈推荐跳转到下方地址进行阅读. ...

  2. wtl单文档选项_Vue3 文档阅读 —— TypeScript 支持

    Vue 官方团队于 2020 年 9 月 18 日晚 11 点半左右发布了Vue3.0版本 .代号为One Piece. Vue 3.0 终于发布了,具体更新内容详见 [v3.0.0](Release ...

  3. 【MFC】利用MFC向导生成单文档应用程序框架

    00. 目录 文章目录 00. 目录 01. 解决方案与工程 02. 使用向导生成单文档应用程序框架 03. 预留 04. 附录 01. 解决方案与工程 每个应用程序都作为一个工程来处理,它包含了头文 ...

  4. 利用MFC向导生成单文档应用程序框架

    HelloWorld 点击文件(File)->新建(New)->项目(Project).弹出新建项目(New Project). 如果安装完VS2010以后第一启动时已经设置为VC++,则 ...

  5. vs2010单文档对话框窗口界面设置

    VS2010窗口属性修改及文本按键添加 1.输出窗口的资源管理器停靠窗口.输出停靠窗口.属性停靠窗口的勾选取消 在创建VS2010单文档工程时,会出现需要改变输出窗口界面的情况,正常情况下的界面如下图 ...

  6. VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)

    原文:http://www.jizhuomi.com/software/141.html 解决方案与工程 鸡啄米在VS2010的使用介绍中已经讲了解决方案与工程的概念,这里再重提一下.每个应用程序都作 ...

  7. 使用VS的MFC应用创建单文档应用并添加对话框菜单和工具栏

    本教程是基于Visual Studio 2019的VC++大作业. 市面上大部分书本教程都使用Microsoft Visual C++工具创建,VS的教程全网少之又少. 故而本教程给初学者避雷,以单文 ...

  8. Windows编程与MFC # 4 单文档应用程序(1)

    整理自VC++程序设计课程课件 使用VC++的应用程序向导MFC AppWizard可以开发: Single document(单文档) Multiple document(多文档) Dialog b ...

  9. MFC单文档及其简介

    MFC单文档及其简介 MFC 是一个编程框架 MFC 中的各种类结合起来构成了一个应用程序框架,它的目的就是让程序员在此基础上来 建立Windows 下的应用程序.MFC 框架定义了应用程序的轮廓,并 ...

  10. MFC单文档应用程序的基础

    一.口令对话框 例题1:编写一个单文档应用程序,在视图中显示自己的姓名:单击鼠标左键,在消息框中显示 鼠标左键被按下的次数:单击鼠标右键,在消息框中显示鼠标右键被按下的次数. 操作步骤: 1.创建一个 ...

最新文章

  1. cn.hutool.poi.excel.ExcelUtil 只输出指定的标题
  2. Navicat是如何连接到服务器的呢
  3. OpenCASCADE:构建线程
  4. 大爱jQuery,10美女模特有用jQuery/CSS3插入(集成点免费下载)
  5. 深度学习用于视频检测_视频如何用于检测您的个性?
  6. C++总结笔记(十)——堆区内存开辟数组和二级指针
  7. nssl1270-创世纪【树形dp,基环树】
  8. 基于上一篇AS项目依赖库问题的优化解决方案
  9. java %3c%=a%%3e_跪求帮忙解析,急!!!
  10. UI设计配色专辑,设计师应用技巧
  11. 登录超时服务器未响应,怎样解决超时时间已到、在操作完成之前超时时间已过或服务器未响应的问题?...
  12. zabbix监控系列(2)之zabbix-agent安装
  13. MiniProfiler.EF6监控调试MVC5和EF6的性能
  14. 【python教程入门学习】Python爬虫入门学习:网络爬虫是什么
  15. VS2015安装Visual C++的Win32控制台应用程序
  16. 衡水十四中2021高考成绩查询,心之所向,行必能至|衡水市第十四中学召开2021高考倒计时200天动...
  17. 【无线上网】无线网络小常识
  18. KEPServer EX6的Modbus、MQTT和REST Server一站式配置整理说明
  19. 思维模型 三明治法则
  20. 监控摄像头进行网页直播

热门文章

  1. 零基础入门学习HTML(下)
  2. 支付宝签名php,支付宝快捷支付 PHP服务端签名
  3. 百度地图实现定位图标随手机方向变化而变化,即运用方向传感器
  4. 嵌入式网络基础知识——MQTT引入
  5. 聚合搜索 Meta Search实践
  6. WordPress站点被挂马,如何预防、检测和应对?
  7. 桥接路由器总是掉线_桥接后副路由器网速特别慢,而且经常掉线
  8. 交换机端口mtu值最大_-【SDN】交换机MTU配置总结
  9. prisma2.0文档学习/翻译
  10. 为什么你要考虑使用Prisma