当前位置: 首页 > news >正文

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_HANDLERStheApp.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);
}

在这里插入图片描述

相关文章:

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 简介 菜单在界面设计中是经常使…...

Java中的动态代理:原理与应用

Java中的动态代理:原理与应用 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在Java开发中,动态代理是一种强大且灵活的技术&#xff…...

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

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

[保姆级教程]uniapp自定义标签页切换组件

文章目录 导文样式改成动态列表切换点击效果加上点击自动滑动scroll-view加上切换组件效果 导文 unaipp自带的标签页和ui设计相差太大,直接修改组件比手写一个还麻烦,下面手写一个。 样式 先用scroll-view做一个滑动,不然多的话滑动不了。 &l…...

4种典型家庭教育方式,无论开始是哪一种,都会过渡到最后一种

家庭教育,是孩子教育的一个重要组成部分,事实上是对孩子影响最大的一种教育方式,绝大部分家庭教育都是由孩子的父母来完成的。 家庭教育的特点 家庭教育具有很明显的启蒙性、长期性、全面性。 1.启蒙性。我们的孩子对外部世界的认识和了解&am…...

[Django学习]查询过滤器(lookup types)

1.exact exact用于精确匹配字段的值。适用于需要精确查找某个字段值的场景。 Book.objects.filter(title__exactHarry Potter) 上面的查询会查找标题完全为“Harry Potter”的书籍。 2.iexact iexact忽略大小写地精确匹配字段的值。适用于需要忽略大小写进行精确匹配的场…...

异步开发的终极答案—协程

我们在之前的文章中讲过,在并发场景下,传统的基于多线程的命令式开发模型虽然比较简单,但并发数高了之后资源占用较高,大量线程会阻塞;而响应式编程模式我们可以通过异步化处理提升系统资源的利用效率,但异步开发有违人的直觉,门槛比较高。作为成年人,我们肯定希望全都…...

构建高效的大数据量延迟任务调度平台

目录 引言系统需求分析系统架构设计 总体架构任务调度模块任务存储模块任务执行模块 任务调度算法 时间轮算法优先级队列分布式锁 数据存储方案 关系型数据库NoSQL数据库混合存储方案 容错和高可用性 主从复制数据备份与恢复故障转移 性能优化 水平扩展缓存机制异步处理 监控与…...

Python武器库开发-武器库篇之ThinkPHP 2.x 任意代码执行漏洞(六十三)

Python武器库开发-武器库篇之ThinkPHP 2.x 任意代码执行漏洞(六十三) PHP代码审计简介 PHP代码审计是指对PHP程序进行安全审计,以发现潜在的安全漏洞和风险。PHP是一种流行的服务器端脚本语言,广泛用于开发网站和Web应用程序。由…...

SQLite数据库(数据库和链表双向转换)

文章目录 SQLite数据库一、SQLite简介1、SQLite和MySQL2、基于嵌入式的数据库 二、SQLite数据库安装三、SQLite的常用命令四、SQLite的编程操作1、SQLite数据库相关API(1)头文件(2)sqlite3_open()(3)sqlite…...

React框架的来龙去脉,react的技术原理及技术难点和要点,小白的进阶之路

React 框架的来龙去脉:技术原理及技术难点和要点 1. React 的起源与发展 React 是由 Facebook 开发的一个用于构建用户界面的 JavaScript 库。它最初由 Jordan Walke 创建,并在 2013 年开源。React 的出现是为了解决在大型应用中管理复杂用户界面的问题…...

CPU飙升100%怎么办?字节跳动面试官告诉你答案!

小北说在前面 CPU占用率突然飙升是技术人员常遇到的一个棘手问题,它是一个与具体技术无关的普遍挑战。 这个问题可以很简单,也可以相当复杂。 有时候,只是一个死循环在作祟。 有时候,是死锁导致的。 有时候,代码中有…...

物理层(二)

2.2 传输介质 2.2.1 双绞线、同轴电缆、光纤和无线传输介质 传输介质也称传输媒体,是数据传输系统中发送器和接收器之间的物理通路。传输介质可分为:①导向传输介质,指铜线或光纤等,电磁波被导向为沿着固体介质传播:②)非导向传输介质&…...

C#——文件读取IO操作File类详情

文件读取操作 IO类 就是对应文件的操作的类I/O类 包含各种不同的类 用于执行各种文件操作,创建文件删除文件读写文件 常用的类: File处理文件操作的类 FilleStream用于文件当中任何位置的读写 File类 1.文件创建 File.Create() 在指定路径下创建…...

昨天gitee网站访问不了,开始以为电脑哪里有问题了

昨天gitee网站下午访问不了,开始以为是什么毛病。 结果同样的网络,手机是可以访问的。 当然就ping www.gitee.com 结果也下面那样是正常的 以为是好的,但就是访问www.gitee.com也是不行,后来用阿里云的服务器curl访问是下面情况&…...

深入理解适配器模式:Java实现与框架应用

适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户端希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以协同工作。在本篇博客中,我们将详细介绍适配器模式,并演示如何在Java中实现它。最后&#xff0…...

跌倒识别:守护公共安全的AI技术应用场景-免费API调用

随着科技的不断进步,人工智能在各个领域的应用日益广泛,其中在公共安全领域,智能跌倒识别系统正逐渐成为守护人们安全的重要工具。本文将分享智能跌倒识别系统在不同场景下的应用及其重要性。 产品在线体验地址-API调用或本地化部署 AI算法模…...

算法:渐进记号的含义及时间复杂度计算

渐进记号及时间复杂度计算 渐近符号渐近记号 Ω \Omega Ω渐进记号 Θ \Theta Θ渐进记号小 ο \omicron ο渐进记号小 ω \omega ω渐进记号大 O \Omicron O常见的时间复杂度关系 时间复杂度计算:递归方程代入法迭代法套用公式法 渐近符号 渐近记号 Ω \Omega Ω …...

idea导入文件里面的子模块maven未识别处理解决办法

1、File → Project Structure → 点击“Modules” → 点击“” → “Import Model” 2、可以看到很多子模块,选择子模块下的 pom.xml 文件导入一个一个点累死了,父目录下也没有pom文件 解决办法:找到子模块中有一个pom.xml文件,…...

IOS Swift 从入门到精通:协议和扩展

文章目录 协议协议继承扩展协议扩展面向协议的编程总结: 今天你将学习一些真正的 Swifty 功能:协议和面向协议的编程(POP)。 POP 摒弃了庞大而复杂的继承层次结构,代之以更小、更简单、可以组合在一起的协议。这确实应…...

Vue插件开发:Vue.js的插件架构允许开发者扩展Vue的核心功能,我们可以探讨如何开发一个Vue插件并与社区分享

了解Vue插件 Vue插件的概念: Vue插件用于为Vue.js添加全局级别的功能。它提供了一种开箱即用的机制来应用全局性的功能扩展。这些插件通常用来将全局方法或属性,组件选项,Vue实例的方法,或者注入一些组件选项比如mixins和自定义方法添加至Vue.js。 Vue插件的使用场景:…...

学习面向对象前--Java基础练习题

前言 写给所有一起努力学习Java的朋友们,敲代码本身其实是我们梳理逻辑的一个过程。我们在学习Java代码的过程中,除了需要学习Java的一些基本操作及使用,更重要的是我们需要培养好的逻辑思维。逻辑梳理好之后,我们编写代码实现需要…...

用Python实现抖音新作品监控助手,实时获取博主动态

声明: 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。包含关注,点赞等 该项目的主要功能是通过Python代码&…...

图像分隔和深度成像技术为什么受市场欢迎-数字孪生技术和物联网智能汽车技术的大爆发?分析一下图像技术的前生后世

图像分隔和深度成像是计算机视觉和图像处理领域的两项重要技术,它们各自有不同的技术基础和要点。 图像分隔技术基础: 机器学习和模式识别: 图像分隔通常依赖于机器学习算法,如支持向量机(SVM)、随机森林…...

Redis 内存策略

一、Redis 内存回收 Redis 之所以性能强&#xff0c;最主要的原因就是基于内存存储。然而单节点的 Redis 其内存大小不宜过大&#xff0c;会影响持久化或主从同步性能。 我们可以通过修改配置文件来设置 Redis 的最大内存&#xff1a; # 格式&#xff1a; # maxmemory <byt…...

Java小实验————斗地主

早期使用的JavaSE用到的技术栈有&#xff1a;Map集合,数组&#xff0c;set集合&#xff0c;只是简单实现了斗地主的模拟阶段&#xff0c;感兴趣的小伙伴可以调试增加功能 代码如下&#xff1a; import java.util.*;public class Poker {public static void main(String[] arg…...

【Oracle】Linux 卸载重装 oracle 教程(如何清理干净残留)系统 CentOS7.6

总览 1.停止监听 2.删除 Oracle 数据库实例 3.删除 Oracle 相关服务 4.删除 Oracle 服务脚本 5.清理 Oracle 软件和配置文件 6.强制卸载 Oracle 软件包 一、开始干活&#xff08;所有操作使用 root 权限&#xff0c;在 root 用户下执行&#xff09; 1.停止监听 lsnrctl sto…...

web中间件漏洞-Jenkins漏洞-弱口令、反弹shell

web中间件漏洞-Jenkins漏洞-弱口令、反弹shell Jenkins弱口令 默认用户一般为jenkins/jenkins 使用admin/admin123登陆成功 Jenkins反弹shell 格式为 println"命令".execute().text 在/tmp目录中生成shell.sh文件&#xff0c;并向其中写入反弹shell的语句 new…...

Linux开发讲课9--- Linux的IPC机制-内存映射(Memory Mapping)

Linux的IPC&#xff08;Inter-Process Communication&#xff0c;进程间通信&#xff09;机制是多个进程之间相互沟通的方法&#xff0c;它允许不同进程之间传播或交换信息。Linux支持多种IPC方式&#xff0c;包括但不限于&#xff1a; 管道&#xff08;Pipe&#xff09;&#…...

Java赋值运算符

Java赋值运算符分为以下&#xff1a; 符号 作用 说明 赋值 int a 10,把10赋值给变量a 加后赋值 ab,将ab的值赋值给变量a - 减后赋值 a-b,将a-b的值赋值给变量a* 乘后赋值 a*b,将a*b的值赋值给变量a / 除后赋值 a/b,将a/b的值赋值给变量a % 取余赋值 a%b,将a%b的值赋值给变量…...

Qt做群控系统

群控系统顾名思义&#xff0c;一台设备控制多台机器。首先我们来创造下界面。我们通过QT UI设计界面。设计界面如下&#xff1a; 登录界面&#xff1a; 登录界面分为两种角色&#xff0c;一种是管理员&#xff0c;另一种是超级管理员。两种用户的主界面是不同的。通过选中记住…...

【专业英语 复习】第10章 Information System

1. 单选题 (1分) An example of this type of report would be a sales report that shows that certain items are selling significantly above or below forecasts. () A. Inventory B. Demand C. Periodic D. Exception 正确答案&#xff1a; D 这种类型的报…...

09-axios在Vue中的导入与配置

09-axios 前言首先简单了解什么是Axios&#xff1f;以上完成后就可以使用了 前言 我们接着上一篇文章 08-路由地址的数据获取 来讲。 下一篇文章 10-vuex在Vue中的导入与配置 首先简单了解什么是Axios&#xff1f; Axios是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端…...

odoo17 小变更4

odoo17 小变更4 1、代码中去除了访问私人地址权限,但翻译中均还有,怪不 model:res.groups,name:base.group_private_addresses msgid "Access to Private Addresses" msgstr "" 代码也查看了,的确没有了此权限组 --><record model="res.g…...

Flink assignTimestampsAndWatermarks 深度解析:时间语义与水印生成

目录 概述 时间语义 时间戳分配 水印的作用 最佳实践 案例分析 注意事项 应用场景 概述 在Apache Flink中,assignTimestampsAndWatermarks是一个重要的方法,它允许数据流处理程序根据事件时间(event time)分配时间戳和生成水印(watermarks)。这个方法通常用于处理…...

C++排序算法——合并有序数组

合并有序数组 思路 我们可以设想一个排序的函数 这个函数里 我们有三个while while(第一次的执行条件) {先进行第一次的合并 } while(第二次的合并条件) { 把a数组在第一次没有排序上的给加进去 }while(第三次的合并条件) { 把b数组在第一次没有排序上的给加进去 }看完了这个…...

安装pytorch环境

安装&#xff1a;Anaconda3 通过命令行查显卡nvidia-smi 打开Anacanda prompt 新建 conda create -n pytorch python3.6 在Previous PyTorch Versions | PyTorch选择1.70&#xff0c;安装成功&#xff0c;但torch.cuda.is_available 返回false conda install pytorch1.7.0…...

内卷从古到今就一直存在,并不是近年的“新物”,破局在于你是否有意识地学习。

一.背景&#xff1a; 反思自己过去从学生时代到职场时代。“内卷”其实已经一直存在&#xff0c;从古到今都一直存在&#xff0c;也并不是近几年产出的“新物”。已经连续5年高考人数在1000万以上&#xff0c;而今年1300多万达到新高&#xff0c;对于竞争压力如此之大&#xf…...

跟《经济学人》学英文:2024年6月15日这期 The war for AI talent is heating up

The war for AI talent is heating up Big tech firms scramble to fill gaps as brain drain sets in 争夺人工智能人才的战争正在升温 随着人才流失的到来&#xff0c;大型科技公司争相填补空缺 brain drain&#xff1a;人才流失 scramble&#xff1a;争夺&#xff1b;争…...

港湾周评|高盛眼中的618增长

《港湾商业观察》李镭 年中最重要的购物节618终于尘埃落定了。2024年的618各大电商平台竞技情况如何&#xff1f;又有哪些新的亮点&#xff1f;都成为外界观察消费行为的参考指标。 根据京东618数据显示&#xff1a;累计成交额过10亿的品牌83个&#xff0c;超15万个中小商家销…...

SPSS知识

特点 SPSS的一些特点&#xff1a; 分析结果清晰、直观&#xff1a;SPSS提供了丰富的图表和表格&#xff0c;可以帮助用户直观地理解数据分析的结果。分析结果通常包含详细的统计量、图形和文本描述&#xff0c;使得分析结果易于解释。 易学易用&#xff1a;SPSS的用户界面设计…...

【网络安全的神秘世界】关于Linux中一些好玩的字符游戏

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 佛祖保佑 把 motd 通过xtp拖到Linux中 liyangUbuntu2204:~$ cp motd /etc/motd #一定要放在etc下 liyangUbuntu2204:~$ exi…...

【LeetCode】Hot100:验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树 只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 英文题目 Given the root…...

[Qt] Qt Creator 编译输出乱码,问题页中的报错、警告内容,编译输出乱码

确保文件编码为"UTF-8"&#xff0c;"如果编码是UTF-8则添加"&#xff0c;如下图&#xff1a; 设置IDE环境语言跟随系统语言&#xff0c;Text codec for tools&#xff1a; "System" 瑞斯拜...

sed

1、sed的定义 sed是一种流编辑器&#xff0c;按行处理&#xff0c;一次处理一行内容 处理方式&#xff1a;如果只是展示&#xff0c;会放在缓冲区&#xff08;模式空间&#xff09;&#xff0c;展示结束后&#xff0c;会从模式空间把操作结果删除 一行一行处理&#xff0c;处…...

C++一文讲透thread中的detach和join的差别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、thread详解二、线程何时运行三、线程启动方式1.join2.detach 总结 前言 无论哪种语言线程在绝大多数项目中都是会用到的&#xff0c;C也一样&#xff0c;C…...

当Windows台式电脑或笔记本电脑随机关机时,请先从这8个方面检查

序言 你的Windows笔记本电脑或PC是否意外关闭?笔记本电脑电池故障、电源线松动、过热、电源设置错误、驱动程序过时或电脑组件故障等问题都可能是罪魁祸首。如果你对这个问题感到沮丧,试试这些解决方案。 进行一些初步检查 与从电池中获取电力的笔记本电脑不同,台式电脑依…...

【凤凰房产-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

【建议收藏】逻辑回归面试题,机器学习干货、重点。

. . . . . . . . . . .纯 干 货 . . . . . . . . . . . .今天是机器学习面试题&#xff0c;16大块的内容&#xff0c;124个问题总结的第二期&#xff1a;逻辑回归面试题。 逻辑回归是一种用于解决分类问题的统计学习方法&#xff0c;尤其在二分类…...

C++使用教程

目录 一、软件使用 二、C基础规则补充 关键字 整型取值范围 浮点型取值范围 字符型使用规则 字符串型使用规则 布尔类型 常用的转义移字符 三、数组、函数、指针、结构体补充 1.数组 2.函数 声明&#xff1a; 分文件编写&#xff1a; 值传递&#xff1a; 3.指…...