这篇博客主要解决3个问题:
1、如何在对话框资源上创建菜单,用菜单项控制工具栏和状态栏的显示与隐藏;
2、如何在对话框资源上创建工具栏,并实现工具栏上按钮的响应;
3、如何在对话框资源上创建状态栏,在状态栏分别获取系统时间、鼠标位置、进度条。
希望对读者提供参考价值,也方便自己以后查阅。
首先用MFC向导创建对话框资源class CAddSourceDlg,然后在对话框类中声明需要创建的资源:
private:
CMenu m_menu; //菜单
CToolBar m_toolbar; //工具栏
CStatusBar m_statusbar; //状态栏
CProgressCtrl m_progress; //进度条
在资源窗口编辑菜单资源,如下:
第一个参数的值取决于第二个参数,这在上一篇博文中有提到。
//创建菜单
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
//设置标记菜单
GetMenu()->GetSubMenu(0)->CheckMenuItem(2, MF_CHECKED|MF_BYPOSITION);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_DISP_STATUSBAR, MF_CHECKED|MF_BYCOMMAND);
菜单创建好了,添加前两个菜单项的响应函数如下:
void CAddSourceDlg::OnPrintT()
{
// TODO: Add your command handler code here
MessageBox("print T");
}
void CAddSourceDlg::OnPrintI()
{
// TODO: Add your command handler code here
MessageBox("print I");
}
然后在资源窗口编辑工具栏资源。由于工具栏相当于菜单的快捷方式,所以工具栏的按钮ID必须和关联菜
单项的ID一致,共用同一个响应函数。这里讲将工具栏按钮T和按钮I的ID分别设置成菜单项“打印“T””和打印“I”的ID。
然后在成员函数OnInitDialog中将工具栏资源添加到对话框。
//创建工具栏
m_toolbar.CreateEx(this); //创建空白工具栏
m_toolbar.LoadToolBar(IDR_TOOLBAR1); //加载工具栏资源
CRect rect;
GetClientRect(&rect); //计算客户区大小
m_toolbar.MoveWindow(0,0,rect.Width(), 25); //必须设置工具栏显示位置
运行程序,发现点击工具栏按钮和点击对应菜单项都会调用相同的响应函数,证明创建的工具栏没有问题。
由于在创建状态栏时需要设置各元素的ID,所以现在头文件resource.h中定义好然后在成员函数OnInitDialog中将状态栏资源添加到对话框。其中状态栏第一个元素用来显示系统时间,第二个元素用来指示鼠标位置,第三个元素用来表示进度条。
//创建状态栏
//创建定时器,由于重载了基类消息响应函数,因此第三个参数可以为NULL
SetTimer(ID_TIMER, 1000, NULL);
static UINT indicators[] = //指定状态栏上三个元素的ID
{
IDS_TIME,
IDS_PROGRESS,
IDS_MOUSE
};
m_statusbar.Create(this); //创建空白状态栏
//设置状态栏上元素的ID及元素数量
m_statusbar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
//设置状态栏3个元素的宽度
m_statusbar.SetPaneInfo(0, IDS_TIME, SBPS_NORMAL, rect.Width()/3);
m_statusbar.SetPaneInfo(1, IDS_MOUSE, SBPS_NORMAL, 80);
m_statusbar.SetPaneInfo(2, IDS_PROGRESS, SBPS_STRETCH, 100);
//必须重新设置和调整状态栏大小,否则无法显示
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);
因为显示系统时间要不断刷新,所一上面创建了一个时间间隔为1秒触发事件的定时器,响应函数为基类的虚函数。这里可以重写虚函数,定义我们自己的虚函数。每隔1秒钟,重新获取系统时钟,并显示在对应状态栏上。
void CAddSourceDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CString strTime;
CTime time = CTime::GetCurrentTime();
strTime.Format("%d:%d:%d", time.GetHour(),time.GetMinute(),time.GetSecond());
//确定字符串长度
// CClientDC dc(this);
// CSize sz = dc.GetTextExtent(strTime);
// m_statusbar.SetPaneInfo(0, IDS_TIME, SBPS_NORMAL, sz.cx);
m_statusbar.SetPaneText(0, strTime);
//每过1s,进度条自动增长
//m_progress.StepIt();
CDialog::OnTimer(nIDEvent);
}
因为要在状态栏上显示鼠标位置,这里在对话框类中定义一个鼠标移动的消息响应函数
void CAddSourceDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString strPoint;
strPoint.Format("%d,%d", point.x,point.y);
m_statusbar.SetPaneText(1, strPoint);
CDialog::OnMouseMove(nFlags, point);
}
然后成员函数OnInitDialog中创建进度条资源
//创建进度条
CRect rectPro;
m_statusbar.GetItemRect(2, &rectPro); //获取状态栏元素2的区间大小
//注意此处进度条的父窗口设置为状态栏
m_progress.Create(WS_CHILD|WS_VISIBLE, rectPro, &m_statusbar, ID_PROGRESS);
//设置初始位置
m_progress.SetPos(50);
//设置步长
m_progress.SetStep(5);
也可以在定时响应函数中递增进度。最后还要实现菜单项控制工具栏和状态栏的显示、隐藏,添加其余两个菜单项的消息响应函数如下:
void CAddSourceDlg::OnDispToolbar()
{
// TODO: Add your command handler code here
if (m_toolbar.IsVisible())
{ //如果工具栏处于可见状态,则隐藏,并将菜单的标记撤除
m_toolbar.ShowWindow(SW_HIDE);
GetMenu()->GetSubMenu(0)->CheckMenuItem(2, MF_UNCHECKED|MF_BYPOSITION);
}
else
{
//如果工具栏处于不可见状态,则消失,并添加菜单标记
m_toolbar.ShowWindow(SW_SHOW);
GetMenu()->GetSubMenu(0)->CheckMenuItem(2, MF_CHECKED|MF_BYPOSITION);
}
}
void CAddSourceDlg::OnDispStatusbar()
{
// TODO: Add your command handler code here
if (m_statusbar.IsVisible())
{
m_statusbar.ShowWindow(SW_HIDE);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_DISP_STATUSBAR, MF_UNCHECKED|MF_BYCOMMAND);
}
else
{
m_statusbar.ShowWindow(SW_SHOW);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_DISP_STATUSBAR, MF_CHECKED|MF_BYCOMMAND);
}
}
运行程序,显示正常,虽然简陋,但是方法还算易懂。