标签:
Windows-定制程序外观
简介:介绍常用的应用程序外观属性的操作
一 修改应用程序窗口的外观
1.在窗口创建之前修改
需要在框架窗口的CMainFrame::PreCreateWindow函数中进行操作。
添加如下代码,可以更改窗口的大小和标题
#if 1
cs.cx = 400;
cs.cy = 300;
//设置自定义标题的两种方法
//cs.style &= ~FWS_ADDTOTITLE;
cs.style = WS_OVERLAPPEDWINDOW;
cs.lpszName = _T("chengzhi");
#endif
2.在窗口创建之后修改
需要在CMainFrame::OnCreate函数中操作
添加如下代码,去掉程序标题(文档标题),
#if 1
//窗口创建之后改变外观
SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
#endif
如果想要在已有的窗口风格的基础上修改可以使用下面的代码
GetWindowLong函数和SetWindowLong相对应
#if 1
//在窗口创建之后去掉窗口的最大化按钮
SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
#endif
二 修改窗口的光标,图标和背景
1.在窗口创建之前修改
需要在CMainFrame::PreCreateWindow函数中操作
方法一:自己定义一个窗口类并注册,但是不建议这种方法,太麻烦了。
#if 1
//不建议使用的方法,改变图标,光标等属性
WNDCLASS ws;
ws.cbClsExtra = 0;
ws.cbWndExtra = 0;
ws.hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
ws.hCursor = LoadCursor(nullptr, IDC_HELP);
ws.hIcon = LoadIcon(nullptr, IDI_ERROR);
ws.hInstance = AfxGetInstanceHandle();
ws.lpfnWndProc = ::DefWindowProc;
ws.lpszClassName = _T("chengzhi");
ws.lpszMenuName = nullptr;
ws.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&ws);
cs.lpszClass = _T("chengzhi");
#endif
注意:在框架类中只能修改图标,如果要修改背景和光标则需要找View类中操作。
在CStyleView::PreCreateWindow中设置新的窗口类,来修改背景和光标
#if 1
cs.lpszClass = _T("chengzhi");
#endif
方法二:使用全局函数AfxRegisterWndClass
在框架类中修改图标
#if 1
//建议使用的方法
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 0, 0, LoadIcon(nullptr, IDI_WARNING));
#endif
在View类中修改背景和光标
#if 1
//在view中修改客户区中的属性
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, LoadCursor(nullptr, IDC_CROSS), static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
#endif
2.在窗口创建之后修改
在框架类的CMainFrame::OnCreate函数中修改图标属性,具体的API大家可以查看MSDN的帮助:https://msdn.microsoft.com/library
#if 1
//窗口创建之后改变外观
SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
#endif
在View类中修改背景和光标属性
#if 1
//在视图窗口创建完毕之后设置背景和鼠标指针的图标
SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH));
SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(nullptr, IDC_HELP));
#endif
三 切换应用程序图标
既然是是切换应用程序的图标,那就要在框架类中操作了
先定义一个图标数组
private:
//存储图标的数组
HICON m_hIcons[3];
在CMainFrame::OnCreate函数中切换,MAKEINTRESOURCE宏将指定的ID转换成字符串
#if 1
//初始化图标数组,我们分别使用了3种方法
m_hIcons[0] = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON1));
//需要在这个函数的.cpp文件中声明theApp全局对象
//extern CStyleApp theApp;
m_hIcons[2] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON3));
//设置定时器,id = 1, 定时1000ms,1s切换一个图标
SetTimer(1, 1000, nullptr);
//初始化就设置第一幅图标
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[0]);
#endif
为框架类添加定时器WM_TIMER的事件响应
在 CMainFrame::OnTimer响应函数中添加如下代码:
#if 1
//因为初始化显示的是第一幅,所以这里设置index = 1,而不是0
static int index = 1;
//设置App图标
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
//使用取模运算, 将index限定在0-2之内
index = (++index) % 3;
#endif
四 工具栏(ToolBar)编程
1.注意:ToolBar中的ID对应于菜单栏中的菜单项的ID,我们一般都是先开发菜单栏,然后将常用的菜单项操作提供到工具栏中。
2.创建ToolBar
先看看它的继承层次
创建工具栏仍然需要在框架类中创建
(1).创建工具栏资源
自己创建一个类似系统那样的位图图片即可
(2).构造CToolBar对象
private:
//自定义的新的工具栏
CToolBar m_newToolBar;
(3).Create()/CreateEx(),LoadToolBar
#if 1
//创建自定义工具栏
if (!m_newToolBar.CreateEx(this,
TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER
| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_newToolBar.LoadToolBar(IDR_TOOLBAR1)) {
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}
//设置工具栏可以停靠
m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);
//设置主框架窗口可以被停靠
EnableDocking(CBRS_ALIGN_ANY);
//停靠工具栏
DockControlBar(&m_newToolBar);
#endif
3.添加菜单项来管理工具栏
添加一个菜单项,并添加事件响应,在响应函数中添加入下代码
void CMainFrame::OnShowMyToolBar()
{
#if 0
//复杂的显示方法,而且不能在上次显示的地方重新显示
if (m_newToolBar.IsWindowVisible()) {
m_newToolBar.ShowWindow(SW_HIDE);
}
else {
m_newToolBar.ShowWindow(SW_SHOW);
}
//框架窗口上的活动对象会受到布局变动的通知
RecalcLayout();
DockControlBar(&m_newToolBar);
#endif
#if 1
//简单的方法,在上次隐藏的地方重新显示
ShowControlBar(&m_newToolBar, !m_newToolBar.IsWindowVisible(), FALSE);
#endif
}
我们完善这个菜单项,加上复选标记,为刚才添加的菜单项添加命令更新消息,在消息响应函数中这样处理
void CMainFrame::OnUpdateShow(CCmdUI *pCmdUI)
{
// TODO: 在此添加命令更新用户界面处理程序代码
#if 1
//设置复选标记的状态
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
#endif
}
五 状态栏(CStatusBar)编程
1.在框架类中添加自己的状态栏
框架类已经定义了状态栏成员变量
public:
CStatusBar m_wndStatusBar;
添加新的状态指示器标示
//状态栏的指示器数组,资源ID是自己定在字符串资源中的
static UINT indicators[] =
{
ID_SEPARATOR, // 状态行指示器
IDS_TIMER, //时间指示器
IDS_PROGRESS, //进度条指示器
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
在CMainFrame::OnCreate函数中设置我们的添加的状态指示器显示系统当前时间
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
...
#if 1
//状态栏显示时间
SetTimer(1, 1000, nullptr);
//设置状态栏时间
CTime t = CTime::GetCurrentTime();
CString str = t.Format("%H:%M:%S");
//知道IDS_TIMER的索引是1
//m_wndStatusBar.SetPaneText(1, str);
/*不知道状态栏网格的索引*/
CClientDC dc(this);
CSize sz = dc.GetTextExtent(str);
//根据ID获取网格的索引
int index = m_wndStatusBar.CommandToIndex(IDS_TIMER);
//设置状态栏网格的宽度
m_wndStatusBar.SetPaneInfo(index, IDS_TIMER, SBPS_NORMAL, sz.cx);
//设置网格内容
m_wndStatusBar.SetPaneText(index, str);
#endif
...
在定时器的响应函数中更新时间,这里只是实例,没有抽取成一个函数,实际开发过程中,不能出现这样的重复代码
void CMainFrame::OnTimer(UINT_PTR nIDEvent) {
...
#if 1
//设置状态栏时间
CTime t = CTime::GetCurrentTime();
CString str = t.Format("%H:%M:%S");
//知道IDS_TIMER的索引是1
//m_wndStatusBar.SetPaneText(1, str);
/*不知道状态栏网格的索引*/
CClientDC dc(this);
CSize sz = dc.GetTextExtent(str);
//根据ID获取网格的索引
int index = m_wndStatusBar.CommandToIndex(IDS_TIMER);
//设置状态栏网格的宽度
m_wndStatusBar.SetPaneInfo(index, IDS_TIMER, SBPS_NORMAL, sz.cx);
//设置网格内容
m_wndStatusBar.SetPaneText(index, str);
#endif
...
CFrameWnd::OnTimer(nIDEvent);
}
2.在状态栏中显示鼠标位置
我们需要得到鼠标的位置,我们就需要在View类中捕获WM_MOUSEMOVW消息进行。
下面提供的几种方法都可以实现功能
void CStyleView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CString str;
str.Format(_T("x = %d, y = %d"), point.x, point.y);
#if 0
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
#endif
#if 0
//设置状态栏的第一个网格的文本
((CMainFrame*)GetParent())->SetMessageText(str);
#endif
#if 0
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);
#endif
#if 1
//获取子孙窗口
GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);
#endif
CView::OnMouseMove(nFlags, point);
}
6.进度栏编程
1.在框架类的OnCreate中创建一个进度栏
#if 0
//创建水平进度条
//m_progress.Create(WS_CHILD | WS_VISIBLE, CRect(100, 100, 200, 120), this, 123);
//创建垂直进度条
m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL, CRect(100, 100, 120, 200), this, 123);
m_progress.SetPos(50);
#endif
2.在状态栏中创建进度栏
我们采用发送自定义消息的方式来创建。
1.自定义一个自己用户的消息
MainFrm.h
#define UM_PROGRESS WM_USER + 1
2.添加消息映射声明
// 生成的消息映射函数
protected:
afx_msg LRESULT OnProgress(WPARAM wParam, LPARAM lParam);
3.定义消息映射
MainFrm.cpp
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
...
ON_MESSAGE(UM_PROGRESS, &CMainFrame::OnProgress)
...
END_MESSAGE_MAP()
4.定义消息响应函数
LRESULT CMainFrame::OnProgress(WPARAM wParam, LPARAM lParam) {
//在状态栏中显示进度条
CRect rect;
m_wndStatusBar.GetItemRect(2, &rect);
m_progress.Create(WS_CHILD | WS_VISIBLE, rect, &m_wndStatusBar, 123);
m_progress.SetPos(50);
return 0;
}
5.让进度栏动起来
在前面设置的定时器的处理函数中,我们增加进度栏的进度百分比,实现动态的效果。
#if 1
//设置进度栏的步长
//m_progress.SetStep(1);
//增加进度栏的步长
m_progress.StepIt();
#endif
6.为了能在窗口大小改变的时候,保持进度条的位置不变,需要为框架类捕获WM_PAINT消息,在此消息中重新设置进度栏的位置,但是这样出现错误,原因还没找到,大家发现原因可以邮件告诉我,学习了。
void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CFrameWnd::OnPaint()
#if 0
//在状态栏中显示进度条,有问题
CRect rect;
m_wndStatusBar.GetItemRect(2, &rect);
if (!m_progress.m_hWnd) {
m_progress.Create(WS_CHILD | WS_VISIBLE, rect, &m_wndStatusBar, 123);
}
else {
m_progress.MoveWindow(rect);
}
m_progress.SetPos(50);
#endif
}
7.总结
资料:https://yunpan.cn/cSIuhhchmL7ZH 访问密码 bf13
欢迎指正
标签:
原文地址:http://blog.csdn.net/qq_22075977/article/details/51570112