The framework calls PreCreateWindow just prior to creating the window. By modifying the CREATESTRUCT parameter to PreCreateWindow, your application can change the attributes used to create the window.
修改窗口的标题:通过修改CREATESTRUCT结构体中的lpszName
,但是注意,
FWS_ADDTOTITLE is an MFC-specific style that instructs the framework to add the document title to the window’s caption,所以必须将FWS_ADDTOTITLE从现有的style中去除FWS_ADDTOTITLE,即使cs.style & ~FWS_ADDTOTITLE
对于窗口的类型和大小,是在创建窗口的时候设定的,而窗口的图标,光标,背景是在设计窗口设计类的时候的设定的,是由MFC底层代码设计,但可以自己创建窗口类,然后让系统按照自己定义的窗口类执行。将以下代码放在CMainFrame类的PreCreateWindow函数中添加:
WNDCLASS wndcls;
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //设置窗口背景为黑色
wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
wndcls.hIcon=LoadIcon(NULL,IDI_WARNING);
wndcls.hInstance=AfxGetInstanceHandle();
//因为MFC本身也有DefWindowProc函数,但参数不一致,所以还是调用win32的函数
wndcls.lpfnWndProc=::DefWindowProc; //不想修改系统操作,所以调用系统默认的回调函数
wndcls.lpszClassName="style test";
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
cs.lpszClass="style test"; //按照自己的设计创建
运行以上代码后发现窗口图标改变了,但光标和背景没有改变,这是因为上述代码修改是框架类,光标和背景属于View类,所以还要在View类中PreCreateWindow修改。在实现上述代码后,在CView的PreCreateWindow函数中添加如下代码就可以实现修改光标和背景颜色的目的:
cs.lpszClass="style test"; //修改光标和背景
也可以通过以下方式实现:
cs.lpszClass=AfxRegisterWndClass(NULL,LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);
注:所以在CMainFrame类中只能修改的是Icon
随意如果采用这种代码实现,编写的代码较多,会比较麻烦,有一种替代的方法:
cs.lpszClass=AfxRegisterWndClass(NULL,0,0,LoadIcon(NULL,IDI_WARNING));
2. 在窗口创建之后修改窗口的外观:
窗口创建之后修改窗口外观一般在CMainFrame类的OnCreate函数中:
SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW); //文档的标题也去掉了
下面一种实现是从现有的窗口风格中去除某一种属性:
LONG currentStyle=GetWindowLong(m_hWnd,GWL_STYLE); //得到现有窗口的风格
SetWindowLong(m_hWnd,GWL_STYLE,currentStyle & ~WS_MAXIMIZEBOX ); 去除了最大化框
//在创建窗口后修改图标
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_WARNING));
//在创建窗口后修改光标和背景(注:以下代码在CView的OnCreate函数中实现:)
SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH)); //设置背景颜色
SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_CROSS)); //设置光标
3. 加载外部导入的图标:
LoadIcon如果加载的是系统图标,则第一个参数是null,但如果是自己的图标,则必须取得实例句柄。MAKEINTRESOURCE宏将资源号转换为字符指针类型
HICON m_hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
//theApp在别的cpp文件中定义,则必须在本cpp中进行extern CStyleApp theApp声明
HICON m_hIcon=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));
HICON m_hIcon=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
4. 工具栏:
给栏上的图标间加上分隔符:按住鼠标左键拖动分隔符后的图标一小段距离即可。
删除栏上的图标:将指定图标拖出工具栏即可。
创建工具栏:在MSDN说明中提供两种方法
Visual C++ provides you with two methods to create a toolbar. To create a toolbar resource using the Resource Editor, follow these steps:
- Create a toolbar resource.
- Construct the CToolBar object.
- Call the Create (or CreateEx) function to create the Windows toolbar and attach it to the CToolBar object.
- Call LoadToolBar to load the toolbar resource.
//创建自己的工具栏,具体的创建过程参看MSDN中的CToolBar部分,以下代码模仿向导自动创建的toolbar(代码也是在CMainFrame类的OnCreate函数中)
首先创建ToolBar的资源m_newToolBar
//以下代码放在CMainFrame类的OnCreate函数中:
if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_LEFT| 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); //使新的toolbar可停靠
EnableDocking(CBRS_ALIGN_ANY); //使MainFrame可停靠,因为此段代码已经有了,所以省去
DockControlBar(&m_newToolBar); //是新的toolbar停靠在MainFrame上
Otherwise, follow these steps:
- Construct the CToolBar object.
- Call the Create (or CreateEx) function to create the Windows toolbar and attach it to the CToolBar object.
- Call LoadBitmap to load the bitmap that contains the toolbar button images.
- Call SetButtons to set the button style and associate each button with an image in the bitmap.
显示和隐藏工具栏:
//第一种方法:
if(m_newToolBar.IsWindowVisible()) //工具栏也是一个窗口
{
m_newToolBar.ShowWindow(SW_HIDE);
}
else
{
m_newToolBar.ShowWindow(SW_SHOW);
}
RecalcLayout(TRUE); //整个工具栏所在的控制栏显示或消失
DockControlBar(&m_newToolBar); //将新的toolbar停靠在MainFrame上
//第二种方法,这种方法是最好的,一行代码实现了上面的功能
ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);
5. 状态栏:
向导创建状态栏是在CMainFrame类的OnCreate函数中实现的,代码如下:
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, //indicators
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar/n");
return -1; // fail to create
}
其中indicators是一个指示器数组,它在CMainFrame的源文件中定义:
static UINT indicators[] =
{
//以下这些资源在string table中定义
ID_SEPARATOR, // status line indicator
IDS_TIMER, //自定义
IDS_PROGRESS, //自定义
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
该指示器表示了在状态栏中显示的许多小面板
以下代码实现在状态栏上显示当前时间(该函数也是在OnCreate函数中实现):
CTime currentTime=CTime::GetCurrentTime();
CString strTime=currentTime.Format("%Y-%m-%d %H:%M:%S");
CClientDC dc(this);
CSize size=dc.GetTextExtent(strTime);
int idx=m_wndStatusBar.CommandToIndex(IDS_TIMER); //在不知道索引的前提下
//SetPaneInfo函数是设置面板的style,size等
m_wndStatusBar.SetPaneInfo(idx,IDS_TIMER,SBPS_NORMAL,size.cx); //使宽度合适
//SetPaneText函数是在指定的面板上显示内容
m_wndStatusBar.SetPaneText(idx,strTime);
6. 进度栏:
创建类的成员函数:CProgressCtrl m_progress;
创建水平进度条
m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH,CRect(100,100,200,120),this,IDS_PROGRESS);
垂直进度条
m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_VERTICAL,CRect(100,100,120,220),this,IDS_PROGRESS);
m_progress.SetRange(0,100); //设置范围
m_progress.SetStep(10); //设置步进长度
将创建的进度栏放在状态栏的指定编号的面板上(以下代码放在OnPaint函数中):
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect); //得到状态栏上指定面板的矩形大小
if(!m_progress.m_hWnd)
m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH,rect,&m_wndStatusBar,IDS_PROGRESS);
else
m_progress.MoveWindow(rect); //如果已经创建,则只需要将进度条移动到指定矩形框内
m_progress.SetRange(0,100);
m_progress.SetStep(10);
注:上述代码没有放在CMainFrame类的OnCreate函数中是因为OnCreate函数创建好的时候窗口上的控件还没有创建好,所以想得到状态栏上指定面板的矩形大小时候,会取不到值(可以想象成状态栏也是窗口上的一个控件)。
将鼠标在视图上移动时对应的x,y坐标时时显示在状态栏上
在CView类的OnMouseMove函数中添加:
CString location;
location.Format("x=%d,y=%d",point.x,point.y);
方法1:
((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText(0,location,TRUE);
方法2:
SetMessageText在MSDN中的解释是这样的:Call this function to place a string in the status-bar pane that has an ID of 0. This is typically the leftmost, and longest, pane of the status bar.
((CMainFrame*)GetParent())->SetMessageText(location);
方法3:
GetMessageBar在MSDN中解释:Call this member function to get a pointer to the status bar.
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(location);
7. 为程序添加启动画面:
Project->Add To Project->Components and Controls->Visual C++ component->Splash screen
修改启动画面的等待时间,其中在函数OnCreate函数有设置:SetTimer(1, 1000, NULL);
利用上述的向导自动添加了一个新类,CSplashWnd,并且自动在CMainFrame类中的OnCreate函数中添加了CSplashWnd::ShowSplashScreen(this),也就是将启动画面添加到了运行程序框架类中了。