一、改变窗口的风格
1、CWnd::PreCreateWindow((CREATESTRUCT& cs)函数是虚函数,重新定义后,可以在其中通过改变cs的某些值,来实现在窗口创建前改变窗口的风格。
利用MFC创建的单文档程序,MFC将框架窗口类的style设置为FWS_ADDTOTITLE | WS_OVERLAPPEDWINDOW ,其中FWS_ADDTOTITLE的含义是将打开文档名添加到框架的标题上,即用文档名代替框架的标题。若想去掉此选项,只需将框架窗口与 &(~FWS_ADDTOTITLE) 作运算即可。
2、在窗口创建后改变窗口的风格,可以使用函数LONG SetWindowLong( HWND hWnd, // handle to window
(此函数在平台SDK和CWindow中均有定义) int nIndex, // offset of value to set
(本函数可以改变窗口的style、窗口过程函数等) LONG dwNewLong) // new value 新值
在窗口创建之后改变其风格,可以在OnCreate()函数的后面进行。
GetWindowLong(HWND hWnd, int nIndex)获取指定窗口的特定值。
AfxGetInstanceHandle()函数,可以获取当前应用程序的句柄。
(1)因为窗口的背景、光标、图标等内容是在窗口类的定义时确定的,所以若要改变窗口的背景、光标、图标等内容,我们在PreCreateWindow(CREATESTRUCT& cs)中改变cs的值是无法实现的;(较笨拙的方法:)我们需要定义新的窗口类,并注册之,且将我们新定义的窗口类名赋值给cs.lpszClass,如cs.lpszClass="sunxin.org";
又因为视类是覆盖在框架类之上的,所以在框架类的PreCreateWindow()函数中改变窗口的图标,在视类的PreCreateWindow()函数中改变窗口的背景和光标。
(2)较以简单的方法:调用全局函数LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 ),即可改变窗口类的样式、光标、背景、图标等;且其返回值是我们改变后的新窗口类的名字。
(3)(较灵活的方法:)在窗口创建之后改变其背景、光标、图标,通过函数DWORD SetClassLong( HWND hWnd, // handle to window
int nIndex, // index of value to change
LONG dwNewLong ) // new value
导入图标,并加载,加载使用LoadIcon(HINSTANCE hInstance, // handle to application instance 可以通过AfxGetInstanceHandle()获取;也可以通过CWinApp的成员变量m_hInstance来获取;也可以通过AfxGetApp()->m_hInstance,先获取该应用程序的指针,在调用其中的成员变量。
LPCTSTR lpIconName) // name string or resource identifier 可以通过宏MAKEINTRESOURCE(IDI_ICON1),该宏可以通过资源的ID获取资源对应的资源名称(name)。
在一个源文件2中使用另一个源文件1中定义的全局变量,需要在源文件2中使用该全局变量之前,声明该全局变量,如 extern CStyleApp theApp; ,此语句只是声明,而非定义。
二、工具栏
1、一般工具栏的按钮ID和我们的某单项的ID是一致的。
2、创建工具栏按钮间的分隔符,左键点击该按钮,轻轻向右稍微拖动即可;删除工具栏按钮,将按钮拖到工具栏以外的某地方即可,直接安delete按钮,并不能删除该按钮,只是删除了该按钮上的位图。
代码: m_newToolBar.EnableDocking(CBRS_ALIGN_ANY); //使工具栏可以停靠
DockControlBar(&m_newToolBar); //使框架窗口可以被停靠
3、显示、隐藏工具栏
方法一:通过判断,调用ShowWindow()函数,依据不同的参数或者SW_HIDE,或者SW_SHOW,即可完成。
CWnd::IsWindowVisible()函数用于判断窗口是否可视。
virtual void CFrameWnd::RecalcLayout(BOOL bNotify = TRUE)函数用于重新计算工具栏的停靠位置,在我们改变了工具条的位置,或隐藏工具条后,应当调用该函数,该函数调用完成后,一般还要再次调用DockControlBar()函数。
方法二:调用void CFrameWnd::ShowControlBar( CControlBar* pBar, BOOL bShow, BOOL bDelay )
注:一般我们的菜单项和工具栏的按钮变灰,可以分为两种情况:1、我们没有给我们新建的菜单项或工具栏按钮添加消息处理函数;2、我们使相应的项不使能了。
状态栏被一个指示器分成许多个小窗格(面板Pane),其个数由指示器中字符串的个数决定,其中ID_SEPARATOR是文本显示窗格,用于显示提示信息,我们称其为“提示行”;指示器的索引是从0开始的。
static CTime::GetCurrentTime()函数返回一个包含当前时间的CTime类对象,因其是静态函数,所以要静态调用,即如ct=CTime::GetCurrentTime();然后使用CTime::Format("%H:%M:%S")函数将时间信息格式化到一个字符串中,即将本函数的返回值赋值给某个CString类对象。
CStatusBar::SetPaneText()函数用于设置状态栏中某窗格(面板)的文本;CStatusBar::CommandToIndex()函数用于通过字符串的ID获取其对应的面板在状态栏中的索引;CStatusBar::SetPaneInfo()函数用于设置状态栏中某面板的显示宽度。
SendMessage()和PostMessage()的区别:SendMessage()是自动调用所发消息消息的消息处理函数,待消息处理函数完成后,本函数才返回,(即发送后直接处理);PostMessage()是将发送的的消息放入消息队列中,然后,GetMessage()函数依次从消息队列中取出消息进行处理。(此两函数的区别有点像同步和异步的区别:一个是发送后不管,一个是造成阻塞,完成后才返回)
当调试程序时,出现“重试”,“忽视”,“终止”这种警告框时,我们可以考虑是不是某种同样(同名)的资源被创建了两次,如某窗口,状态栏等。
第一次创建窗口的时候,MFC会自动地调用OnPaint函数来绘制窗口,其调用在OnCreate()之后。
一个进度栏的创建和工具栏,状态栏等的创建类似,就是:先定义相应的对象,然后在OnCreate()中调用其Create()函数来创建。
CProgressCtrl::SetPos()函数用于设置进度栏的进度。
CStatusBar::GetItemRect(HTREEITEM hItem,LPRECT lpRect)函数可通过状态栏中某窗格的ID得到其矩形区域,其中参数一为面板索引,参数二接受本函数返回的矩形。
在OnCreate()函数返回之前,状态栏中的各面板的位置还没有完全确定,因此,其各个面板的矩形区域时
----------------------------------------------------------------------------------------------
在窗口创建前修改
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
TODO: Modify the Window class or styles here by modifying
the CREATESTRUCT cs
cs.cx=300;
cs.cy=200;
cs.style&=~FWS_ADDTOTITLE; //去掉无标题
cs.style=WS_OVERLAPPEDWINDOW;
cs.lpszName="http://www.sunxin.org";
WNDCLASS wndcls; //方法一
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //修改背景
wndcls.hCursor=LoadCursor(NULL,IDC_HELP); //修改光标
wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //修改图标
wndcls.hInstance=AfxGetInstanceHandle();
wndcls.lpfnWndProc=::DefWindowProc; //因为CWnd类中有成员函数DefWindowProc,但其参数与我们标准的窗口过程函数个数不匹配,所以不能使用,这里我们使用平台的窗口过程函数。
wndcls.lpszClassName="sunxin.org";
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls); //CWnd类中没有成员函数RegisterClass()
//疑问:是不是若在代码中使用了本类中没的成员函数,MFC是不是自动去调用平台的此函数?回答:YES!!
cs.lpszClass="sunxin.org";// 关键:将我们要绘制的窗口类的类名改为我们自己刚定义的新窗口类的类名。
//方法二
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0, LoadIcon(NULL,IDI_WARNING));
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
return TRUE;
}
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
TODO: Modify the Window class or styles here by modifying
the CREATESTRUCT cs
cs.lpszClass="sunxin.org"; //方法一:在视类中调用自定义的类,使修改的背景、光标生效
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0); //方法二
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
return CView::PreCreateWindow(cs);
}
-------------------------------------------------------------------------------------------------
在窗口创建后修改
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ ......
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); //使工具栏可以停靠
EnableDocking(CBRS_ALIGN_ANY); //使框架窗口可以被停靠
DockControlBar(&m_wndToolBar); //(完成)停靠工具栏这个动作
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));
}
int CStyleView::OnCreate(LPCREATESTRUCT lpCreateStruct) //需要自己添加消息响应
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));
return 0;
}
-------------------------------------------------------------------------------------------------
模拟动画图标、创建工具栏、状态栏编程
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ ......
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); //使工具栏可以停靠
EnableDocking(CBRS_ALIGN_ANY); //使框架窗口可以被停靠
DockControlBar(&m_wndToolBar); //(完成)停靠工具栏这个动作
//动画图标
m_hIcons[0]=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1)); //获得当前句柄的三种方式
m_hIcons[1]=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));
m_hIcons[2]=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[0]);
SetTimer(1,1000,NULL);
//创建工具栏
if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_newToolBar.LoadToolBar(IDR_TOOLBAR1))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_newToolBar);
CTime t=CTime::GetCurrentTime(); //在状态栏设置时间
CString str=t.Format("%H:%M:%S");
CClientDC dc(this);
CSize sz=dc.GetTextExtent(str);
int index=0;
index=m_wndStatusBar.CommandToIndex(IDS_TIMER);
m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(index,str); //静止时间
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect);
m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL,CRect(100,100,120,200),this,123);
m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL,rect,&m_wndStatusBar,123);
m_progress.SetPos(50);
SendMessage(UM_PROGRESS);
PostMessage(UM_PROGRESS);
// CG: The following line was added by the Splash Screen component.
CSplashWnd::ShowSplashScreen(this);
return 0;
}
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int index=1; //循环三幅位图
SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[index]);
index=++index%3; //保持一个数在一个范围内的方法
CTime t=CTime::GetCurrentTime(); //使时间动起来
CString str=t.Format("%H:%M:%S");
CClientDC dc(this);
CSize sz=dc.GetTextExtent(str);
m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(1,str);
m_progress.StepIt(); //使进度条动起来
CFrameWnd::OnTimer(nIDEvent);
}
void CMainFrame::OnViewNewtool() //菜单项响应,使工具栏显示或隐藏
{
// TODO: Add your command handler code here
//方法一:悬浮的再出现后停靠在客户区顶部
if(m_newToolBar.IsWindowVisible())
{
m_newToolBar.ShowWindow(SW_HIDE);
}
else
{
m_newToolBar.ShowWindow(SW_SHOW);
}
RecalcLayout(); //框架窗口上活动的对象收到布局变动的通知
DockControlBar(&m_newToolBar); //使其再出现后停靠在客户区顶部,没此句悬浮的有问题
//方法二:出现在上一次消失的地方,只一句,简练!
ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);
}
void CMainFrame::OnUpdateViewNewtool(CCmdUI* pCmdUI) //菜单项前面的复选标记
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
}
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
IDS_TIMER,
IDS_PROGRESS,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
void CMainFrame::OnProgress() //进度栏——自己添加的消息处理函数
{
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect);
m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
rect,&m_wndStatusBar,123);
m_progress.SetPos(50);
}
void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect);
if(!m_progress.m_hWnd)
m_progress.Create(WS_CHILD | WS_VISIBLE ,//| PBS_SMOOTH,
rect,&m_wndStatusBar,123);
else
m_progress.MoveWindow(rect);
m_progress.SetPos(50);
// Do not call CFrameWnd::OnPaint() for painting messages
}
----------------------------------------------------------------------------------------------
在状态栏显示鼠标当前位置
void CStyleView::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())->SetMessageText(str);//第二种方法
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);//第三种方法
GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);//第四种方法
CView::OnMouseMove(nFlags, point);
}
-----------------------------------------------------------------------------------------------
启动画面
int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// Center the window.
CenterWindow();
// Set a timer to destroy the splash screen.
SetTimer(1, 3000, NULL);
return 0;
}
void CSplashWnd::OnTimer(UINT nIDEvent)
{
// Destroy the splash screen window.
HideSplashScreen();
}