本章主要是学习窗口的创建,修改以及图标,菜单栏的等知识点。
首先:
1.修改外观和图标可以在MainFrm中进行,而修改背景和光标只能在View中进行。为什么?因为view的显示挡在了MainFrame的前面。
a.在MainFrame中
PreCreateWindow()中,在窗口创建之前,用重新注册窗口类的方法,这样比较麻烦:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
/*
WNDCLASS CS;
CS.cbClsExtra = 0;
CS.cbWndExtra = 0;
CS.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
CS.hCursor = LoadCursor(NULL, IDC_CROSS);
CS.hIcon = LoadIcon(NULL, IDI_ERROR);
CS.lpszClassName = "sunxin.org";
CS.hInstance = AfxGetInstanceHandle();
CS.lpfnWndProc = ::DefWindowProc;
CS.style = CS_VREDRAW | CS_HREDRAW;
CS.lpszMenuName = NULL;
RegisterClass(&CS);
cs.lpszClass = "sunxin.org";
其中:preCreatWindow 是虚函数,且传递类型是引用,所以要修改窗口的大小和外观,只要改变对应的参数就可以。
但是这样比较麻烦,可以选择用全局函数AfxRegisterWndClass()来修改。
//cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));
其中的HCursor hCursor 和HBRUSH hbrbackgroud 表示的是光标和画布,只能是在view函数里面修改。
修改外观和图标可以在MainFrm中进行,而修改背景和光标只能在View中进行。为什么?因为view的显示挡在了MainFrame的前面。
在View中:
b.在ViewPreCreateWindow()中
//cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
// LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),NULL);
在窗口创建之后,在OnCreate()中修改
//SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
//SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) & ~WS_MAXIMIZEBOX);
// SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
OnCreate()中
SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));
由上可知;我们如果要修改弹出窗口的名称时,可以
cs.lpszName = "sunxin.org";
cs.style &= ~FWS_ADDTOTITLE;
但是
二:创建一个变化的图标
用函数setClassLong 和 setTimer两个函数
首先先在CMainFrame中新建个m_hIcons[n]数组。接着
m_hIcons[0] = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));//AfxGetInstanceHandle(),表示获取当前应用程序的实例句柄,MAKEINTRESOURCE是一个宏,它将实例句柄的地址整数转化为Win32的资源类型,简单的说它是一个类型转换#define
m_hIcons[1] = LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));//应用全局对象theAPP来获取句柄实例。但是前提是得在CMainFrame中添加外部变量的声明:extern style theAPP;
m_hIcons[2] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON3));//应用全局变量AfxGetAPP来获取实例地址.
然后在int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)中添加
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[0]);// 将第一个图标设置为弹出窗口的第一个显示。
SetTimer(1, 1000,NULL);//时间设置为1S,其中NULL表示的是按照系统的。
然后在:新建个Timer宏变量:
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int index = 0;
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
index = ++index%3;//表示的是经过3S就自动循环
CFrameWnd::OnTimer(nIDEvent);
}
注:如果希望把某个数限定在一定的范围内,可以对此进行取模运算(%)实际上就是取余运算。
三:工具栏的编程
3.1
a.加入分隔符的方法,向右拖动即可;
b.删除按纽的方法,拖出即可。
3.2 创建工具栏
首先创建工具栏同时在新建个CToolBar m_wndToolBar1;
在int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)中
if (!m_wndToolBar1.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar1.LoadToolBar(IDR_TOOLBAR1))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
m_wndToolBar1.EnableDocking(CBRS_ALIGN_ANY);//第一个EnableDocking是工具看对象成员函数,允许工具栏对象停靠
EnableDocking(CBRS_ALIGN_ANY);//允许主对话框被停靠
DockControlBar(&m_wndToolBar1);//让工具栏停靠在主窗口
但是这样的工具栏有个问题:怎样显示设置好的工具栏:
方法一:void CMainFrame::OnToolBar1()
{
// TODO: Add your command handler code here
//第一种显示工具栏的方法,但是第一种有个缺陷是:工具栏出于悬浮时,就不能出现在原来的位置。
/*
if (m_wndToolBar1.IsWindowVisible())//工具栏也是窗口,具有cwn窗口的属性
{
m_wndToolBar1.ShowWindow(SW_HIDE);
}
else
{
m_wndToolBar1.ShowWindow(SW_SHOW);
}
// 调用上面的显示和隐藏时,工具栏的工具条还在
// 改函数有一个BOOL类型参数:bNotify。如果该参数是真,则框架窗口上的活动对象会收到布局变动的通知。
// 如果为假,则不会。默认值为TRUE
RecalcLayout();//调用框架类的函数,重新放置工具栏的位置
DockControlBar(&m_wndToolBar1);//当工具栏被拖出来时,重新调用该函数,来重新放置
但是该方法是有个缺点:工具栏的位置隐藏后再次点击会出现在最上面
*/
方法二:
ShowControlBar(&m_wndToolBar1, !m_wndToolBar1.IsWindowVisible(), FALSE);
}
最后在菜单栏添加复选标记
void CMainFrame::OnUpdateToolBar1(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(m_wndToolBar1.IsWindowVisible());
}
第四节:状态栏编程
状态栏的类: CStatusBar 也是个窗口类
对应的状态栏地址
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator状态栏
IDS_TEMP,
IDS_PROGRESS,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
首先要新建个状态栏窗格,应在ResourceView类下面的String Table下面新建字符串ID
在此想在状态栏显示时间应在OnCreate()下面新建个
//显示系统时间
CTime t = CTime::GetCurrentTime();
CString s = t.Format( "%H:%M:%S");
但是有个问题:不能完全显示时间。对此应该要重新设置窗格的大小
/ CClientDC:(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让
// 开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC。
CClientDC dc(this);
CSize sz= dc.GetTextExtent(s);
//获取当前索引的地址
int index = m_wndStatusBar.CommandToIndex(IDS_TEMP);
m_wndStatusBar.SetPaneInfo(index, IDS_TEMP, SBPS_NORMAL, sz.cx);//获取当前时间对应的宽度
m_wndStatusBar.SetPaneText(index, s, TRUE);//显示时间窗格
如果可以知道index的值 就可以直接写数字就可以。
然后在void CMainFrame::OnTimer(UINT nIDEvent) 函数中设置时间栏
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int index = 0;
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
index = ++index%3;
CTime s = CTime::GetCurrentTime();
CString str = s.Format("%H:%M:%S");
CClientDC dc(this);
CSize sz = dc.GetTextExtent(str);
m_wndStatusBar.SetPaneInfo(1, IDS_TEMP, SBPS_NORMAL, sz.cx);//重新设置时间栏
//原型为BOOL SetPaneText(int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE)
// 其中的lpszNewText为指向新的窗格文本的指针 bUpdata是否立即更新?true
m_wndStatusBar.SetPaneText(1, str);//设置显示状态栏窗格文本
设置进度栏:
//设置进度栏,其中的CRect()分别表示的是左横坐标,左宗坐标,和右边的横纵坐标
// m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH, CRect(100,100,300,115), this, 123);
// m_progress.SetPos(10);
但是我们要在状态栏设置进度栏就应该要
先新建个CRect rect,然后引用// m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH, &rect, &m_wndStatusBar, 123);
m_progress.SetPos(10);
接下来我们要让工具栏动起来。。具体必须调用CprogressCtrl::SetIt()函数,该函数表示进度栏以预先设定的速度增加,要设定预先的每步步长,可以用CprogressCtrl::stepSet()函数,默认值为10,这些必须是在CMainFrame::Ontimer()函数中设定。
五:在状态栏显示鼠标
首先调用捕获鼠标移动的消息:WM_MOUSEMOVE消息响应函数。
void CLesson9StyleView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString str;
str.Format("x = %d, y = %d", point.x, point.y);
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str)
// ((CMainFrame*)GetParent())->SetWindowText(str);这个是
CView::OnMouseMove(nFlags, point);
}
注:
首先格式化当前的鼠标信息,然后为了将该信息显示在状态栏的第一个窗格上,需要捕获状态栏对象,捕获鼠标的可以调用SetWindowText()函数,但是,但是状态栏是在框架类中定义的,同时框架类窗口是视窗类的父窗口,因此在视窗类对象中调用GetParent()函数就可以得到视窗类的父窗口,即框架窗口。因此该函数返回的是一个CWnd的指针,而这里需要的是CMainFrame的指针,因此进行强制转化,然后在应用CMainFrame窗口类调用该对象内部的状态栏成员变量:
M_wndStatusBar(),但是要注意修改该对象的属性为Public
注意:状态栏不属于视类窗口,而是属于框架类窗口
六:启动画面
在project下选择Add to Project 下面的