4、MFC:菜单栏、工具栏与状态栏

菜单栏、工具栏与状态栏

  • 1、菜单栏
    • 1.1 简介
    • 1.2 创建
      • 属性设置
      • 菜单消息
      • 成员函数
    • 1.3 实例
  • 2、工具栏
    • 2.1 简介
    • 工具栏属性
    • 2.2 创建
      • 消息
      • CToolBar类的主要成员函数
    • 2.3 实例
  • 3、状态栏
    • 3.1 简介
    • 3.2 创建
      • CStatusBar类
      • 状态栏创建
    • 3.3 实例

1、菜单栏

1.1 简介

菜单在界面设计中是经常使用的一种元素,包括Windows系统中的窗口、智能终端设备的应用界面等都会经常见到菜单的身影。我们在对可视化窗口操作时,菜单确实提供了很大方便。
菜单分为:

  1. 下拉式菜单:下拉式菜单一般在窗口标题栏下面显示,下拉式菜单通常是由主菜单栏、子菜单及子菜单中的菜单项和分隔条所组成的。
  2. 弹出式菜单:弹出式菜单一般可以通过单击鼠标右键等操作显示。它的主菜单不可见,只显示子菜单。

1.2 创建

属性设置

在这里插入图片描述

  1. 菜单项中含有“…”则表示点击后会弹出对话框。
  2. 热键:菜单项的标题文本中都有一个字母带下划线,带下划线的字母为热键。中文则为括号中的字母。

主菜单栏上的“File”中字母“F”带下划线,F就是热键,程序运行并显示窗口时,在键盘上点击Alt+F就等同于直接点菜单项File,弹出File下的子菜单后,点击“Open”的热键O就可以实现与直接点菜单项Open相同的功能。
热键的定义:可在属性中直接设置。Caption为“&File”,很明显,只要在要定义为热键的字母前加&就可以了。
在这里插入图片描述

  1. 快捷键:用这些组合键就能实现与相应菜单项一样的功能。
    定义:“Open”菜单项的Caption属性,为“&Open…\tCtrl+O”,这里的\t表示在显示前面的文本后跳格再显示快捷键Ctrl+O,但这样设置其Caption属性只是能显示出快捷键,要实现快捷键的功能还需要在Accelerator资源中设定。
    在这里插入图片描述
  • Accelerator中有四列,分别为:ID、Modifier、Key和Type。ID就是菜单项的ID,Modifer和Key就代表了组合键。例如,Open菜单项的ID为ID_FILE_OPEN,Modifer为“Ctrl”,Key为“O”。
  1. 创建:右键插入新列、分隔符、菜单项等;也可以直接输入。
    需要为菜单项设置ID、热键和快捷键(Accelerator)。
    在这里插入图片描述

菜单消息

菜单主要能发送两种消息:COMMAND消息和UPDATE_COMMAND_UI消息。

  1. COMMAND消息:在菜单项被点击时发送该消息。
  2. UPDATE_COMMAND_UI消息:用来维护菜单项的各项状态,包括激活、禁用、变灰、选中、未选中等。在下拉菜单每次打开的时候,所有菜单项的此消息都会被发送出去。如果所属类中为菜单项的该消息添加了处理函数,则执行相应函数更新菜单状态,如果菜单项没有此消息处理函数,也没有COMMAND消息的处理函数,那么它就会变灰。

成员函数

MFC为菜单的操作提供了CMenu类。

  1. BOOL LoadMenu(UINT nIDResource);
    加载菜单资源,并将其附加到CMenu对象上。参数nIDResource指定了要加载的菜单资源的ID。如果菜单加载成功则返回TRUE,否则返回FALSE。
  2. BOOL DeleteMenu(UINT nPosition,UINT nFlags);
    在菜单中删除一个菜单项。参数nPosition指定要删除的菜单项。参数nFlags就用来解释nPosition的意义,为MF_BYCOMMAND时说明nPosition表示菜单项的ID,为MF_BYPOSITION时说明nPosition表示菜单项的位置,第一个菜单项的位置为0。如果删除菜单项成功则返回TRUE,否则返回FALSE。
  3. BOOL TrackPopupMenu(UINT nFlags,int x,int y,CWnd* pWnd,LPCRECT lpRect = 0);
    用来在指定位置显示一个浮动的弹出式菜单。参数nFlags指定屏幕坐标和鼠标位置的标志,可以是以下取值:
    TPM_CENTERALIGN:菜单在水平方向上相对于参数x指定的坐标值居中显示
    TPM_LEFTALIGN:菜单的左侧与参数x指定的坐标值对齐
    TPM_RIGHTALIGN:菜单的右侧与参数x指定的坐标值对齐
    TPM_BOTTOMALIGN:菜单的底部与参数y指定的坐标值对齐
    TPM_TOPALIGN:菜单项的顶部与参数y指定的坐标值对齐
    TPM_VCENTERALIGN:菜单在垂直方向上相对于参数y指定的坐标值居中显示
    参数x指定弹出式菜单的水平方向的屏幕坐标,参数y指定菜单顶部垂直方向上的屏幕坐标,参数pWnd指明哪个窗口拥有此弹出式菜单,不能为NULL,参数lpRect忽略。
  4. UINT CheckMenuItem(UINT nIDCheckItem,UINT nCheck);
    在弹出菜单中为菜单项增加选中标记或移除选中标记。参数nIDCheckItem指定要选中或取消选中的菜单项。参数nCheck指定菜单项的选中状态和如何根据nIDCheckItem确定菜单项的位置,可以是MF_CHECKED或MF_UNCHECKED与MF_BYPOSITION或MF_BYCOMMAND的组合,这几个标志的含义如下:
    MF_BYCOMMAND:为默认值。说明参数nIDCheckItem表示菜单项的ID
    MF_BYPOSITION:说明参数nIDCheckItem表示菜单项的位置,第一个菜单项的位置是0
    MF_CHECKED:为菜单项添加选中标记
    MF_UNCHECKED:为菜单项移除选中标记
    该函数返回菜单项之前的状态:MF_CHECKED或MF_UNCHECKED, 如果菜单项不存在则返回0xFFFFFFFF。
  5. UINT EnableMenuItem(UINT nIDEnableItem,UINT nEnable);
    激活、禁用菜单项或使其变灰。参数nIDEnableItem指定要激活、禁用或变灰的菜单项。参数nEnable指定操作的类型,可以是MF_DISABLED、MF_ENABLED或MF_GRAYED与MF_BYCOMMAND或MF_BYPOSITION的组合,这些值的含义如下:
    MF_BYCOMMAND:同CheckMenuItem
    MF_BYPOSITION:同CheckMenuItem
    MF_DISABLED:禁用菜单项,使其不能被选择但不变灰
    MF_ENABLED:激活菜单项,使其能够被选择并由变灰状态恢复
    MF_GRAYED:禁用菜单项,使其不能被选择并变灰
    该函数返回菜单项之前的状态:MF_DISABLED、MF_ENABLED或MF_GRAYED
  6. CMenu* GetSubMenu(int nPos) const;
    获取弹出菜单的CMenu对象。参数nPos指定弹出菜单在菜单中的位置,不能使用ID。返回值是CMenu对象的指针,该CMenu对象的m_hMenu成员为由nPos指定的弹出菜单的句柄,如果不存在这样的CMenu对象则返回NULL,然后创建一个临时弹出菜单。

1.3 实例

  • 下拉式菜单实现
  1. 创建菜单项:设置ID,名称,热键,快捷键等;
  2. 创建消息相应函数(消息响应函数应该创建在CMainFrame类中);
ON_COMMAND(IDM_TOOLSDRAW, &CMainFrame::OnToolsdraw)
ON_UPDATE_COMMAND_UI(IDM_TOOLSDRAW, &CMainFrame::OnUpdateToolsdraw)

void CMainFrame::OnToolsdraw()
{
	// TODO: 在此添加命令处理程序代码
}


void CMainFrame::OnUpdateToolsdraw(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
}
  1. 编写函数体中处理代码;数据成员和函数成员实现
    在这里插入图片描述
  • 弹出式菜单实现
    鼠标右键的点击为消息响应函数操作。
  1. 创建弹出菜单资源;
  2. 通过消息响应函数来弹出菜单项,有两种实现方式:
void CSingleDocAppView::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CMenu menu;       // 菜单(包含主菜单栏和子菜单)   
	CMenu* pSubMenu;  // 右键菜单   

	// 加载菜单资源到menu对象   
	menu.LoadMenu(IDR_POPUP_EDIT);
	// 因为右键菜单是弹出式菜单,不包含主菜单栏,所以取子菜单   
	pSubMenu = menu.GetSubMenu(0);
	// 将坐标值由客户坐标转换为屏幕坐标   
	ClientToScreen(&point);
	// 弹出右键菜单,菜单左侧与point.x坐标值对齐   
	pSubMenu->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);

	CView::OnRButtonDown(nFlags, point);
}
void CSingleDocAppView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CSingleDocAppView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}
  1. 在弹出式菜单弹出的相关类中对菜单项的消息响应函数进行实现。

2、工具栏

2.1 简介

工具栏一般位于主框架窗口的上部,菜单栏的下方,由一些带图片的按钮组成。当用户用鼠标单击工具栏上某个按钮时,程序会执行相应的操作,如果鼠标没有点击,只是停留在某个按钮上一会后,会弹出一个小窗口显示提示信息。
工具栏一般位于主框架窗口的上部,菜单栏的下方,由一些带图片的按钮组成。当用户用鼠标单击工具栏上某个按钮时,程序会执行相应的操作,如果鼠标没有点击,只是停留在某个按钮上一会后,会弹出一个小窗口显示提示信息。

工具栏属性

资源位置:在资源视图的Toolbar栏下
在这里插入图片描述
以IDR_MAINFRAME工具栏的第一个按钮为例说明工具栏按钮的各项属性。用鼠标单击工具栏资源上的第一个按钮,属性页中就会显示其属性。下面分别讲解各项属性。

  1. ID属性:ID_FILE_NEW。不知大家是否还记得,菜单IDR_MAINFRAME的菜单项File->New的ID也是ID_FILE_NEW,两者ID相同,正是如此才使得工具栏第一个按钮与菜单项File->New能实现相同的功能。如果想让工具栏某个按钮与菜单栏某个菜单项点击后执行的操作相同,就要为两者设置相同的ID。
  2. Prompt属性:Create a new document\nNew。此属性为工具栏按钮的提示文本。在鼠标指向此按钮时,状态栏中会显示“Create a new document”,当弹出提示信息窗口时会显示包含“New”的提示信息。“\n”是两者的分隔转义符。
  3. Height属性:15。此属性为工具栏按钮的像素高度。
  4. Width属性:16。此属性为工具栏按钮的像素宽度。

在这里插入图片描述

  • 工具栏资源的最右边总是会有一个待编辑的按钮,我们对其进行编辑后,工具栏资源会自动增加一个新的空白按钮,这也实现了按钮的添加操作。如果我们想要删除某个按钮,就可以用鼠标左键点住它,拖出工具栏资源的范围即可。
  • 另外,我们看到,第三个按钮(保存按钮)和第四个按钮(剪切按钮)之间有一些间隙,在运行程序后会出现一个竖的分隔线,所以想要在两个按钮之间添加分隔线的话,可以用鼠标左键拖住右边的按钮往右稍移动一些就可以了。

2.2 创建

消息

一般情况下工具栏中的按钮在菜单栏中都有对应的菜单项,两者实现的功能相同,要想实现这种效果,只需要将工具栏按钮的ID与对应的菜单栏中菜单项的ID设置为相同值即可。
在实际使用工具栏时,除了前面讲的资源编辑外,其他使用与菜单类似。例如,对COMMAND消息和UPDATE_COMMAND_UI消息,可像菜单应用实例那样为工具栏按钮添加消息处理函数。

  • 如果工具栏按钮对应的菜单项已经添加了消息处理函数,那么就不必再为它添加了,因为它的ID与菜单项相同,所以会调用同样的消息处理函数。这样点击工具栏按钮与点击相应菜单项执行相同的功能,在菜单项为选中、激活或禁用等状态时,工具栏按钮会有一样的状态。

CToolBar类的主要成员函数

MFC为工具栏的操作提供了CToolBar类。

  1. virtual BOOL CreateEx(
    CWnd* pParentWnd,
    DWORD dwCtrlStyle = TBSTYLE_FLAT,
    DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,
    CRect rcBorders = CRect(0, 0, 0, 0),
    UINT nID = AFX_IDW_TOOLBAR
    );
    创建工具栏对象。参数pParentWnd为工具栏父窗口的指针。参数dwCtrlStyle为工具栏按钮的风格,默认为TBSTYLE_FLAT,即“平面的”。参数dwStyle为工具栏的风格,默认取值WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,由于是主框架窗口的子窗口,所以要有WS_CHILD和WS_VISIBLE风格,CBRS_ALIGN_TOP风格表示工具栏位于父窗口的顶部, 各种风格可以参见MSDN的Toolbar Control and Button Styles中的定义。参数rcBorders为工具栏边框各个方向的宽度,默认为CRect(0, 0, 0, 0),即没有边框。参数nID为工具栏子窗口的ID,默认为AFX_IDW_TOOLBAR。
  2. BOOL LoadBitmap(UINT nIDResource);
    为工具栏加载位图。参数nIDResource为位图资源的ID。成功则返回TRUE,否则返回FALSE。注意,这里的位图资源应当为每个工具栏按钮都提供位图,如果图片不是标准大小(16像素宽,15像素高),则需要调用SetSizes成员函数调整按钮大小和图片大小。
  3. BOOL LoadToolBar(UINT nIDResource);
    加载由nIDResource指定的工具栏。参数nIDResource为要加载的工具栏的资源ID。成功则返回TRUE,否则返回FALSE。
  4. void SetSizes(SIZE sizeButton,SIZE sizeImage);
    设置工具栏按钮的大小和图片的大小。参数sizeButton为工具栏按钮的像素大小。参数sizeImage为图片的像素大小。
  5. void SetButtonStyle(int nIndex,UINT nStyle);
    设置工具栏按钮或分隔线的风格,或者为按钮分组。参数nIndex为将要进行设置的按钮或分隔线的索引。参数nStyle为按钮风格,可以是以下取值:
    TBBS_BUTTON 标准按钮(默认)
    TBBS_SEPARATOR 分隔条
    TBBS_CHECKBOX 复选框
    TBBS_GROUP 标记一组按钮的开始
    TBBS_CHECKGROUP 标记一组复选框的开始
    TBBS_DROPDOWN 创建下拉列表按钮
    TBBS_AUTOSIZE 按钮的宽度根据按钮文本计算,而不基于图片大小
    TBBS_NOPREFIX 按钮的文本没有快捷键前缀
  6. UINT GetButtonStyle(int nIndex) const;
    获取工具栏按钮或分隔条的风格。风格可参考SetButtonStyle。参数nIndex为按钮或分隔条的索引。
  7. BOOL SetButtonText(int nIndex,LPCTSTR lpszText);
    设置工具栏按钮的文本。参数nIndex为工具栏按钮的索引。参数lpszText为指向要设置的文本字符串的指针。设置成功则返回TRUE,否则返回FALSE。
  8. CString GetButtonText(int nIndex) const;
    获取工具栏按钮上显示的文本。参数nIndex为工具栏按钮的索引。

2.3 实例

CMainFrame类中看到,它创建工具栏所使用的类并不是常用的CToolBar类,而是CMFCToolBar类。CMFCToolBar类是自VS2008以来MFC提供的类,它与CToolBar类有些类似,但功能更丰富。这里要注意,CMFCToolBar类与CToolBar类并没有任何派生关系。
以CMFCToolBar类讲解工具栏的创建步骤:

  1. 创建工具栏资源。
  2. 构造CMFCToolBar类的对象。
  3. 调用CMFCToolBar类的Create或CreateEx成员函数创建工具栏。
  4. 调用LoadToolBar成员函数加载工具栏资源。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
		!m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME))
	{
		TRACE0("未能创建工具栏\n");
		return -1;      // 未能创建
	}

	CString strToolBarName;
	bNameValid = strToolBarName.LoadString(IDS_TOOLBAR_STANDARD);
	ASSERT(bNameValid);
	m_wndToolBar.SetWindowText(strToolBarName);

	CString strCustomize;
	bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
	ASSERT(bNameValid);
	m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);
}

因为创建框架窗口时需要调OnCreate函数,所以工具栏的创建也是在OnCreate中完成的。

  • 工具栏的停靠
    创建好工具栏后,如果想要停靠工具栏,也需要添加相应的停靠代码。工具栏停靠的步骤及需要调用的函数如下(前两个步骤可以颠倒顺序):
  1. 在框架窗口中启用停靠
    若要将工具栏停靠到某个框架窗口,则必须启用该框架窗口(或目标)以允许停靠。可以在CFrameWndEx类中调用下面的成员函数来实现:
BOOL EnableDocking(DWORD dwDockStyle);

该函数采用一个DWORD参数,用来指定框架窗口的哪个边可以接受停靠,可以有四种取值:CBRS_ALIGN_TOP(顶部)、CBRS_ALIGN_BOTTOM(底部)、CBRS_ALIGN_LEFT(左侧)、CBRS_ALIGN_RIGHT(右侧)。如果希望能够将控制条停靠在任意位置,将CBRS_ALIGN_ANY作为参数传递给EnableDocking。

  1. 工具栏启用停靠
    框架窗口启用停靠准备好后,必须以相似的方式准备工具栏。为想要停靠的每一个工具栏CMFCToolBar对象调用下面的函数:
virtual void EnableDocking(DWORD dwAlignment);

允许工具栏停靠到框架窗口,并指定工具栏应停靠的目标边。此函数指定的目标边必须与框架窗口中启用停靠的边匹配,否则工具栏无法停靠,为浮动状态。

  1. 停靠工具栏
    当用户试图将工具栏放置在允许停靠的框架窗口某一边时,需要框架CFrameWndEx类调用以下函数:
void DockPane(CBasePane* pBar,UINT nDockBarID=0,LPCRECT lpRect=NULL);
  • 参数pBar为要停靠的控制条的指针,参数nDockBarID为要停靠的框架窗口某条边的ID,可以是以下四种取值:AFX_IDW_DOCKBAR_TOP、AFX_IDW_DOCKBAR_BOTTOM、AFX_IDW_DOCKBAR_LEFT、AFX_IDW_DOCKBAR_RIGHT

CMainFrame类的OnCreate函数实现中,工具栏的停靠过程:

// TODO: 如果您不希望工具栏和菜单栏可停靠,请删除这五行
	m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	EnableDocking(CBRS_ALIGN_ANY);
	DockPane(&m_wndMenuBar);
	DockPane(&m_wndToolBar);

3、状态栏

3.1 简介

状态栏相信大家在很多窗口中都能见到,它总是用来显示各种状态。状态栏实际上也是一个窗口,一般分为几个窗格,每个窗格分别用来显示不同的信息和状态等,如菜单项和工具栏按钮的提示信息。
用MFC向导生成的单文档或多文档程序都会自动创建状态栏,该状态栏被分为了几个窗格,分别用来显示菜单项和工具栏按钮的提示信息及Caps Lock、Num Lock、Scroll Lock键的状态。

3.2 创建

CStatusBar类

  1. virtual BOOL Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR);
    创建一个状态栏。参数pParentWnd为状态栏父窗口的指针,参数dwStyle为状态栏的风格,除了标准的Windows风格外,它还支持:
    CBRS_TOP:位于框架窗口的顶部。
    CBRS_BOTTOM:位于框架窗口的底部。
    CBRS_NOALIGN:父窗口大小改变时状态栏不会被重新定位。
    参数nID指定状态栏的ID。
  2. BOOL SetIndicators(const UINT* lpIDArray, int nIDCount);
    为每个指示器设置显示文本,具体来说,就是用lpIDArray数组中的对应元素为每个指示器设置一个ID,然后加载每个ID代表的字符串,设置为这些指示器的显示文本。参数lpIDArray为指向一个ID数组的指针,参数nIDCount为lpIDArray数组的元素个数。
  3. UINT GetItemID(int nIndex) const;
    获取由nIndex指定的指示器的ID。参数nIndex为要获取ID的指示器索引。
  4. CString GetPaneText(int nIndex) const;
    获取状态栏窗格中显示的文本。参数nIndex为要获取文本的窗格的索引。返回值为包含窗格文本的CString对象。
  5. BOOL SetPaneText(int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE);
    设置状态栏窗格的显示文本。参数nIndex为要设置文本的窗格的索引,参数lpszNewText为指向新的窗格文本的指针,参数bUpdate表示是否设置后立即更新显示。如果设置成功则返回TRUE,否则返回FALSE。

状态栏创建

在CMainFrame类中看到,创建状态栏时使用的是CMFCStatusBar类对象。CMFCStatusBar类是自VS2008以来提供的状态栏类,用法与CStatusBar类相似,甚至很多成员函数也类似,但它的功能更加丰富。
创建步骤:

  1. 构造一个CMFCStatusBar类的对象。
    在MainFrm.h文件中,为CMainFrame类定义了一个成员对象:CMFCStatusBar m_wndStatusBar;。
  2. 调用CMFCStatusBar::Create函数来创建状态栏窗口。
    在CMainFrame::OnCreate函数的实现中,我们可以找到CMFCStatusBar::Create函数的调用:
if (!m_wndStatusBar.Create(this))   
{   
    TRACE0("Failed to create status bar\n");   
    return -1;      // fail to create   
}
  1. 调用CMFCStatusBar::SetIndicators函数为状态栏划分窗格,并为每个指示器设置显示文本。
    CMFCStatusBar::SetIndicators函数需要一个ID数组的参数,在MainFrm.cpp中,如下定义了一个窗格ID的数组:
static UINT indicators[] =   
{   
    ID_SEPARATOR,           // status line indicator   
    ID_INDICATOR_CAPS,   
    ID_INDICATOR_NUM,   
    ID_INDICATOR_SCRL,   
};
  • indicators数组定义了状态栏窗格的划分信息。第一个元素一般为ID_SEPARATOR,对应的窗格用来显示命令提示信息,上面数组中的后三项为指示器文本的字符串ID,可以根据这些ID在String Table字符串资源中找到相应的字符串,查找方法是,在Resource View资源视图中,打开String Table字符串资源,可以看到有ID、Value和Caption三列,在ID列中找到需要的ID,对应的Caption列文本就是要查找的字符串。ID_INDICATOR_CAPS、ID_INDICATOR_NUM和ID_INDICATOR_SCRL对应的字符串分别是CAP、NUM、SCRL,对应的三个窗格分别为Caps Lock指示器、Num Lock指示器和Scroll Lock指示器。

在CMainFrame::OnCreate函数中调用:

m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));

状态栏就创建完成了,之后我们可以通过CMFCStatusBar::SetPaneText设置窗格的文本。

3.3 实例

在状态栏添加一个事件窗格,用来显示系统时间。

  1. 在Resource View资源视图中打开String Table字符串资源,然后在最后一行的下一个空白行中,或者任意处点右键选择“New String”,添加一个新的字符串资源.
    在这里插入图片描述
  2. 在indicators数组的第一个元素ID_INDICATOR_SCRL后插入IDS_INDICATOR_TIME。
static UINT indicators[] =
{
	ID_SEPARATOR,           // 状态行指示器
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
	IDS_INDICATOR_TIME
};
  1. 要实时显示系统时间,就需要使用一个定时器,每秒钟更新一次时间显示。在CMainFrame::OnCreate函数中开启定时器.
// 启动定时器,定时器ID为1,定时时间为1000ms,即1s   
    SetTimer(1, 1000, NULL);  
  1. 在Class View类视图中找到CMainFrame类,右键选择“Properties”,然后在显示出来的属性页中,点工具栏上的Messages按钮,即显示出消息列表,找到WM_TIMER消息,添加其消息处理函数void CMainFrame::OnTimer(UINT_PTR nIDEvent),并修改此函数实现如下:
void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CString strTime;
	// 获取系统当前时间,并保存到curTime   
	CTime curTime = CTime::GetCurrentTime();

	// 格式化curTime,将字符串保存到strTime   
	strTime = curTime.Format(_T("%H:%M:%S"));
	// 在状态栏的时间窗格中显示系统时间字符串   
	m_wndStatusBar.SetPaneText(4, strTime);

	CFrameWndEx::OnTimer(nIDEvent);
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/733891.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AWS SMB】关于AWS 中小型企业 (SMB) 能力介绍及注意事项

文章目录 前言一、什么是 SMB?📢二、如何识别中小企业的需求三、中小企业营销活动的类型四、AWS 合作伙伴可获得的其他 AWS 机会4.1 AWS IQ4.2 APN 客户参与 (ACE) 计划 前言 AWS 中小型企业 (SMB) 能力合作伙伴专注于帮助中小型…

荒野大镖客2启动找不到emp.dll的7个修复方法,轻松解决dll丢失的办法

一、emp.dll文件丢失的常见原因 安装或更新问题:在软件或游戏的安装过程中,可能由于安装程序未能正确复制文件到目标目录,或在更新过程中文件被意外覆盖或删除,导致emp.dll文件丢失。 安全软件误删:某些安全软件可能…

甘肃旅游服务平台的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,公告信息管理,景点管理,酒店管理,基础数据管理,美食管理 前台账户功能包括:系统首页,个人中心&#xff0…

在 Equinix 上使用 MinIO 控制云数据成本

公有云改变了公司构建、部署和管理应用程序的方式,主要是向好的方向发展。在您刚开始使用时,公有云会提供基础架构、服务、支持和维护,以便快速启动和运行。它以几乎无限的方式提供最终的可伸缩性,无论应用程序的负载如何&#xf…

小米15系列将首发骁龙8 Gen4 SoC

高通已确认2024年骁龙峰会定于10月21日举行。在这次峰会中高通将推出其最新的移动芯片Snapdragon 8 Gen4 SoC。著名科技博主DigitalChatStation今天证实,骁龙8 Gen4将以小米15系列首次亮相。这意味着小米15系列将是第一款使用这款新旗舰处理器的手机。 这不是小米第…

和琪宝的厦门之旅~

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。 引言 承接去年国庆的遗憾,我们将这次的旅行城市定为厦门。 琪宝是下午四点左右到…

湖南(市场调研)源点咨询 新产品上市前市场机会调研与研究分析

湖南源点调研认为:无论是创业公司,还是在公司内部探索新的项目或者新的产品线等,首先都要做“市场机会分析与调研“,要真正思考并解答以下疑问: 我们的目标客户群体是谁,他们如何决策? 我们所…

长尾式差分放大电路调零

长尾式放大电路用了两个参数相同的三极管,但实际上并没有完全相同的三极管,所以为了提高差分放大电路的对称性(一边电流增加多少,另一边电流减小多少,即能在电阻Re上产生的压降不变(后面做虚地处理)),在下图中加入可调…

FaceFusionSharp OnnxRuntime版 视频换脸

FaceFusionSharp OnnxRuntime版 视频换脸 目录 效果 项目 代码 下载 其他 效果 FaceFusionSharp OnnxRuntime版效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Threading; using System.Window…

vivado、vitis2022安装及其注意事项(省时、省空间)

1、下载 AMD官网-资源与支持-vivado ML开发者工具,或者vitis平台, 下载的时候有个官网推荐web安装,亲测这个耗时非常久,不建议使用,还是直接下载89G的安装包快。 注意:安装vitis平台会默认安装vivado&…

Android补间动画、帧动画、属性动画详解

View Animation: 视图动画在古老的Android版本系统中就已经提供了,只能被用来设置View的动画。 Drawable Animation: 这种动画(也叫Frame动画、帧动画)其实可以划分到视图动画的类别,专门用来一个一个的显…

UE4_材质_湿度着色器及Desaturation算法_ben材质教程

学习笔记,不喜勿喷!侵权立删,祝愿美好生活越来越好。 效果图: 原图: 1、使用初学者内容包的材质 我们这里使用虚幻自带的材质M_Brick_Clay_Old,复制一个更名为M_Brickclayoldwet材质。 2、添加去饱和度Desaturation节…

数据库精选题(三)(SQL语言精选题)(按语句类型分类)

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀数据库 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 前言 创建语句 创建表 创建视图 创建索引…

【一】【算法】经典树状数组和并查集,详细解析,初步认识,【模板】树状数组 1,树状数组并查集

【模板】树状数组 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某一个数加上 x x x 求出某区间每一个数的和 输入格式 第一行包含两个正整数 n , m n,m n,m,分别表示该数列数字的个数和操作的总个数。 第二…

Win11下安装VS2022失败的解决办法

前几天我把我的HP Z840的操作系统换成了Win11,在重装VS2022时遇到了麻烦,提示无法安装 Microsoft.VisualStudio.Devenv.Msi。 查看安装日志提示:Could not write value devenv.exe to key \SOFTWARE\Microsoft\Internet Explorer\Main\Featur…

DataWhale - 吃瓜教程学习笔记(二)

学习视频:第3章-一元线性回归_哔哩哔哩_bilibili 西瓜书对应章节: 3.1 - 3.2 一元线性回归 - 最小二乘法 - 极大似然估计 - 梯度 多元函数的一阶导数 - 海塞矩阵 多元函数的二阶导数 - 机器学习三要素

SpringBoot 快速入门(保姆级详细教程)

目录 一、Springboot简介 二、SpringBoot 优点: 三、快速入门 1、新建工程 方式2:使用Spring Initializr创建项目 写在前面: SpringBoot 是 Spring家族中的一个全新框架,用来简化spring程序的创建和开发过程。SpringBoot化繁…

qt+halcon实战

注意建QT工程项目用的是MSVC,如果选成MinGW,则会报错 INCLUDEPATH $$PWD/include INCLUDEPATH $$PWD/include/halconcppLIBS $$PWD/lib/x64-win64/halconcpp.lib LIBS $$PWD/lib/x64-win64/halcon.lib#include "halconcpp/HalconCpp.h" #include &quo…

CompletableFuture 基本用法

一、 CompletableFuture简介 CompletableFuture 是 Java 8 引入的一个功能强大的类,用于异步编程和并发处理。它提供了丰富的 API 来处理异步任务的结果,支持函数式编程风格,并允许通过链式调用组合多个异步操作。 二、CompletableFuture中…

尚品汇-(四)

(1)商品的基本知识 1.1基本信息—分类 一般情况可以分为两级或者三级。咱们的项目一共分为三级,即一级分类、二级分类、三级分类。 比如:家用电器是一级分类,电视是二级分类,那么超薄电视就是三级分类。…