改变窗口的外观和大小
From: http://blog.csdn.net/yoyobaibai/article/details/6044101
?
E.G.
BOOL?CMainFrame::PreCreateWindow(CREATESTRUCT&?cs)
改變窗口的大小?->?cs.cx?=?300;?cs.cy?=?200;
?
改變窗口的顯示位置坐標是 cs.x 和 cs.y
?
這里常用的一個函數是::GetSysMetrics(SM_CXSCREEN);
::GetSysMetrics(SM_CYSCREEN);
用來取得屏幕的大小。
?
要改變窗口標題欄的字符串:
???cs.lpszName?=?"Seven";?會發現標題欄不會改變窗口的標題欄的上的字符串。
改變單文檔應用程序的標題欄的字符串?參考MSDN??window?styles/Frame-window?styles?下面有一個Changing?the?styles?of?a?window?create?by?MFC./?The?SDI?Case
默認的情況是WS_OVERLAPPEDWINDOW?and?FWS_ADDTOTITLE?styles
FWS_ADDTOTITLE?is?add?the?document?title?to?the?window’s?caption.
去掉FWS_ADDTOTITLE?就可以更改窗口標題欄字符串。
?cs.style?&=?~FWS_ADDTOTITLE;
cs.lpszName?=?"Seven";
?
?
如果我們需要改變背景,?畫刷,?光標等等時候。
我們可以在:PreCreateWindow中創建窗口類,?WNDCLASS?wndClass;
把這個類里的值改變成自己想要的內容就可以了。
E.G.
wndClass.cbClsExtra?=?0;
wndClass.cbWndExtra?=?0;
wndClass.hbrBackground?=?(HBRUSH)GetStockObject(DKGRAY_BRUSH);
wndClass.hCursor?=?LoadCursor(NULL,?IDC_WAIT);
wndClass.hIcon?=?LoadIcon(NULL,?IDI_WARNING);
wndClass.hInstance?=?AfxGetInstanceHandle();
獲取應用程序的實例句柄可用AfxGetInstanceHandle函數,?這個函數是一個全局的函數,?前面有一個AFX表示是一個應用程序框架類函數,哪里都可用。
wndClass.lpfnWndProc?=?::DefWindowProc;
我們只是想要改變窗口的圖標,?光標,不想改變條用過程所以用defWindowProc函數來處理。
因為在CWnd中也有一個defWindowProc函數,比全局的函數少一個參數?如果不加::的話調用就要報錯。
wndClass.lpszMenuName?=?NULL;
創建菜單并不是在在設計窗口類的時候創建,?菜單的創建實在CStyleAPP::InitInstance函數中將菜單的標識傳進去。
wndClass.style?=?CS_HREDRAW?|?CS_VREDRAW;
這里的style并不是窗口的類型而是窗口類的類型。
RegisterClass(&wndClass);
注冊窗口類。
cs.lpszClass?=?"GL";
后來把我們剛剛設計好的類賦值個cs.lpszClass。
?
運行程序之后我們會發現只有圖標改變了,?cursor??和brush都沒有改變。這是因為,?我們是在frame中改變的,在frame上邊還覆蓋一個子窗口類。所以我要改變這些需要把在子窗口的View類中PreCreateWindow中把類名復制。
E.g
在CStyleView中?cs.lpszClass?=?"GL";
就可以把我們剛剛的想要的類型來改變view中的窗口類型,?因為“GL”窗口類已經在CMainFrame框架類中已經注冊了,?所以我們可以直接賦值就可以了。
?
在frame中只可以改變ICON?,為了改變圖標我們重寫窗口類我很不劃算,?在MFC中為我們提供了一個函數AfxRegisterWndClass?直接改變icon詳見MSDN
cs.lpszName?=?AfxRegisterWndClass(CS_HREDRAW?|?CS_VREDRAW,?0,?0,
LoadIcon(NULL,?IDI_WARNING));
這樣就直接改變了frame中Icon。?
我們也可以在CStyleView中調用這個函數?來改變窗口的?畫刷,?光標。
?
窗口創建之后改變外觀
用SetWinowLong函數?具體見MSDN
LONG?SetWindowLong( ??HWND?hWnd,??????//?handle?of?window ?
?int?nIndex,?????//?offset?of?value?to?set ??
?LONG?dwNewLong???//?new?value );
在CMainFrame的OnCreate中調用SetWindowLong
????SetWindowLong(m_hWnd,?GWL_STYLE,?WS_OVERLAPPEDWINDOW);
這樣就可以去掉了文檔標題是窗口標題了。
我們可以通過GetWindowLong函數得到當前窗口的類型。?詳見MSDN
???SetWindowLong(m_hWnd,?GWL_STYLE,?GetWindowLong(m_hWnd,?GWL_STYLE)?&?~WS_MAXIMIZEBOX);
這樣就可以灰掉窗口的最大化窗口了。
?
窗口創建之后改變窗口類
上面的是改變窗口的大小和最大化最小化等等的按鈕。
我們可以用SetClassLong來改變創建之后的窗口類的參數?例如?光標,?鼠標,?畫刷?等等。
在單文檔的應用程序中,?在CMainFrame類中只可以改變Icon?調用:
在OnCreate函數中
SetClassLong(m_hWnd,?GCL_HICON,?(LONG)LoadIcon(NULL,?IDI_QUESTION));
可以改變application的icon。
?
在VIEW類中改變brush?cursor?background。
在view類中調用
SetClassLong(m_hWnd,?GCL_HBRBACKGROUND,?(LONG)GetStockObject(DKGRAY_BRUSH));
改變了VIEW的背景為灰色。
?
實現一個每一秒中自動換Icon的功能。
Precondition?
在resources?中添加3個icon的資源。
?
1.?首先在CMainFrame類中添加一個數組用于存放資源的句柄。
???在類中添加?HICON?m_hIcon[3];?的一個數組。
2.?在CMainFrame?函數中加載Icon用LoadIcon這個函數。
?
???HICON?LoadIcon( ??HINSTANCE?hInstance,//?handle?to?application?instance ?? LPCTSTR?lpIconName???//?icon-name?string?or?icon?resource? ??????????????????????? ??//?identifier );
?
???如果用的系統的Icon話,?LoadIcon這函數的第一個參數必須為NULL。
???如果用的是自己定義的Iicon的話,?第一個參數是這個應用程序的一個實例句柄。?第二參數是一個是icon的icon-name?string?可以通過MAKEINTRESOURCE這個宏把資源的ID號轉換為資源的字符串名字。
?
LPTSTR?MAKEINTRESOURCE( ??WORD?wInteger?//?integer?to?convert );
?
???得到應用程序實例句柄我們可以通過幾種方法:
???第一種:?AfxGetInstanceHandle()?函數獲得當前應用程序的實例句柄。
???第二種:?因為CStyleApp這個類是從CWinApp這個類中繼承過來的所以繼承了m_hInstance?這個變量,?這個變量就是應用程序的實例句柄。因為MFC在全局中建立了一個CStyleApp中變量?theApp?如果在CMainFrame中得到這個變量就可以得到應用程序的實例句柄。?在CMainFrame中用到全局變量需要聲明這個變量?添加extern?CStyleApp?theApp;?這樣就在CMainFrame中用theApp了。
theApp.m_hInstance.
???第三種:?CWinApp*?AfxGetApp(?);?返回的是一個CWinApp的指針。這樣可以調用它的實例句柄。
?
3.?設置一個定時器在OnCreate中
我們這里調用的是CWND中的定時器。??
?UINT?SetTimer(?UINT?nIDEvent,?UINT?nElapse,?void?(CALLBACK?EXPORT*?lpfnTimer)(HWND,?UINT,?UINT,?DWORD)?);
第一個參數?定時器的ID?第二個參數是設置的時間?第三個參數是處理函數,?如果設置為NULL?發送WM_TIME消息讓消息處理系統調來處理。
???CWnd::SetTimer(1,?1000,?NULL);
?
4.?在CMainFrame類中添加一個WM_TIME的消息處理函數。
?
???static?int?index?=?1;
SetClassLong(m_hWnd,?GCL_HICON,?(LONG)m_hIcons[index]);
index?=?++index?%?3;
這樣就可以定義出一個會隨時間改變的ICON。
?
工具欄的編程???ToolBar
工具欄在resource中添加一個工具欄Item它的ID和menu中的菜單中的一個菜單的Id一樣,?那么這個工具欄的Item就代表著那個菜單。
E.g
在resourcesiView中在幫助的下面添加一個菜單,?叫TEST?它的ID叫ID_TEST?并且建立對應的command消息響應函數,彈出對話框。
在resourcesView的ToolBar中建立一個Item他的ID?也叫ID_TEST?這樣她們就關聯起來了啊。
Click兩個都是一樣的。
?
添加一個自己的工具欄
在MSDN中查看CToolBar?提供了兩種創建工具欄的方法
1.?首先在resourcesView中創建一個自己的ToolBar,?ToolBar上的Item自己設定。
2.?在CMainFrame中添加一個CToolBar的類成員,?構造一個CToolBar的變量。
3.?調用CToolBar的Create?或者CteateEX??參考MSDN
???可以參考CMainFrame中構造ToolBar的方法。
?
if?(!m_wndToolBar.CreateEx(this,?TBSTYLE_FLAT,?WS_CHILD?|?WS_VISIBLE?|?CBRS_TOP
|?CBRS_GRIPPER?|?CBRS_TOOLTIPS?|?CBRS_FLYBY?|?CBRS_SIZE_DYNAMIC)?||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed?to?create?toolbar/n");
return?-1;??????//?fail?to?create
}
4.??調用LoadToolBar這個函數加載資源。
5.?調用CToolBar的成員函數EnableDocking(CBRS_ALIGN_ANY);設置?這個對象是可以停靠的。?如果不設置這個那么工具欄將不可以懸浮。
6.?再調用CMainFrame::EnableDocking(CBRS_ALIGN_ANY);設置框架類可以被停靠。?
7.?最后在調用CMainFrame中的函數DockControlBar(&m_wndToolBar);停靠工具欄。
8.?我們還可以通過在菜單欄上設置一個Item并且設置command消息處理函數。
在處理函數中寫上
if(m_toolBar.IsWindowVisible())
{
????m_toolBar.ShowWindow(SW_HIDE);
}
else
{
m_toolBar.ShowWindow(SW_SHOW);
}
CWnd::IsWindowVisible?當有WS_VISIBLE的時候?返回TRUE.用IsWindowVisible來返回ToolBar是不是可見的。
?
當我調用這個處理的時候?點擊菜單里的Item來顯示或者隱藏工具欄。但是發現雖然ToolBar消失了,?但是這個工具條還在。這個時候工具欄的停靠位子有所變化,?這個時候需要調用
CFrameWnd::RecalcLayout?函數。?
void?RecalcLayout(?BOOL?bNotify?=?TRUE?);
在上面的程序后面接上
RecalcLayout();
當把工具欄拖出來,?處于浮空的ToolBar的時候發現,?然后點擊菜單來顯示或者隱藏ToolBar發現?當浮空的時候ToolBar的工具條不會隱藏。?這個時候我們還需要調用一個函數
DockControlBar(&m_toolBar);
?
顯示或隱藏工具欄的第二種方法
這個時候調用一個函數
ShowControlBar(&m_toolBar,?!m_toolBar.IsWindowVisible(),?FALSE);??具體調用參見MSDN。?ShowControlBar是CFrameWnd框架類的一個函數。
?
9.?我們還需要標記菜單的Item。當選中是標記,?當隱藏時取消標記。這個時候我們需要對這個Item的?UPDATE_COMMAND_UI進行響應。建立消息響應來標記活隱藏標記。?
調用CCmdUI的SetCheck();這個函數。來標記或者取消標記。
pCmdUI->SetCheck(m_toolBar.IsWindowVisible());?具體用法參見MSDN。
?
狀態欄的編寫
1.??首先construct?一個CStatusBar的對象。
2.??然后調用變量的Create函數把狀態欄窗口和一個CStatusBar的對象綁定。
?
CStatusBar::Create
BOOL?Create(?CWnd*?pParentWnd,?DWORD?dwStyle?=?WS_CHILD?|?WS_VISIBLE?|?CBRS_BOTTOM,?UINT?nID?=?AFX_IDW_STATUS_BAR?);
在MFC中是這樣調用的:
if?(!m_wndStatusBar.Create(this)?||?!m_wndStatusBar.SetIndicators(indicators,
?sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed?to?create?status?bar/n");
return?-1;??????//?fail?to?create
}
m_wndStausBar.Create(this),?其他的參數都用默認的參數。?后來條用m_wndStatusBar.Setindicators(indicators,?sizeof(indicators)/sizeof(UINT));
Indicators?是一個數組儲存字符串ID和每一個指示符。?后面一個參數是數組里面的數是多少個。
可以添加indicator?在數組中,?首先在String?Table?中添加字符串ID?,?然后把字符串ID添加在indicators的數組里面。這樣就可以在狀態欄中顯示了。?
有三種方法更新狀態欄上的字符。
1.?Call?CWnd::SetWindowText?to?update?the?text?in?pane?0?only.
2.?Call?CCmdUI::SetText?in?the?status?bar’s?ON_UPDATE_COMMAND_UI?handler.
3.?Call?SetPaneText?to?update?the?text?for?any?pane.
?
我們可以把系統當前時間顯示在狀態欄上。
這個時候需要用到?CTime
?CTime?t?=?CTime::GetCurrentTime();
CString?timeStr?=?t.Format("%H:%M:%S");
格式輸出到一個字符串中。?
然后調用?m_wndStatusBar.SetPaneText(1,?timeStr);
第一個參數是索引Index?of?the?pane?whose?text?is?to?be?set。
timeStr是要顯示的字符串了。
如果不知道要顯示的索引,?我們可用調用m_wndStatusBar的一個成員函數CommandToIndex(IDS_TIMER);?括號里面的參數是表示要顯示的字符串ID。
?
運行程序,?我們會發現時鐘的秒不能顯示。?這個是因為狀態欄空間不夠所以不能完全顯示內容。?
我們可以調用SetPaneInfo();
CStatusBar::SetPaneInfo
void?SetPaneInfo(?int?nIndex,?UINT?nID,?UINT?nStyle,?int?cxWidth?);
?
?函數改變狀態欄空間大小。
?
為了獲得字符串的顯示寬度,?我們需要調用GetTextExtent(Cstring?str);來返回字符創的空間大小,?CSize。
CClientDC?dc(this);
CSize?sz?=?dc.GetTextExtent(timeStr);
之后再調用SetPaneText();來顯示內容
?
這個時候發現時間是不動的。?需要動,?要把剛剛這段代碼放到SetTimer的響應函數中不停調用顯示時間。?
?
創建一個進度欄
進度欄的類是CProgressCtrl。?定義一個變量,?并且調用Create初始化一個進度欄。
?
CProgressCtrl::Create
BOOL?Create(?DWORD?dwStyle,?const?RECT&?rect,?CWnd*?pParentWnd,?UINT?nID?);
第一個參數是一個窗口類,?E.G??WS_CHILD?|?WS_VISIBLE?|?PBS_SMOOTH?
第二個參數是一個矩形區域。
?
CProgressCtrl?m_progressCtrl;
m_progressCtrl.SetPos(50); 設置到中間。?
?
如果我們想把這個矩形區域顯示在狀態欄里。?
?
首相我們在CMainFrame類中編寫這樣一段程序
CRect?rect;
m_wndStatusBar.GetItemRect(2,?&rect);
m_progressCtrl.Create(WS_CHILD|?WS_VISIBLE|?PBS_SMOOTH,?rect,
&m_wndStatusBar,?1);
注意這里的&m_wndStatusBar是進度條的父窗口。?在View類中創建進度條時,?父類窗口就是this,?代表這個對象的指針。
?
運行程序發現進度條并沒有出現,?我們在CRect?rect?;?這里設置斷點,?運行函數,?看斷點的值發現rect的值是一個無效的值,?這個時候我們猜想,?在OnCreat?結束錢狀態欄還沒有初始化好。?這樣我們可以在OnCreate之后調用一個函數來處理進度條。
我們可以自己定義一個消息,在OnCreate中把這個消息投遞到消息隊列中,來處理這個函數。
首先我先定義一個消息,?在window中消息都是用一個整數來表示的,在CMainFrame的頭文件中添加一個消息。?#define?UM_PROGRESS?WM_USER+1
因為window的很多消息已經占用了很多的整數,?我們胡亂定義很可可能和系統沖突,?WM_USER以下的是系統消息保留的。?以上的可以是用戶自己定義的。這樣我們就定義了一個UM_PROGRESS?的消息。添加完這個消息后,?要有相應的消息響應函數來處理這個消息。
protected:
//{{AFX_MSG(CMainFrame)
afx_msg?int?OnCreate(LPCREATESTRUCT?lpCreateStruct);
afx_msg?void?OnTimer(UINT?nIDEvent);
afx_msg?void?OnTest();
afx_msg?void?OnAppendToolbar();
afx_msg?void?OnUpdateAppendToolbar(CCmdUI*?pCmdUI);
afx_msg?void?OnPaint();
//}}AFX_MSG
先要在頭文件的這段代碼后面添加
??afx_msg?void?OnProgress();
DECLARE_MESSAGE_MAP()
?
參考MFC的程序;
然后在。CPP文件中
BEGIN_MESSAGE_MAP(CMainFrame,?CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_COMMAND(ID_TEST,?OnTest)
ON_COMMAND(ID_APPEND_TOOLBAR,?OnAppendToolbar)
ON_UPDATE_COMMAND_UI(ID_APPEND_TOOLBAR,?OnUpdateAppendToolbar)
ON_WM_PAINT()
//}}AFX_MSG_MAP
ON_MESSAGE(UM_PROGRESS,?OnProgress)
END_MESSAGE_MAP()
消息響應函數是通過?ON_MESSAGE()?把消息和消息處理函數關聯起來的。
?
最后在添加消息處理函數
Void?CMainFrame::OnProgress()
?
CRect?rect;
m_wndStatusBar.GetItemRect(2,?&rect);
m_progressCtrl.Create(WS_CHILD|?WS_VISIBLE|?PBS_SMOOTH,?rect,
&m_wndStatusBar,?1);
?
在這個函數中處理進度條。在OnCreate函數中用PostMessage();
不能用SendMessage();?因為?SendMessage是直接調用了處理函數,?這個時候狀態欄還沒有處理好。?
?
現在運行應用程序,?這個時候progress顯示在狀態欄上,?但是當我們拉伸或者縮放的時候進度欄?不再第二個狀態欄上的時候而是在別的地方?這是為什么呢??
每當窗口的尺寸變化的時候就會重繪發送ON_PAIN這個消息我們可以創建響應函數,?在這個函數中編寫上面的程序。
當改變尺寸的時候會當初dialog錯誤,?這是因為每當發送一個ON_PAIN消息函數的時候都會Create一個進度欄,?所照成了錯誤。應該判斷是否已經創建沒有創建的時候創建,?創建了移動窗口。
修改程序為一下:
CRect?rect;
m_wndStatusBar.GetItemRect(2,?&rect);
if(m_progressCtrl.m_hWnd?==?NULL)
m_progressCtrl.Create(WS_CHILD|?WS_VISIBLE|?PBS_SMOOTH,?rect,
&m_wndStatusBar,?1);
else
m_progressCtrl.MoveWindow(rect);
?
如果要進度欄里的進度增加的話,?我們可以調用CProgressCtrl類的一個StepIt函數來增長,?把發在OnTimer();?里面每次調用就會發送一個OnPaint函數來重繪進度欄。?
?
現在我們想在在狀態欄上顯示當前鼠標的位置,?在View類中添加ON_MOUSEMOVE處理函數。
CString?pointStr;
pointStr.Format("x=%d?y=%d",?point.x,?point.y);
((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText(0,?pointStr);
運行程序顯示出位置。因為狀態欄是框架類的,?所以首先要先獲得框架類的指針,?通過GetParent()?這個函數來獲得,?轉換為CMainFrame指針類型。
需要在View中加入頭文件“MainFrm.h”
或者調用?((CMainFrame*)GetParent())->SetMessageText(pointStr);
?
也可以這樣
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(pointStr);
GetMessageBar()是一個CMainFrame類的函數,?無需知道狀態欄的變量。
?
創建啟動畫面
在菜單上點擊工程->添加到工程->組件和空間-?>Visual?C++?components->solash?Screen?->insert.
總結
以上是生活随笔為你收集整理的改变窗口的外观和大小的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 智慧社区智能化管理系统搭建
- 下一篇: [vim]在vim中格式化xml