我們在做程序設計時界面與功能,那個更加吸引用戶的興趣呢?這是一個很難回答的問題。擁有美麗的外觀,軟件就成功了一半。界面由控件、工具欄、菜單、窗體等元素組成,對他們進行美化就能得到一個美麗的界面。
目前界面編程技術包括MFC、win32 SDK 、CJLibrary、WTL以及一些界面開發包。文本介紹MFC界面編程技術。
一、控件自繪
控件的生成包括靜態控件和動態控件的生成。動態控件是在應用程序運行過程中臨時產生的。所以在進行動態控件的自繪時,方法比自繪靜態控件複雜些。應該考慮控件的大小、寬高等。
自繪控件類型
靜態控件
動態控件
繪製步驟
1、控件具有自繪屬性。
2、響應OnDrawItem函數。
1、控件具有自繪屬性。
2、響應OnMeasureItem函數。
3、響應OnDrawItem函數。
注:控件的自畫需要響應四個消息:WM_MEASUREITEM, WM_DRAWITEM, WM_COMPAREITEM, 和WM_DELETEITEM.
combo box ,list box 銷燬時響應OnDeleteItem
combo ,list box 排序時響應OnCompareItem
button, combo box, list box, or menu 創建時響應OnMeasureItem
button, combo box, list box, or menu 改變時響應OnDrawItem
OnDrawItem函數說明,函數定義爲:
afx_msg void OnDrawItem(int nIDCtl,LPDRAWITEMSTRUCT lpDrawItemStruct);
參數說明:
nIDCtl:發送WM_DRAWITEM消息控件的ID值,如果該值爲零,表明該消息由菜單控件發出的。
LpDrawItemStruct:指向一個DRAWITEMSTRUCT結構的指針, DRAWITEMSTRUCT 爲需要自繪的控件或者菜單項提供了必要的信息。在需要繪製的控件或者菜單項對應的WM_DRAWITEM消息函數中得到一個指向該結構的指針。 DRAWITEMSTRUCT結構的定義如下:
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemAction;
UINT itemState;
HWND hwndItem;
HDC hDC;
RECT rcItem;
ULONG_PTR itemData;
} DRAWITEMSTRUCT;
結構成員:
CtlType :指定了控件的類型,其取值如下表所示。
取值 描述
ODT_BUTTON 按鈕控件
ODT_COMBOBOX 組合框控件
ODT_LISTBOX 列表框控件
ODT_LISTVIEW 列表視圖控件
ODT_MENU 菜單項
ODT_STATIC 靜態文本控件
ODT_TAB Tab控件
CtlID: 指定了自繪控件的ID值,而對於菜單項則不需要使用該成員
itemID :表示菜單項ID,也可以表示列表框或者組合框中某項的索引值。對於一個空的列表框或組合框,該成員的值爲–1。這時應用程序只繪製焦點矩形(該矩形的座標由rcItem 成員給出)雖然此時控件中沒有需要顯示的項,但是繪製焦點矩形還是很有必要的,因爲這樣做能夠提示用戶該控件是否具有輸入焦點。當然也可以設置itemAction 成員爲合適值,使得無需繪製焦點。
itemAction :指定繪製行爲,其取值可以爲下表中所示值的一個或者多個的聯合。
取值 描述
ODA_DRAWENTIRE 當整個控件都需要被繪製時,設置該值
ODA_FOCUS 如果控件需要在獲得或失去焦點時被繪製,則設置該值。此時應該檢查itemState成員,以確定控件是否具有輸入焦點。
ODA_SELECT 如果控件需要在選中狀態改變時被繪製,則設置該值。此時應該檢查itemState 成員,以確定控件是否處於選中狀態。
itemState :指定了當前繪製操作完成後,所繪項的可見狀態。例如,如果菜單項應該被灰色顯示,則可以指定ODS_GRAYED狀態標誌。其取值可以爲下表中所示值的一個或者多個的聯合。
取值 描述
ODS_CHECKED 如果菜單項將被選中,則可設置該值。該值只對菜單項有用。
ODS_COMBOBOXEDIT 在自繪組合框控件中只繪製選擇區域。
ODS_DEFAULT 默認值。
ODS_DISABLED 如果控件將被禁止,則設置該值。
ODS_FOCUS 如果控件需要輸入焦點,則設置該值。
ODS_GRAYED 如果控件需要被灰色顯示,則設置該值。該值只在繪製菜單時使用。
ODS_HOTLIGHT Windows 98/Me, Windows 2000/XP: 如果鼠標指針位於控件之上,則設置該值,這時控件會顯示高亮顏色。
ODS_INACTIVE Windows 98/Me, Windows 2000/XP: 表示沒有激活的菜單項。
ODS_NOACCEL Windows 2000/XP: 控件是否有快速鍵盤。
ODS_NOFOCUSRECT Windows 2000/XP: 不繪製捕獲焦點的效果。
ODS_SELECTED 選中的菜單項。
hwndItem :指定了組合框、列表框和按鈕等自繪控件的窗口句柄;如果自繪的對象時菜單項,則表示包含該菜單項的菜單句柄。
hDC :指定了繪製操作所使用的設備環境。
rcItem :指定了將被繪製的矩形區域。這個矩形區域就是上面hDC的作用範圍。系統會自動裁剪組合框、列表框或按鈕等控件的自繪製區域以外的部分。也就是說rcItem中的座標點(0,0)指的就是控件的左上角。但是系統不裁剪菜單項,所以在繪製菜單項的時候,必須先通過一定的換算得到該菜單項的位置,以保證繪製操作在我們希望的區域中進行。
itemData :
對於菜單項,該成員的取值可以是由CMenu::AppendMenu、CMenu::InsertMenu或者CMenu::ModifyMenu等函數傳遞給菜單的值。
對於列表框或這組合框,該成員的值可以爲由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等傳遞給控件的值。
如果ctlType 的取值是ODT_BUTTON或者ODT_STATIC, itemData的取值爲0
OnMeasureItem函數說明,函數定位:
afx_msg void OnMeasureItem(int nIDCtl,LPMEASUREITEMSTRUCT lpMeasureItemStruct);
參數說明:
nIDCtl:發送WM_MEASUREITEM消息控件的ID值,如果該值爲零,表明該消息是由菜單控件發出的。
LpMeasureItemStruct:指向一個MEASUREITEMSTRUCT結構的指針,它的數據結構定義如下:
typedef struct tagMEASUREITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemWidth;
UINT itemHeight;
DWORD itemData;
} MEASUREITEMSTRUCT;
CtlType:指定控件的類型.這個成員可以是下列的一個值:
取值 描述
ODT_BUTTON 自繪按鈕
ODT_COMBOBOX 自繪組合框
ODT_LISTBOX 自繪列表框
ODT_LISTVIEW 自繪列表視圖控件
ODT_MENU 自繪菜單
CtlID:指定組合框(combo box), 列表框(list box), 或 控鈕(button)的標識符.這個成員不能在菜單中使用
ItemID:指定菜單項的標識符或組合框(combo box), 列表框(list box)的位置索引。列表框(list box)風格已經有LBS_OWNERDRAWVARIABLE時這個值才被指定。組合框(combo box)風格已經有CBS_OWNERDRAWVARIABLE風格時這個值才被指定。
ItemWidth:指定寬,單位象素,一個菜單項目.在從消息返回之前,自繪菜單項的所有者必需填充這個成員。
ItemHeight:指定高,單位象素,列表框(list box)一個個別的項或一個菜單.在從消息返回之前自繪組合框,列表框或菜單項必需填寫這個參數。
ItemData:指定與應用程序定義的菜單項相關聯的32位值.做爲控件,這個參數指定值是最後指定給列表框(list box)或組合框(combo box)的LB_SETITEMDATA或CB_SETITEMDATA消息中的值.如果列表框(list box)或組合框(combo box)已經使用LB_HASSTRINGS或CB_HASSTRINGS風格這個最初值是零.否則,這個值最初的值是傳給列表框(list box)或組合框(combo box)下列消息中lparam參數的一個值:
CB_ADDSTRING
CB_INSERTSTRING
LB_ADDSTRING
LB_INSERTSTRING
WM_MEASUREITEM與WM_DRAWITEM區別:在WM_MEASUREITEM消息影射函數中設置當前要畫的Item的大小尺寸;創建控件。在WM_DRAWITEM消息影射函數中根據Item的大小尺寸來畫該Item(圖標/位圖/字符串等)。
二、常用控件使用方法
1、按鈕類
CButtonST目前見過的最強大,功能最全的CButton派生類。具體使用方法參考:http://www.vckbase.com/document/viewdoc/?id=517
2、菜單
自繪菜單的實現:
http://www.vckbase.com/document/viewdoc/?id=1200
3、工具條使用方法
http://www.vckbase.com/document/viewdoc/?id=629
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=305
4、CToolTipCtrl使用方法
ToolTip是Win32中一個通用控件,用於提示信息的顯示,MFC中爲其生成了一個類CToolTipCtrl,總的說來其使用方法是較簡單的,下面講一下它的一般用法和高級用法。
一般用法步驟:
添加CToolTipCtrl成員變量 m_tt。
在父窗口中調用EnableToolTips(TRUE);
在窗口的OnCreate(或者其他適當的位置)中向ToolTip中添加需要顯示Tip的子窗口,並同時指定相應的顯示字串CToolTipCtrl::AddTool(pWnd,"string to display")。
重載父窗口的 BOOL PreTranslateMessage(MSG* pMsg) ,在函數中調用 m_tt.RelayEvent(pMsg)。
下面假設在窗口CWndYour中使用CToolTipCtrl
在類定義中添加變量說明:
class CWndYour:xxx
{
CToolTipCtrl m_tt;
}
在OnCreate中添加需要顯示Tip的子窗口
CWndYour::OnCreate(....)
{
EnableToolTips(TRUE);
m_tt.Create(this);
m_tt.Activate(TRUE);
CWnd* pW=GetDlgItem(IDC_CHECK1);//得到窗口指針
m_tooltip.AddTool(pW,"Check1");//添加
........
}
在BOOL PreTranslateMessage(MSG* pMsg)中添加代碼
BOOL CWndYour::PreTranslateMessage(MSG* pMsg)
{
{
m_tt.RelayEvent(pMsg);
}
return CParentClass::PreTranslateMessage(pMsg);
}
這樣當鼠標移動到相應的子窗口上時會顯示出相應的ToolTip。
動態改變ToolTip的顯示內容的方法及步驟:
上面所講的1、2、4步驟。
在增加ToolTip時不指定顯示的字串,而是使用LPSTR_TEXTCALLBACK。
在窗口中增加消息映射 ON_NOTIFY_EX( TTN_NEEDTEXT, 0, SetTipText )。
在窗口中增加一個函數用於動態提供顯示內容,其原型爲 BOOL SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult ),下面的代碼可以根據傳入的參數判定應該顯示的內容。
BOOL CWndYour::SetTipText( UINT id, NMHDR * pTTTStruct, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pTTTStruct;
UINT nID =pTTTStruct->idFrom; //得到相應窗口ID,有可能是HWND
if (pTTT->uFlags & TTF_IDISHWND) //表明nID是否爲HWND
{
nID = ::GetDlgCtrlID((HWND)nID);//從HWND得到ID值,當然你也可以通過HWND值來判斷
switch(nID)
case(IDC_YOUR_CONTROL1)
strcpy(pTTT->lpszText,your_string1);//設置
return TRUE;
break;
case(IDC_YOUR_CONTROL2)
//設置相應的顯示字串
return TRUE;
break;
}
return(FALSE);
}
5、狀態欄
狀態欄是基於 Windows 通用控件 msctls_statusbar32,這個通用控件並不提供任何方法來添加子窗口。在 Windows 中,在某些控件或是窗口中添加子窗口並不是將它們作爲這些控件的子窗口,而是作爲這些控件的兄弟窗口。在現在這種情況下,你有兩個選擇:一是建立一個“超級狀態欄“,它包含一個普通狀態欄 以及其它控件子窗口(就像 Windows 結合列表框和編輯框而合成的組合框一樣);第二、你也可以直接將按鈕或是其它控件直接加在主框架上,就像是狀態欄,工具欄 或視圖的兄弟窗口一樣。
至於決定使用那種方法取決於你的設計有多複雜以及你的規劃。如果你想加很多的控件, 和/或在其它的窗口或應用程序中重用組合的狀態欄/按鈕/編輯控制的話,那麼最好建立一個複合控件。如果僅僅是想 在某個窗口中添加單個按鈕,那麼最好是將它添加到主框架。無論你使用哪種方法,你都需要寫一點代碼來定位你的控件,使 之與其它相鄰的控件在合適的位置上。
1)首先了解單文檔應用程序中自帶的狀態欄結構:
在Mainfrm.cpp中有兩處:
static UINT indicators[] =
{
ID_SEPARATOR, // 狀態行指示器
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
該數組指明每個指示器的ID,可以理解爲狀態欄中的一個格子,格子的大小由字符串的長度決定。其中每個ID在string table 中都有定義,定義中的的“標題”就是將要顯示的內容,如“AFX_IDS_IDLEMESSAGE 57345 就緒”等。
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("未能創建狀態欄\n");
return -1; // 未能創建
}
以上語句是在OnCreate()函數中創建狀態欄,其中用SetIndicators函數將indicators數組中的內容設爲每個指示器的ID。
2)簡單操作--添加時間
添加SetTimer()和OnTimer函數,在Ontimer中添加
CTime time = CTime::GetCurrentTime();
CString str;
str=time.Format("%H:%M:%S");
m_wndStatusBar.SetPaneText(0,str); //顯示時鐘
即可顯示時鐘。如果添加自定義的ID則要在string table中添加新的圖IDS_MYTIME 00:00:00 並將其添加到indicators數組中,將m_wndStatusBar.SetPaneText(0,str); //顯示時鐘 改爲:
m_wndStatusBar.SetPaneText(m_wndStatusBar.CommandToIndex(IDS_MYTIME),str);
6、CEdit使用方法
http://www.vckbase.com/document/viewdoc/?id=1025
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=311
7、CRichEditCtrl使用方法
http://blog.csdn.net/byxdaz/archive/2010/03/18/5393658.aspx
http://www.vckbase.com/document/viewdoc/?id=328
8、ComboBox
Auto-completion ComboBox:
http://www.codeguru.com/cpp/controls/combobox/article.php/c1807/
9、屬性頁CPropertySheet使用方法
http://www.vckbase.com/document/viewdoc/?id=427
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=317
10、靜態控件使用方法
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=319
11、樹型控件使用方法
樹形控件在MFC中以兩種形式來封裝,即樹形控件(CtreeCtrl)和樹形視圖(CtreeView),來滿足用戶的不同需求,對於一般要求的用戶如在對話框中應用,使用樹形控件比較方便,而對於具有較高要求的用戶,在使用樹形視圖時還具有視圖窗口的各種方便特性,可以更好的滿足文檔/視圖結構的要求。在窗口中使用樹形視圖時,樹形視圖會佔滿兩個窗口的客戶區域並自動隨窗口的框架結構的調整而調整,並能處理菜單、工具條中的命令消息。在樹形視圖中利用CtreeCtrl & treeCtrl = GetTreeCtrl()得到樹形控件。
樹形控件一些典型使用過程如下:
1)、樹形控件的創建,如果樹形控件是添加在對話框資源中的,樹形控件的創建是自動的。如果是動態生成的樹形控件,則需要使用Create函數進行創建。
樹形控件的外觀取決於在創建時對其風格的設置。通常,樹形控件的風格有以下幾種:
TVS_EDITLABELS 允許用戶進行節點文本的編輯
TVS_HASBUTTONS 節點左側添加一個按鈕
TVS_HASLINES 父節點與子節點之間出現連線
TVS_LINESATROOT 子節點與根節點之間出現連線
TVS_NOTOOLTIPS 節點無動態提示
TVS_SINGLEEXPAND 節點的選中(未選中)與展開(合攏)同步
2)、樹形控件節點的添加。調用InsertItem函數能夠將節點插入到樹形控件中。InsertItem函數成功調用後,返回的節點將有可能成爲下次使用InsertItem的一個參數(如父節點)。節點插入工作往往是在對話框OnInitDialog函數中進行,或者在文檔/視圖中OnInitUpdate函數使用。
3)、節點數據的使用。樹形控件節點的數據可以是文本的,也可以是圖像。節點中使用圖像是和樹形控件的圖像列表相對應。在樹形控件使用圖像列表使用SetImageList函數來完成。
4)、進行樹形控件的消息響應,當用戶在樹形控件中對節點的選擇發生變化時,樹形控件會發出相應的通知消息。如果需要對這些消息進行響應,則需要在程序中添加ON_NOTIFY_REFLECT宏。
樹形控件產生的通知消息
樹形控件
通知消息
TVN_BEGINDRAG
開始拖拽操作
TVN_BEGINLABELEDIT
開始編輯節點文本
TVN_BEGINRDRAG
開始拖拽操作(使用右鍵)
TVN_DELETEITEM
刪除指定節點
TVN_ENDLABELEDIT
結束編輯節點
TVN_GETDISPINFO
請求顯示節點所需的消息
TVN_GETINFOTIP
需要得到節點數據提示
TVN_ITEMEXPANDED
節點被展開或合攏
TVN_ITEMEXPANDING
節點即將被展開或合攏
TVN_KEYDOWN
按鍵操作
TVN_SELCHANGED
用戶選擇的節點發生變化
TVN_SELCHANGING
用戶選擇的節點即將發生變化
TVN_SETDISPINFO
更新節點數據
TVN_SINGLEEXPAND
節點被展開或合攏(使用鼠標單擊)
注:樹控制的數據結構 在使用樹控制時需要了解兩個個非常重要的數據結構TV_ITEM和TV_INSERTSTRUCT,前一個數據結構是用來表示樹控制的樹項信息,後一個數據結構是用來定義將樹項增加到數據控制中所需要的數據內容。另外,還需要NM_TREEVIEW、TV_DISPINFO和TV_HITTESTINFO三個數據結構,這幾個數據結構的定義方法如下:
①基本數據項結構
typedef struct _TV_ITEM{
UINT mask; //結構成員有效性屏蔽位
HTREEITEM hItem; //數據項控制句柄
UINT state; //數據項狀態
UINT stateMask; //狀態有效性屏蔽位
LPSTR pszText; //數據項名稱字符串
int cchTextMax; //數據項名稱的最大長度
int iImage; //數據項圖標索引號
int iSelectedImage;//選中數據項圖標索引號
int cChildren; //子項標識
LPARAM lParam; //程序定義的32位數據
} TV_ITEM, FAR *LPTV_ITEM;
②插入樹項結構
typedef struct _TV_INSER TSTRUCT {
HTREEITEM hParent; //父項控制句柄
HTREEITEM hInsertAfter; //插入樹項的位置
TV_ITEM item; //數據項的結構
} TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;
其中插入的位置如果是TVI_FIRST 或TVI_LAST ,則分別插入到樹控制的最前面或最後面,如果是TVI_SORT ,則插入的樹項自動插入到合適的位置。
③樹控制通知消息結構
typedef struct _NM_TREEVIEW {
NMHDR hdr; //通知消息句柄
UINT action; //通知消息標誌
TV_ITEM itemOld; //原來的數據結構
TV_ITEM itemNew; //新的數據結構
POINT ptDrag; //拖動指針
} NM_TREEVIEW;
④取得或設置數據結構
typedef struct _TV_DISPINFO {
tvdi NMHDR hdr; //通知消息控制句柄
TV_ITEM item; //數據項結構
} TV_DISPINFO;
⑤指針測試數據結構
typedef struct _TVHITTESTINFO {
tvhtst POINT pt; //客戶區域屏幕座標指針
UINT flags; //存放測試結果的變量
HTREEITEM hItem; //測試的數據項結構
} TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;
其中flags測試結果可以是如下值: TVHT_ABOVE 在客戶區域上面 TVHT_BELOW 在客戶區域下面 TVHT_NOWHERE 在客戶區域中並在最後一項下面 TVHT_ONITEM 在與樹項關聯的位圖或標籤內 TVHT_ONITEMBUTTON 在與樹項關聯的按鈕上 TVHT_ONITEMICON 在與樹項關聯的位圖上 TVHT_ONITEMINDENT 在與樹項關聯的聯線上 TVHT_ONITEMLABEL 在與樹項關聯的標籤上 TVHT_ONITEMRIGHT 在樹項的右側區域中 TVHT_ONITEMSTATEICON
在用戶定義的狀態圖標上 TVHT_TOLEFT 在客戶區域的左側 TVHT_TORIGHT 在客戶區域的右側。
http://cqyangyong.spaces.live.com/blog/cns!66BB503A2FB4C3F5!346.entry
http://www.vckbase.com/document/viewdoc/?id=1848
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=321
12、列表控件使用方法
列表控制和視(List Control&View)主要用來以各種方式顯示一組數據記錄供用戶進行各種操作,Windows98/95中資源管理器中的“查看”標籤下的“大圖標|小圖標|列表|詳細資源”就是一個非常好的典型應用。列表中的記錄可以包括多個數據項,也可以包括表示數據內容的大小圖標,用來表示數據記錄的各種屬性。
列表控制提供了對Windows列表功能操作的基本方法,而使用列表視的視函數可以對列表視進行各種操作,通過調用視成員GetListCtrl獲取嵌在列表視內列表控制的引用(GetListCtrl& ctrlList = GetListCtrl()),就可以和列表控制一樣進行各種操作。操作一個列表控制和視的基本方法爲:創建列表控制;創建列表控制所需要的圖像列表;向列表控制添加表列和表項;對列表進行各種控制,主要包括查找、排序、刪除、顯示方式、排列方式以及各種消息處理功能等;最後撤消列表控制。
對於一個列表控制,其最典型最常用的顯示控制方式爲:大圖標方式(LVS_ICON)、小圖標方式(LVS_SMALLICON)、列表顯示方式(LVS_LIST)和詳細資料(即報告LVS_REPORT)顯示方式。這可以通過設置其顯示方式屬性來實現。要控制列表所在窗口的風格,可通過功能函數GetWindowLong和SetWindowLong來實現,要控制列表圖標的對齊方式,可通過設置列表窗口的風格LVS_ALIGNTOP或LVS_ALIGNLEFT來實現,
1)、列表控制的建立方法
CListCtrl&listCtrl 定義列表對象的結構
Create 建立列表控制並綁定對象
列表控制CListCtrl::Create的調用格式如下:
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
其中參數dwStyle用來確定列表控制的風格;rect用來確定列表控制的大小和位置;pParentWnd用來確定列表控制的父窗口,通常是一個對話框;nID用來確定列表控制的標識。其中列表控制的風格可以是下列值的組合:
LVS_ALIGNLEFT 用來確定表項的大小圖標以左對齊方式顯示;
LVS_ALIGNTOP 用來確定表項的大小圖標以頂對齊方式顯示;
LVS_AUTOARRANGE 用來確定表項的大小圖標以自動排列方式顯示;
LVS_EDITLABELS 設置表項文本可以編輯,父窗口必須設有LVN_ENDLABELEDIT風格;
LVS_ICON 用來確定大圖標的顯示方式;
LVS_LIST 用來確定列表方式顯示;
LVS_NOCOLUMNHEADER 用來確定在詳細資料方式時不顯示列表頭;
LVS_NOLABELWRAP 用來確定以單行方式顯示圖標的文本項;
LVS_NOSCROLL 用來屏蔽滾動條;
LVS_NOSORTHEADER 用來確定列表頭不能用作按鈕功能;
LVS_OWNERDRAWFIXED 在詳細列表方式時允許自繪窗口;
LVS_REPORT 用來確定以詳細資料即報告方式顯示;
LVS_SHAREIMAGELISTS用來確定共享圖像列表方式;
LVS_SHOWSELALWAYS 用來確定一直顯示被選中表項方式;
LVS_SINGLESEL 用來確定在某一時刻只能有一項被選中;
LVS_SMALLICON 用來確定小圖標顯示方式;
LVS_SORTASCENDING 用來確定表項排序時是基於表項文本的升序方式;
LVS_SORTDESCENDING 用來確定表項排序時是基於表項文本的降序方式;
2)、列表控制的屬性類
列表控制的屬性類包括取得列表控制的背景色GetBkColor、設置列表控制的背景色SetBkColor、取得列表控制的圖像列表GetImageList、設置列表控制的圖像列表SetImageList、取得列表項數目GetItemCount、取得列表控制的屬性GetItem、取得與表項相關的數據GetItemData、設置表項的屬性SetItem、設置與表項相關的數值SetItemData、取得相關聯的下一個表項GetNextItem、設置列表控制的文本顏色SetTextColor、取得列表控制的文本背景顏色GetTextBkColor、設置表項的最大數目SetItemCount和取得被選中表項的數目GetSelectedCount等。
3)、列表控制的操作方法
列表控制的操作方法包括插入一個新的表項InsertItem、刪除一個表項DeleteItem、排序表項SortItems、測試列表的位置HitTest、重繪表項RedrawItems、插入一個表列InsertColumn、刪除一個表列DeleteColumn、編輯一個表項文本EditLabel和重繪一個表項DrawItem等。
注:列表控制的數據結構
列表控制中包含兩個非常重要的數據結構LV_ITEM和LV_COLUMN。LV_ITEM用於定義列表控制的一個表項,LV_COLUMN用於定義列表控制的一個表列,其定義格式分別爲:
typedef struct _LV_ITEM {
UINT mask; //結構成員屏蔽位
int iItem; //表項索引號
int iSubItem; //子表項索引號
UINT state; //表項狀態
UINT stateMask; //狀態有效性屏蔽位
LPTSTR pszText; //表項名文本
int cchTextMax; //表項名最大長度
int iImage; // 表項圖標的索引號
LPARAM lParam; // 與表項相關的32位數
} LV_ITEM;
typedef struct _LV_COLUMN {
UINT mask; //結構成員有效性屏蔽位
int fmt; //表列對齊方式
int cx; //表列的象素寬度
LPTSTR pszText; //表列的表頭名
int cchTextMax; //表列名的文本長度
int iSubItem; //與表列關聯的子表項索引號
} LV_COLUMN;
其中fmt可以取如下值:
LVCFMT_CENTER 表列居中對齊
LVCFMT_LEFT 表列左對齊
http://blog.csdn.net/ctbinzi/archive/2009/09/03/4510858.aspx
http://blog.csdn.net/sghgcn/archive/2009/03/05/3958219.aspx
http://www.vckbase.com/document/viewdoc/?id=1604
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=323
13、進度條使用方法
http://www.yesky.com/33/1710533.shtml
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=325
14、CScrollBar
http://xinny.bokee.com/1131543.html
http://download.csdn.net/source/1802602
15、數據表格控件DBGrid,FlexGrid使用方法
http://www.vckbase.com/document/listdoc.asp?mclsid=3&sclsid=327
16、cgridctrl詳細說明
http://blog.csdn.net/byxdaz/archive/2008/06/19/2563142.aspx
17、CAnimateCtrl 動畫控件
http://blog.csdn.net/huahuamoon/archive/2008/02/14/2095060.aspx
18、對話框
http://www.vckbase.com/document/listdoc.asp?mclsid=5&sclsid=501
19、單文檔界面
http://www.vckbase.com/document/listdoc.asp?mclsid=5&sclsid=503
20、多文檔界面
http://www.vckbase.com/document/listdoc.asp?mclsid=5&sclsid=505
21、視圖分割與停靠
http://www.vckbase.com/document/listdoc.asp?mclsid=5&sclsid=507
22、高級用戶界面
http://www.vckbase.com/document/listdoc.asp?mclsid=5&sclsid=510
23、VC模仿超炫QQ界面的實現
http://www.vckbase.com/document/viewdoc/?id=1841
24、CdialogBar
http://www.cppblog.com/tx7do/archive/2008/06/03/51926.html
25、CImageList控件
圖像列表控制(CImageList)是相同大小圖像的一個集合,每個集合中均以0爲圖像的索引序號基數,圖像列表通常由大圖標或位圖構成,其中包含透明位圖模式。可以利用Windows32位應用程序接口函數API來繪製、建立和刪除圖像,並能實現增加、刪除、替換和拖動圖像等操作。圖像列表控制提供了控制圖像列表的基本方法,這些方法在WINDOWS95及以後版本才能實現。
(一)圖像控制的對象結構
1)、圖像控制的數據成員
m_hImageList 連接圖像對象的控制句柄
2)、圖像控制的建立方法
CimageList&imageList建立圖像控制對象結構
Create 初始化圖像列表並綁定對象
圖像控制的建立方法如下:
BOOL Create( int cx, int cy, UINT nFlags, int nInitial, int nGrow );
BOOL Create( UINT nBitmapID, int cx, int nGrow, COLORREF crMask );
BOOL Create( LPCTSTR lpszBitmapID, int cx, int nGrow, COLORREF crMask );
BOOL Create( CImageList& imagelist1, int nImage1, CImageList& imagelist2
,int nImage2,int dx, int dy );
其中各項參數的含義爲:cx定義圖像的寬度,單位爲象素;cy定義圖象的高度,單位爲象素;nFlags確定建立圖像列表的類型,可以是以下值的組合:ILC_COLOR、ILC_COLOR4、ILC_COLOR8、ILC_COLOR16、ILC_COLOR24、ILC_COLOR32、ILC_COLORDDB和ILC_MASK;nInitial用來確定圖像列表包含的圖像數量;nGrow用來確定圖像列表可控制的圖像數量。
NbitmapID 用來確定圖像列表聯繫的位圖標誌值;crMask表示顏色屏蔽位;
LpszBitmapID 用來確定包含位圖資源的標識串;
imagelist1 指向圖像列表控制對象的一個指針;nImage1圖像列表1中包含的圖像數 量;imagelist2指向圖像列表控制對象的一個指針;nImage2圖像列表2中包含的圖像數量;dx表示以象素爲單位的圖像寬度;dy表示以象素爲單位的圖像高度。
同樣,圖像控制的建立也包括兩個步驟,首先建立圖像列表結構,然後建立圖像列表控制。
3)、圖像控制的屬性類
圖像控制的屬性類包括返回m_hImageList.控制句柄GetSafeHandle、取得圖像列表中的圖像數量GetImageCount、設置圖像列表的背景顏色SetBkColor、取得圖像列表的背景顏色SetBkColor和取得圖像的有關信息SetBkColor。
4)、圖像控制的操作方法
圖像控制的操作方法包括將一個圖像列表綁定到一個對象上Attach、將對象上的圖像列表解除綁定並返回句柄Detach、刪除一個圖像列表DeleteImageList、將一個圖像增加到圖像列表中Add和將一個圖像從圖像列表中刪除Remove等。
(二)圖像控制的應用技巧
對於圖像控制,同樣不能單獨使用,必須與列表控制、樹控制和標籤控制相互結合應用,下面分別介紹其具體應用技巧。
1)、圖像控制在列表控制中的應用技巧
①設置圖像控制CListCtrl::SetImageList的調用格式如下:
CImageList* SetImageList( CImageList* pImageList, int nImageList );
其返回值是指向前一個圖像列表控制的一個指針,如果不存在前一個圖像列表則爲NULL;其中參數pImageList是指向圖像列表的標識,nImageList是圖像列表的類型,可以是如下值:
LVSIL_NORMAL 用大圖標方式進行圖像列表;
LVSIL_SMALL 用小圖標方式進行圖像列表;
LVSIL_STATE 以圖像狀態進行圖像列表;
②取得圖像控制CListCtrl::GetImageList的調用格式如下:
CImageList* GetImageList( int nImageList ) const;
其返回值爲指向圖像列表控制的指針,其中nImageList用來確定取得返回值的圖像列表的 值,其取值與設置圖像列表函數相同。
③圖像控制在列表控制中的應用示例
CImageList Cil1,Cil2; //定義大小圖標像列表
CVCLISTApp *pApp=(CVCLISTApp *)AfxGetApp();//取得列表控制程序
Cil1.Create(32,32,TRUE,2,2); //建立32位圖像控制
Cil1.Add(pApp->LoadIcon(IDI_GJ));//增加選中狀態圖像
Cil1.Add(pApp->LoadIcon(IDI_XS));//增加非選中狀態圖像
Cil2.Create(16,16,TRUE,2,2); //建立16位圖像控制
Cil2.Add(pApp->LoadIcon(IDI_GJ));//增加選中狀態圖像
Cil2.Add(pApp->LoadIcon(IDI_XS));//增加非選中狀態圖像
m_ListCtrl.SetImageList(&Cil1,LVSIL_NORMAL);//設置大圖標控制
m_ListCtrl.SetImageList(&Cil2,LVSIL_SMALL);//設置小圖標控制
2)、圖像控制在樹控制中的應用技巧
①設置圖像控制CTreeCtrl::SetImageList的調用格式如下:
CImageList* SetImageList( CImageList * pImageList, int nImageListType );
其返回值爲指向前前一個圖像列表的指針,否則爲NULL;參數pImageList爲指向圖像列表的標識,如果pImageList爲NULL則所有的圖像都將從樹控制中被清除;nImageListType爲圖像列表設置的類型,可以是如下值之一:
TVSIL_NORMAL 設置正常圖像列表,其中包括選中和非選中兩種圖標;
TVSIL_STATE 設置圖像列表狀態,指用戶自定義狀態;
②取得圖像控制CTreeCtrl::GetImageList的調用格式如下:
CImageList* GetImageList( UINT nImage );
如果調用成功則返回圖像列表控制指針,否則爲NULL;nImage爲取得返回值的圖像列表類型,其取值和取得圖像列表控制完全相同。
③圖像控制在樹控制中的應用示例
CImageList Cil1,Cil2;//定義大小圖標像列表
CVCTREEApp *pApp=(CVCTREEApp *)AfxGetApp();//獲取應用程序指針
Cil1.Create(16,16,ILC_COLOR,2,2);//建立圖像控制
Cil1.Add(pApp->LoadIcon(IDI_PM));//增加選中狀態圖像
Cil1.Add(pApp->LoadIcon(IDI_CJ));//增加非選中狀態圖像
m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL);//設置圖像控制列表
然後在樹控制的結構定義中進行如下設置:
TCItem.item.iImage=0; //設置未選中圖像索引號
TCItem.item.iSelectedImage=1;//設置選中時圖像引號
3)、圖像控制在標籤控制中的應用技巧
①設置圖像控制CTabCtrl::SetImageList的調用格式
CImageList * SetImageList( CImageList * pImageList );
其返回值爲指向前一個圖像列表的指針,如果不存在前一個圖像列表則爲NULL;pImageList爲標識TAB控制的圖像列表指針。
②取得圖像控制CTabCtrl::GetImageList的調用格式
HIMAGELIST GetImageList() const;
其返回值爲指向TAB控制的圖像列表指針,如果調用不成功則爲NULL。
26、CheaderCtrl表頭控件
表頭控件是一個有組織的排列成一行的標籤序列,表頭控件(CheaderCtrl)通常應用在窗口中的文本或數據的列表之上。一般爲數據列的標題,可以包括多個部分(圖標、文本、位圖),用戶可以拖動每個部分並可以控制每列的寬度。表頭控件類提供了普通表頭控件的基本方法,它一般與標籤控件(CtabCtrl)和列表控件(ClistCtrl)配套使用。
1)、表頭控件的建立
BOOL Create(DWORD dwStyle,const RECT & rect,CWnd *pParentWnd,UINT nID);
參數說明:
dwStyle,表示表頭控件風格,它可以是下列值之一:
HDS_BUTTONS 表頭控件外觀類似按鈕
HDS_HORZ 表頭控件爲水平排列
HDS_VERT 表頭控件爲垂直排列
HDS_HIDDEN 表頭控件爲隱藏模式
HDS_FILTERBAR 允許將過濾條作爲表頭控件的一部分,過濾條可以定製有選擇地顯示內容
HDS_FULLDRAG 在用戶重新設定列寬時同樣顯示列內容
rect,表示表頭控件的大小和位置
pParentWnd,表示表頭控件的父窗口
nID, 表示表頭控件的ID值
2)、表頭控制的屬性
表頭控制的屬性包括取得表頭控制中項目的數量GetItemCount、取得表頭控制中某一項目的內容GetItem和設置表頭控制中某一項目的內容SetItem。
3)、表頭控制的操作方法
表頭控制的操作方法包括向表頭控制中插入一個新項目InsertItem、從表頭控制中刪除一個項目DeleteItem和繪製表頭中給定的項目DrawItem等。
注:表頭控制的數據結構
在使用表頭控制時,首先必須建立一個數據結構HD_ITEM,其結構定義如下:
typedef struct _HD_ITEM
{ UINT mask; //結構成員有效控制位
int cxy; //表頭項目的寬度
LPSTR pszText; //表頭項目內容
HBITMAP hbm; //表頭項目的位置句柄
int cchTextMax; //表頭內容字符串長度
int fmt; //表頭項目的格式
LPARAM lParam; //應用程序定義的32位數據
} HD_ITEM;
屏蔽控制位說明了數據結構成員中包含的有效數據,可以是下面標誌的組合:
HDI_BITMAP hbm成員有效
HDI_FORMAT fmt 成員有效
HDI_LPARAM lParam成員有效
HDI_TEXT pszText 和cchTextMax 成員有效
HDI_WIDTH cxy 成員有效並確定項目寬度值
格式標誌位fmt可以是以下標誌的組合:
HDF_CENTER 表頭項目居中
HDF_LEFT 表頭項目左對齊
HDF_RIGHT 表頭項目右對齊
HDF_BITMAP 表頭顯示一個位圖
HDF_OWNERDRAW 由主窗口自繪表頭項目
HDF_STRING 表頭項目爲一個字符串
27、CFileDialog
CFileDialog文件選擇對話框的使用
首先構造一個對象並提供相應的參數,構造函數原型如下:
CFileDialog::CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );參數意義如下:
bOpenFileDialog 爲TRUE則顯示打開對話框,爲FALSE則顯示保存對話文件對話框。
lpszDefExt 指定默認的文件擴展名。
lpszFileName 指定默認的文件名。
dwFlags 指明一些特定風格。
lpszFilter 是最重要的一個參數,它指明可供選擇的文件類型和相應的擴展名。參數格式如:
"Chart Files (*.xlc)|*.xlc|Worksheet Files (*.xls)|*.xls|Data Files (*.xlc;*.xls)|*.xlc; *.xls|All Files (*.*)|*.*||";文件類型說明和擴展名間用 | 分隔,同種類型文件的擴展名間可以用 ; 分割,每種文件類型間用 | 分隔,末尾用 || 指明。
pParentWnd 爲父窗口指針。
創建文件對話框可以使用DoModal(),在返回後可以利用下面的函數得到用戶選擇:
CString CFileDialog::GetPathName( ) 得到完整的文件名,包括目錄名和擴展名如:c:\test\test1.txt
CString CFileDialog::GetFileName( ) 得到完整的文件名,包括擴展名如:test1.txt
CString CFileDialog::GetExtName( ) 得到完整的文件擴展名,如:txt
CString CFileDialog::GetFileTitle ( ) 得到完整的文件名,不包括目錄名和擴展名如:test1
POSITION CFileDialog::GetStartPosition( ) 對於選擇了多個文件的情況得到第一個文件位置。
CString CFileDialog::GetNextPathName( POSITION& pos ) 對於選擇了多個文件的情況得到下一個文件位置,並同時返回當前文件名。但必須已經調用過POSITION CFileDialog::GetStartPosition( )來得到最初的POSITION變量。
CColorDialog顏色選擇對話框的使用
首先通過CColorDialog::CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL )構造一個對象,其中clrInit爲初始顏色。通過調用DoModal()創建對話框,在返回後調用COLORREF CColorDialog::GetColor( )得到用戶選擇的顏色值。
CFontDialog字體選擇對話框的使用
首先構造一個對象並提供相應的參數,構造函數原型如下:
CFontDialog::CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL );構造一個對象,其中參數lplfInitial指向一個LOGFONG結構.如果該參數設置爲NULL表示不設置初始字體。pdcPrinter指向一個代表打印機設備環境的DC對象,若設置該參數則選擇的字體就爲打印機所用。pParentWnd用於指定父窗口。通過調用DoModal()創建對話框,在返回後通過調用以下函數來得到用戶選擇:
void CFontDialog::GetCurrentFont( LPLOGFONT lplf );用來獲得所選字體的屬性。該函數有一個參數,該參數是指向LOGFONT結構的指針,函數將所選字體的各種屬性寫入這個LOGFONT結構中。
CString CFontDialog::GetFaceName( ) 得到所選字體名字。
int CFontDialog::GetSize( ) 得到所選字體的尺寸(以10個象素爲單位)。
COLORREF CFontDialog::GetColor( ) 得到所選字體的顏色。
BOOL CFontDialog::IsStrikeOut( )
BOOL CFontDialog::IsUnderline( )
BOOL CFontDialog::IsBold( )
BOOL CFontDialog::IsItalic( )
得到所選字體的其他屬性,是否有刪除線,是否有下劃線,是否爲粗體,是否爲斜體。
三、特效圖像處理技術
1、 GDI在Windows中定義爲Graphics Device Interface,即圖形設備接口,是Windows API(Application Programming Interface)的一個重要組成部分。它是Windows圖形顯示程序與實際物理設備之間的橋樑,GDI使得用戶無需關心具體設備的細節,而只需在一個虛擬的環境(即邏輯設備)中進行操作。
GDI、GDI+編程操作:
http://dev.yesky.com/255/2190255.shtml
2、DirectX
DirectX是一種圖形應用程序接口(API),簡單的說它是一個輔助軟件,一個提高系統性能的加速軟件,由微軟創建開發的,微軟將定義它爲“硬件設備無關性”。Direct是直接的意思,X是很多東西,加在一起就是一組具有共性的東西,從內部原理探討,也簡單說來DirectX 就是一系列的 DLL (動態連接庫),通過這些 DLL,開發者可以在無視於設備差異的情況下訪問底層的硬件,DirectX 封裝了一些 COM(Component Object Model)對象,這些 COM 對象爲訪問系統硬件提供了一個主要的接口。
DirectX並不是一個單純的圖形API,它是由微軟公司開發的用途廣泛的API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個組件,它提供了一整套的多媒體接口方案。只是其在3D圖形方面的優秀表現,讓它的其它方面顯得暗淡無光。DirectX開發之初是爲了彌補Windows 3.1系統對圖形、聲音處理能力的不足,而今已發展成爲對整個多媒體系統的各個方面都有決定性影響的接口。
下載地址:
Direct9.0c http://www.fs2you.com/files/9c976905-0cb9-11dd-9c0b-00142218fc6e/
DirectX 9.0C http://down1.tech.sina.com.cn/download/downContent/2004-03-16/363.shtml
參考書籍:《Visual C++ 6.0高級編程技術——DirectX篇》
3、OpenGL
OpenGL是近幾年發展起來的一個性能卓越的三維圖形標準,它是在SGI等多家世界聞名的計算機公司的倡導下,以SGI的GL三維圖形庫爲基礎制定的一個通用共享的開放式三維圖形標準。目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都採用了OpenGL做爲三維圖形標準,許多軟件廠商也紛紛以OpenGL爲基礎開發出自己的產品,其中比較著名的產品包括動畫製作軟件Soft Image和3D Studio MAX、仿真軟件Open Inventor、VR軟件World Tool Kit、CAM軟件ProEngineer、GIS軟ARC/INFO等等。值得一提的是,隨着Microsoft公司在Windows
NT和最新的Windows 95中提供了OpenGL標準及OpenGL三維圖形加速卡的推出,OpenGL將在微機中有廣泛地應用,同時也爲廣大用戶提供了在微機上使用以前只能在高性能圖形工作站上運行的各種軟件的機會。
OpenGL編程指南(第四版)(PDF)+源碼 下載地址:
http://download.csdn.net/source/286881
四、Windows Shell編程
在Windows環境下,不論是使用Visual C++還是Delphi或是其他一些軟件開發工具開發的應用程序,儘管存在着差別,但有一點是相同的:都是運行於Windows操作系統之下的。在程序開發過程中也經常要在自己的應用程序中加入一些Windows系統本身就有的功能,比如文件的拷貝、刪除、查找以及運行程序等等。而這些功能在Windows操作系統下都是具備的,顯然如果能直接從系統中調用這些功能將不僅僅減少程序的大小和開發人員的工作量,而且由於是直接通過操作系統來完成這些功能,將會大大減小這部分程序出現異常錯誤的概率。Windows系統雖說也存在不少錯誤,但常用功能的錯誤還是比較少的,而且通過補丁程序可以更低限度減少系統錯誤,因此程序員可以將調試檢錯的注意力放在應用程序的其他地方,對於調用系統功能這部分代碼則可以不必投入太大的精力去調試,因爲這部分調試的工作在操作系統發佈的時候就已經由微軟做好了。實際上我們可以通過這些COM接口來直接對Windows外殼進行編程。
具體shell編程可以參考《Windows Shell擴展編程完全指南》書籍,書中提供了shell編程技巧以及大量的實例。下載地址:http://download.csdn.net/source/182553
注意事項:
1、對於控件的背景色(位圖),Windows是通過發送WM_ERASEEKGND消息給控件,讓控件自己決定所使用的背景。對於控件的色彩,Windows是通過發送WM_CTLCOLOR消息給控件,同樣也是通過控件自己決定所使用的色彩。
2、默認情況下,窗口是不響應WM_MOUSELEAVE和WM_MOUSEHOVER消息的,所以要使用_TrackMouseEvent函數來激活這兩個消息。調用這個函數後,當鼠標在指定窗口上停留超過一定時間或離開窗口後,該函數會Post這兩個消息到指定窗口。
使用方法:
1).在對話框類中定義一個變量來標識是否追蹤當前鼠標狀態,之所以要這樣定義是要避免鼠標已經在窗體之上時,一移動鼠標就不斷重複產生WM_MOUSEHOVER。
BOOL _bMouseTrack=TRUE;
2).在OnMouseMove中調用_TrackMouseEvent函數
if (_bMouseTrack) //若允許追蹤,則。
{
TRACKMOUSEEVENT csTME;
csTME.cbSize = sizeof(csTME);
csTME.dwFlags = TME_LEAVE|TME_HOVER;
csTME.hwndTrack = m_hWnd;//指定要追蹤的窗口
csTME.dwHoverTime = 10; //鼠標在按鈕上停留超過10ms,才認爲狀態爲HOVER
::_TrackMouseEvent(&csTME); //開啓Windows的WM_MOUSELEAVE,WM_MOUSEHOVER事件支持
_bMouseTrack=FALSE; //若已經追蹤,則停止追蹤
}
3).在OnMouseLeave中再次允許追蹤鼠標狀態
_bMouseTrack=TRUE;
4).備註:這兩個消息的映射要自己寫
ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
3、子類化
子類化函數的參數說明:
BOOL SubclassDlgItem( UINT nID, CWnd* pParent);將一個 Windows 控件與 CWnd 或 CWnd 派生類的對象連接,然後使它通過 CWnd 或 CWnd 派生類的消息映射轉發消息。其中nID爲該控件的ID,pParent爲控件的父窗口。
BOOL SubclassWindow( HWND hWnd );作用同SubclassDlgItem,只是該函數通過創後的句柄來完成子類化操作。hWnd爲需要子類化的窗口句柄 HWND
UnsubclassWindow();反子類化,該函數使窗口與子類化所連接的類脫離,使用該控件窗口默認的消息處理函數WndProc來處理。函數返回取消子類化的窗口句柄。
4、使用Rich Edit控件前一定要用AfxInitRichEdit()初始化RichEdit環境。
5、一般畫Windows控件的過程分爲三大部分:
第一:在WM_MEASUREITEM消息影射函數中設置當前要畫的Item的大小尺寸;創建控件。(一般自繪控件都響應WM_MEASUREITEM和WM_DRAWITEM消息)
第二:在WM_DRAWITEM消息影射函數中根據Item的大小尺寸來畫該Item(圖標/位圖/字符串等);
第三:在WM_PAINT消息映射函數中不斷的繪製當前的控件內容。
6、使用內存DC防止窗口閃爍
在使用VC開發圖形相關的應用程序時,常常需要使用MFC的CDC類直接把圖形畫在窗口上。這通常是通過響應Windows的WM_PAINT消息實現的。如果要畫的圖形比較複雜,或者比較大,那麼畫圖過程可能會造成窗口的閃爍。當窗口調整大小時,這種閃爍由爲明顯。
解決窗口閃爍問題的有效辦法就是使用內存DC,也稱爲緩衝DC。在內存中準備一個和窗口DC相同屬性的DC,在這個內存DC上執行畫圖操作。完成畫圖以後,把畫圖輸出的內容整體複製到目標窗口DC上。因爲畫圖操作不在窗口DC上進行,所以在畫圖的過程中窗口可以保持原來的內容。當畫好的內容被複制到窗口DC時,因爲複製操作執行的非常快,所以用戶感覺窗口彷彿被立刻被畫好,從而消除了從舊畫面到白板再到新畫面的閃爍現象。
生成內存DC主要用到以下四個函數:
CreateCompatibleDC(CDC* pDC )。CDC類的成員函數,用於創建一個和pDC指向的DC兼容的內存DC。
CreateDiscardableBitmap( CDC* pDC, int nWidth, int nHeight)。CBitmap類的成員函數,用於按指定尺寸創建一個和pDC指向的DC兼容的位圖。
SelectObject(CBitmap * pBitmap)。CDC類的成員函數,執行以後,所以在該DC上的圖像輸出都將被畫到pBitmap指向的位圖上。
BOOL BitBlt (int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )。CDC類的成員函數,用於從源DC(pSrcDC)複製一個矩形的圖象到當前DC中。
對於一個窗口,我們可以用下面的代碼來創建內存DC,在內存DC上輸出,並最終複製到窗口DC上。
void PaintWnd(CWnd * pWnd)
...{
CDC * pWndDC = pWnd->GetWindowDC();
CRect WndRect = pWnd->GetWindowRect();
CDC MemDC;
CBitMap MemBitmap;
MemDC.CreateCompatibleDC(pWndDC); // 創建內存DC
MemBitmap.CreateCompatibleBitmap( // 創建兼容的位圖
pWndDC,
WndRect.Width(),
WndRect.Height());
MemDC.SelectObject(MemBitmap); // 讓內存DC輸出到位圖
// 使用MemDC畫圖
// 。。。。。。
pWndDC->BitBlt( // 從內存DC複製到窗口DC
0,0,
WndRect.Width(),
WndRect.Height(),
&MemDC,
0,0,
SRCCOPY);
}
當然,實際的情況下,我們需要考慮的更多,因爲內存DC、位圖的創建都可能會失敗。爲了簡化代碼,筆者定義了一個類CMemoryDC,包裝了內存DC創建過程中的出錯處理,內存DC的事後清理等操作,並自動複製內存DC的內容到目標DC上。
聲明CMemoryDC類的頭文件MemoryDC.h如下:
#pragma once
#include "Afxwin.h"
class CMemoryDC
...{
public:
CMemoryDC(CDC *dc, RECT * rect,bool autoRender = false);
~CMemoryDC(void);
bool IsOK();
void Render(CDC * p_objectDC = NULL);
CDC* GetMemoryDC();
operator CDC * ();
private:
bool m_bAutoRender;
CRect m_DCRect;
CDC* m_pOriginalDC;
CDC m_MemoryDC;
CBitmap m_MemoryBmp;
};
類的實現文件CMemoryDC.cpp如下:
#include ".MemoryDC.h"
CMemoryDC::CMemoryDC(CDC *dc, RECT * rect, bool autoRender)
...{
m_bAutoRender = autoRender;
m_pOriginalDC = dc;
if (dc==NULL || rect==NULL)
return;
if (!m_MemoryDC.CreateCompatibleDC(dc))
return;
m_DCRect.SetRect(rect->left, rect->top, rect->right, rect->bottom);
if (!m_MemoryBmp.CreateCompatibleBitmap(dc, m_DCRect.Width(), m_DCRect.Height()))
return;
m_MemoryDC.SelectObject(m_MemoryBmp);
}
CMemoryDC::~CMemoryDC(void)
...{
if (m_bAutoRender)
Render();
if (m_MemoryDC.m_hDC!=NULL)
m_MemoryDC.DeleteDC();
if (m_MemoryBmp.m_hObject!=NULL)
m_MemoryBmp.DeleteObject();
}
bool CMemoryDC::IsOK()
...{
return m_MemoryDC.m_hDC!=NULL && m_MemoryBmp.m_hObject != NULL;
}
void CMemoryDC::Render(CDC * p_objectDC)
...{
if (!IsOK())
return;
CDC * pDC = (p_objectDC==NULL ? m_pOriginalDC : p_objectDC);
CSize Size = m_MemoryDC.GetViewportExt() ;
pDC->BitBlt(
m_DCRect.left,
m_DCRect.top,
m_DCRect.Width(),
m_DCRect.Height(),
&m_MemoryDC,
0,0,
SRCCOPY);
}
CDC* CMemoryDC::GetMemoryDC()
...{
return & m_MemoryDC;
}
CMemoryDC::operator CDC * ()
...{
return & m_MemoryDC;
}
使用這個類可以大大簡化內存DC的創建操作。如果我們在窗口消息WM_PAINT的響應函數中使用內存DC,只要用如下這樣簡便的代碼便可實現:
CRect Rect;
GetClientRect(Rect);
CPaintDC dc(this); // device context for painting
CMemoryDC MemDC(&dc, Rect, true);
if (MemDC.IsOK())
...{
// 使用MemDC畫窗口
}
// MemDC析構時會自動把圖像複製到dc,無需其它操作
使用CMemoryDC創建內存DC防止窗口閃爍,編程的代碼和不使用內存DC時相比,數量和複雜性幾乎沒有增加。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/zhengmingen/archive/2009/10/25/4726357.aspx
7、MFC中通用控件初始化過程
InitCommonControls和InitCommonControlsEx從Win95開始,Windows提供了一些新的Win32控件,稱爲通用控件. 如:Toolbar,Status bar,Tree view,List view,Animation,Hot-key,Image list,Tab等等.這些控件的可執行代碼都放在comctl32.dll中.要使用通用控件,必須加載comctl32.dll.
可以調用函數InitCommonControls或InitCommonControlsEx來初始化控件.這兩個函數都是動態鏈接庫comctl32.dll中的函數,兩個函數的原型如下:
void InitCommonControls(VOID);BOOL InitCommonControlsEx(LPINITCOMMONCONTROLSEX lpInitCtrls);可以看到,InitCommonControls沒有參數,表示初始化所有的(實際上是大部分,見下文)通用控件.而InitCommonControlsEx則可以指定初始化什麼控件.
這裏"初始化"的含義是明確的,就是指註冊相應的窗口類.比如,只有事先註冊了"SysTreeView32"窗口類,然後纔可以創建該控件的窗口.
注意,註冊窗口類只對當前進程有效,因爲註冊的時候必須指定一個窗口地址,而地址是隻對一個進程有效的.因此,每個進程都必須初始化後纔可以使用通用控件.
函數InitCommonControls是個空函數,不做任何事情.但如果你調用了該函數,則鏈接器會將你的程序鏈接到comcl32.lib,然後在程序啓動時,會加載comctl32.dll. 真正初始化的工作是在該庫的入口點處做的,在這裏會註冊通用控件窗口類,然後應用程序就可以創建控件窗口,就象創建其它的子窗口控件一樣.
InitCommonControlsEx是實際註冊控件窗口類的函數.它根據參數lpInitCtrls->dwICC的內容類決定調用哪些控件的註冊代碼.相關的值如下:
#define ICC_LISTVIEW_CLASSES 0x00000001 // listview, header#define ICC_TREEVIEW_CLASSES 0x00000002 // treeview, tooltips#define ICC_BAR_CLASSES 0x00000004 // toolbar, statusbar, trackbar, tooltips#define ICC_TAB_CLASSES 0x00000008 // tab, tooltips#define
ICC_UPDOWN_CLASS 0x00000010 // updown#define ICC_PROGRESS_CLASS 0x00000020 // progress#define ICC_HOTKEY_CLASS 0x00000040 // hotkey#define ICC_ANIMATE_CLASS 0x00000080 // animate#define ICC_WIN95_CLASSES 0x000000FF#define ICC_DATE_CLASSES 0x00000100 // month
picker, date picker, time picker, updown#define ICC_USEREX_CLASSES 0x00000200 // comboex#define ICC_COOL_CLASSES 0x00000400 // rebar (coolbar) control #define ICC_INTERNET_CLASSES 0x00000800#define ICC_PAGESCROLLER_CLASS 0x00001000 // page scroller#define
ICC_NATIVEFNTCTL_CLASS 0x00002000 // native font control注意到ICC_WIN95_CLASSES等於之前所有值的或,因此使用該標記調用InitCommonControlsEx會初始化listview,header,treeview等控件.
進程初次加載dll時,系統會以DLL_PROCESS_ATTACH參數調用DLLMain. 在動態庫comctl32.dll中,會在這時候用ICC_WIN95_CLASSES標記調用InitCommonControlsEx, 因此進程一旦加載了comctl32.dll,就註冊了一系列的通用控件.進程最後一次卸載dll時,系統會以DLL_PROCESS_DETACH參數調用DLLMain. 在動態庫comctl32.dll中,會在這時候調用UnregisterClass取消所有已經冊過的通用控件窗口類.
注意:
對Windows 95/98/Me來說,dll卸載的時候,在其中註冊的所有窗口類會自動取消註冊.這是自動進行的,並不需要你寫下UnregisterClass的調用代碼.
對Windows NT/2000/XP來說,當dll卸載的時候,在該dll中註冊的窗口類並不會自動取消註冊,因此必須在DllMain中人爲的用代碼調用unregisterClass. 否則一旦dll卸載後再次創建控件(因爲沒有反註冊,系統認爲窗口類仍有效),則該控件的窗口過程將指向無效的地址.
8、ON_COMMAND_RANGE和ON_COMMAND的區別
ON_COMMAND_RANG來進行批量消息映射,而ON_COMMAND以是用單個消息映射。單個消息映射函數都是無參數的如:OnSchemaChanged(); 而ON_COMMAND_RANG映射的是多個控件,因此需要一個值來標識控件,即消息處理函數至少需要一個 UINT 類的參數來標識是哪一個控件被選擇了,於是我的消息處理函數改成: void OnSchemaChanged( UINT nID );。
ON_COMMAND_RANGE用法:
afx_msg void OnOutPutStatusButtonUp (WPARAM wParam, LPARAM lParam);
BEGIN_MESSAGE_MAP(CIOStatue, CDialog)
//{{AFX_MSG_MAP(CIOStatue)
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(IDC_STATIC_OUT1,IDC_STATIC_OUT16,OnOutPutStatusButtonUp)
END_MESSAGE_MAP()
//注意IDC_STATIC_OUT1,IDC_STATIC_OUT16之間是連續的
void CIOStatue::OnOutPutStatusButtonUp(WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case IDC_STATIC_OUT1:
//代碼1
break;
case IDC_STATIC_OUT2:
//代碼2
break;
case IDC_STATIC_OUT3:
//
break;
//等
}
}
註釋:
當按下IDC_STATIC_OUT1按鈕,執行 代碼1的程序。
當按下IDC_STATIC_OUT2按鈕,執行 代碼2的程序。
等等
9、CDialogBar上所有按鈕都是灰色?解決方法:DialogBar的父窗口類中處理相應Dialog模板上按鈕控件的消息事件: ON_COMMAND 與 ON_UPDATE_COMMAND_UI
ON_COMMAND(IDC_BUTTON, OnButton)
ON_UPDATE_COMMAND_UI(IDC_BUTTON, OnUpdateButton)
10、如何改變對框中控件的顏色
在對話框中加入WM_CTLCOLOR事件,單擊Edit Code按鈕,然後把改函數的內容替換爲如下代碼:
if(nCtlColor== CTLCOLOR_LISTBOX)//控件類型
{
pDC- >SetBkMode(TRANSPARENT);
pDC- >SetTextColor(#ffffff);
//此處設置字體的顏色
return (HBRUSH)m_brush.GetSafeHandle();
}
else
{
return CDialog::OnCtlColor (pDC, pWnd, nCtlColor);
}
11、在ComboBox中改變列表框的寬度
組合框是是有2種功能的--下拉和列表。一般情況下,列表框的寬度和選擇框是一樣寬的,但是我們有些時候確實很需要把列表框的寬度變大,一便讓我們能更好的看我們要選的東西。爲了能有這個功能,寫了下面的這個函數。首先得在你的對話框中添加一個的WM_CTLCOLOR的消息句柄,或者使用CComboBox的繼承類,而且在其中添加下面的代碼:
HBrush tvisualcombo::onctlcolor(CDC* pdc, CWND* pwnd, UINT nctlcolor)
{
HBrush hbr = ccombobox::onctlcolor(pdc, pwnd, nctlcolor);
switch (nctlcolor) {
case ctlcolor_edit:
break;
case ctlcolor_listbox:
if (listwidth > 0) {
// new width of a listbox is defined
CRect rect;
pwnd->GetWindowRect(&rect);
if (rect.Width() != listwidth) {
rect.right = rect.left + listwidth;
pwnd->MoveWindow(&rect);
}
}
break;
}
// todo: return a different brush if the default is not desired
return hbr;
}
這樣之後還沒有完全好,你還得刷新一下列表框,那樣才能隨時根據列表框中的文本的長度,而改變列表框的寬度,要想這樣的話,你還得這樣,你必須掃描列表框中的條目,還得計算其中文本的長度(通過pdc),這樣你如果再刷新列表框的話,才能一條目中比較長的來顯示。
上面的方法是通過WM_CTLCOLOR消息來實現的,後來才知道在MFC的CComboBox類中有一個函數也可以實現同樣的功能,就是:
CComboBox::SetDroppedWidth(int width);
通過這個函數,你可以把寬度設成你自己喜歡的值,而它的實際的寬度是下面2個值中的最大值:
1).你所設置的值(就是通過上面的函數所設置的值)
2).列表框的值
12、怎樣在程序開始的時候讓它最大化?
在App類裏的C…App::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);
13、如何在顯示窗口時,使最大化按鈕變灰?
第一種方法:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// disable the maxmini box
cs.style &= ~WS_MAXIMIZEBOX;
return TRUE;
}
第二種方法:
CMenu *pMenu=AfxGetApp()->m_pMainWnd->GetSystemMenu(FALSE);
int x=pMenu->GetMenuItemCount( );
UINT pID=pMenu->GetMenuItemID(x-1);
pMenu->EnableMenuItem(pID, MF_DISABLED);
第三種方法:
ModifyStyle(WS_MAXIMIZEBOX, 0);
這個函數也可以是最大化按鈕失效!
並且可以在程序中動態的改變窗口的風格
14、更改屬性頁標題
void CXXXSheet::SetPageTitle(int nPage, int nImage, CString strTitle)
{
TC_ITEM item;
//item.mask = TCIF_TEXT|TCIF_IMAGE; //設置圖標和文字
item.mask = TCIF_IMAGE; //只設置圖標
item.iImage = nImage;
// item.pszText = strTitle.GetBuffer(0); //設置文字
GetTabControl ()->SetItem (nPage, &item);
//要設置文字時就將上面2行有註釋符的代碼前的註釋符去掉
}
15、創建動態菜單
void CMainFrame::OnSelectState(NMTOOLBAR* pnmtb, LRESULT *plr)
{
"CMenu menu;
"if(!menu.CreateMenu())
"return;
"menu.AppendMenu(MF_STRING,0,"開始");
"menu.AppendMenu(MF_STRING,0,"結束");
"CRect rc;
"m_wndToolBar.SendMessage(TB_GETRECT, pnmtb->iItem, (LPARAM)&rc);
"m_wndToolBar.ClientToScreen(&rc);
"menu.TrackMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
"""rc.left, rc.bottom, this, &rc);
//"menu.DestroyMenu();
"menu.detach();
}
16、打印
1)要打印哪個視就
((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.SetActivePane(...)
//要打印的那個視對應的Pane
2)有一個單文檔工程,文檔窗口被切分:左視圖由CTreeView 的派生類管理,右視圖由CListView 的派生類CMyListView(其爲風格爲LVS_REPORT)管理,我想爲右視圖添加打印和打印預覽,我在MyListView.cpp中添加了
ON_COMMAND(ID_FILE_PRINT,CListView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CListView::OnFilePrintPreview)還有
BOOL CMyListView::OnPreparePrinting(CPrintInfo* pInfo)
{
// TODO: call DoPreparePrinting to invoke the Print dialog box
// return CListView::OnPreparePrinting(pInfo);
pInfo->SetMaxPage(2);
BOOL bret=DoPreparePrinting(pInfo);
pInfo->m_nNumPreviewPages=2;
return bret;
}
3)Crystal report(水晶報表)打印
http://www.svn8.com/c/VC/2010012919646.html
17、Scroll編程技巧
1)設置滾動條的滾動大小
創建一個基於CScrollview的SDI Project(在第6步中選CScrollview)
然後改爲如下:
void CTestView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: calculate the total size of this view
sizeTotal.cx = 1024; //改這兩個
sizeTotal.cy = 768; //
SetScrollSizes(MM_TEXT, sizeTotal);
}
2)滾動條的控制
BOOL CDiagramShowView::PreTranslateMessage(MSG* pMsg)
{
CFileTreeDoc* pDoc = (CFileTreeDoc*)GetDocument();
CPoint point = GetScrollPosition();
if(pMsg->message == WM_KEYDOWN)
{
switch(pMsg->wParam)
{
case VK_LEFT:
if( point.x > 10)
{
EndPoint.x = EndPoint.x - 10;
EndPoint.y = EndPoint.y;
}
else
{
EndPoint.x = 0;
EndPoint.y = EndPoint.y;
}
ScrollToPosition(EndPoint);
InvalidateRect(NULL,TRUE);
break;
case VK_RIGHT:
if( point.x < pDoc->intDiagramColumnCount * pDoc->intColumnWidth - 10 )
{
EndPoint.x = EndPoint.x + 10;
EndPoint.y = EndPoint.y;
}
else
{
EndPoint.y = pDoc->intDiagramColumnCount * pDoc->intColumnWidth;
EndPoint.x = EndPoint.x;
}
ScrollToPosition(EndPoint);
InvalidateRect(NULL,TRUE);
break;
case VK_UP:
if( point.y > 10)
{
EndPoint.y = EndPoint.y - 10;
EndPoint.x = EndPoint.x;
}
else
{
EndPoint.y = 0;
EndPoint.x = EndPoint.x;
}
ScrollToPosition(EndPoint);
InvalidateRect(NULL,TRUE);
break;
case VK_DOWN:
if( point.y < pDoc->intDiagramRowCount * pDoc->intRowHeight - 10 )
{
EndPoint.y = EndPoint.y + 10;
EndPoint.x = EndPoint.x;
}
else
{
EndPoint.y = pDoc->intDiagramRowCount * pDoc->intRowHeight;
EndPoint.x = EndPoint.x;
}
ScrollToPosition(EndPoint);
InvalidateRect(NULL,TRUE);
break;
default:
break;
}
}
return FALSE;
}
// 通過正負號判斷是向上還是向下滾動
if(zDelta==120)
向上滾動
if(zDelta==-120)
向下滾動
BOOL CDiagramShowView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
CFileTreeDoc* pDoc = (CFileTreeDoc*)GetDocument();
CPoint point = GetScrollPosition();
if(zDelta==120)
{
if( point.y >= 20 )
{
EndPoint.x = point.x;
EndPoint.y = point.y;
EndPoint.x = EndPoint.x;
EndPoint.y = EndPoint.y - 20;
}
else
{
EndPoint.x = EndPoint.x;
EndPoint.y = 0;
}
}
if(zDelta==-120)
{
if( point.y <= pDoc->intDiagramRowCount * pDoc->intRowHeight - 20 )
{
EndPoint.x = point.x;
EndPoint.y = point.y;
EndPoint.x = EndPoint.x;
EndPoint.y = EndPoint.y + 20;
}
else
{
EndPoint.x = EndPoint.x;
EndPoint.y = EndPoint.y;
}
}
ScrollToPosition(EndPoint);
InvalidateRect(NULL,TRUE);
return CScrollView::OnMouseWheel(nFlags, zDelta, pt);
}
3).給從CWnd派生的窗口添加滾動條
ModifyStyle(0,WS_VSCROLL);
4).如何用鍵盤滾動分割的視口
我的問題是當我用鼠標滾動分割窗口時,視口滾動都很正常,但用鍵盤時,卻什麼也沒有發生.
在你的視圖繼承類中加入如下兩個函數,假定該類爲CScrollerView:
void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
BOOL processed;
for (unsigned int i=0;i< nRepCnt&&processed;i++)
processed=KeyScroll(nChar);
if (!processed)
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
BOOL CScrollerView::KeyScroll(UINT nChar)
{
switch (nChar)
{
case VK_UP:
OnVScroll(SB_LINEUP,0,NULL);
break;
case VK_DOWN:
OnVScroll(SB_LINEDOWN,0,NULL);
break;
case VK_LEFT:
OnHScroll(SB_LINELEFT,0,NULL);
break;
case VK_RIGHT:
OnHScroll(SB_LINERIGHT,0,NULL);
break;
case VK_HOME:
OnHScroll(SB_LEFT,0,NULL);
break;
case VK_END:
OnHScroll(SB_RIGHT,0,NULL);
break;
case VK_PRIOR:
OnVScroll(SB_PAGEUP,0,NULL);
break;
case VK_NEXT:
OnVScroll(SB_PAGEDOWN,0,NULL);
break;
default:
return FALSE; // not for us
// and let the default class
// process it.
}
return TRUE;
}
18、修改主窗口風格
AppWizard生成的應用程序框架的主窗口具有缺省的窗口風格,比如在窗口標題條中自動添加文檔名、窗口是疊加型的、可改變窗口大小等。要修改窗口的缺省風格,需要重載CWnd::PreCreateWindow(CREATESTRUCT& cs)函數,並在其中修改CREATESTRUCT型參數cs。
CWnd::PreCreateWindow 函數先於窗口創建函數執行。如果該函數被重載,則窗口創建函數將使用CWnd::PreCreateWindow 函數返回的CREATESTRUCT cs參數所定義的窗口風格來創建窗口;否則使用預定義的窗口風格。
CREATESTRUCT結構定義了創建函數創建窗口所用的初始參數,其定義如下:
typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams; // 創建窗口的基本參數
HANDLE hInstance; // 擁有將創建的窗口的模塊實例句柄
HMENU hMenu; // 新窗口的菜單句柄
HWND hwndParent; // 新窗口的父窗口句柄
int cy; // 新窗口的高度
int cx; // 新窗口的寬度
int y; // 新窗口的左上角Y座標
int x; // 新窗口的左上角X座標
LONG style; // 新窗口的風格
LPCSTR lpszName; // 新窗口的名稱
LPCSTR lpszClass; // 新窗口的窗口類名
DWORD dwExStyle; // 新窗口的擴展參數
} CREATESTRUCT;
CREATESTRUCT結構的style域定義了窗口的風格。比如,缺省的MDI主窗口的風格中就包括FWS_ADDTOTITLE(在標題條中顯示當前的工作文檔名)、FWS_PREFIXTITLE(把文檔名放在程序標題的前面)、WS_THICKFRAME(窗口具有可縮放的邊框)等風格。由於多種風格參數由邏輯或(“|”)組合在一起的,因此添加某種風格,就只需用“|”把對應的參數加到CREATESTRUCT結構的style域中;刪除已有的風格,則需用“&”連接CREATESTRUCT結構的style域與該風格的邏輯非值。
CREATESTRUCT結構的x、y、cx、cy域分別定義了窗口的初始位置和大小,因此,在CWnd::PreCreateWindow 函數中給它們賦值,將能定義窗口的初始顯示位置和大小。
下例中的代碼將主框窗口的大小將固定爲1/4屏幕,標題條中僅顯示窗口名,不顯示文檔名。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// 修改主窗風格
cs.style &= ~FWS_ADDTOTITLE; //去除標題條中的文檔名
cs.style &= ~WS_THICKFRAME; //去除可改變大小的邊框
cs.style |= WS_DLGFRAME; //增加不能改變大小的邊框
// 確定主窗的大小和初始位置
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);//獲得屏幕寬
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); //獲得屏幕高
cs.x = 0; // 主窗位於左上角
cs.y = 0;
cs.cx = cxScreen/2; // 主窗寬爲1/2屏幕寬
cs.cy = cxScreen/2; // 主窗高爲1/2屏幕高
return CMDIFrameWnd::PreCreateWindow(cs);
}
19、如何隱藏工具欄
添加如下兩個函數
隱藏:
void CMainFrame::OnHide()
{
if(m_wndToolBar.IsWindowVisible())
m_wndToolBar.ModifyStyle(WS_VISIBLE,0);
SendMessage(WM_SIZE);
}
顯示:
void CMainFrame::OnShow()
{
if(!m_wndToolBar.IsWindowVisible())
m_wndToolBar.ModifyStyle(0,WS_VISIBLE);
SendMessage(WM_SIZE);
}
20、如何獲得狀態條的指針:
CStatusBar * pStatusBar =(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
21、在狀態條中顯示鼠標的設備座標與邏輯座標
顯示器的設備座標系的原點在客戶區的左上角,x軸向右增長,y軸向下增長。我們要設置的邏輯座標系的原點則在客戶區的中心,x軸向右增長,y軸向上增長,如一個笛卡爾座標系一般。
爲CChildView添加一個成員函數void OnPrepareDC(CDC * pDC, CPrintInfo * pInfo = NULL);
void OnPrepareDC(CDC * pDC, CPrintInfo * pInfo){
CRect rect;
// 設置映射模式爲LOMETRIC (0.1mm),右上爲增長方向
pDC->SetMapMode (MM_LOMETRIC);
// 將座標原點定在客戶區的中心
GetClientRect(rect);
pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);
}
爲CChildView響應鼠標移動消息,並在狀態條中顯示鼠標的座標值。m_ptMouse數據成員是原打算做十字交叉線用的,在此使用沒有實際意義。
void CChildView::OnMouseMove(UINT nFlags, CPoint point){
CClientDC dc(this);
CString str;
OnPrepareDC(&dc);
//要訪問類CMainFrame,需要將mainfrm.h文件引入
CMainFrame * pFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;
//要訪問CMainFrame的數據成員m_wndStatusBar,需要手工修改mainfrm.h,public這個數據成員
CStatusBar * pStatus = (CStatusBar *) &pFrame->m_wndStatusBar;
m_ptMouse = point;
str.Format ("設備座標 X=%i pixel, Y=%i pixel", m_ptMouse.x, m_ptMouse.y);
pStatus->SetPaneText(1, str);
dc.DPtoLP(&m_ptMouse);
str.Format ("邏輯座標 X=%i * 0.1mm, Y=%i * 0.1mm", m_ptMouse.x, m_ptMouse.y);
pStatus->SetPaneText(2, str);
}
22、如何用VC++ 動態修改應用程序菜單
使用CWnd::GetMenu( )訪問主菜單,GetMenu( )返回指向CMenu對象的指針,它有一些成員函數,允許我們修改一個菜單。
1) 如何實現找到一個菜單項:
步驟如下:
{
//動態修改菜單:
// Get the Main Menu
CMenu* pMainMenu = AfxGetMainWnd()->GetMenu();
CMenu* pSubMenu = NULL;
int i;
for (i=0; i<(int)pMainMenu->GetMenuItemCount(); i++)
{
pSubMenu = pMainMenu->GetSubMenu(i);
if (pSubMenu && pSubMenu->GetMenuItemID(0) == ID_FILE_NEW)
break;
}
CString s;
s.Format("%d",i);//菜單項的位數.
AfxMessageBox(s);
ASSERT(pSubMenu);
}
2) 動態編輯菜單:
步驟如下(可以用上例的pSubMenu,要加的菜單你自己定義.):
1) 添加一個稱爲Wzd2,命令ID爲IDC_NAME_NEW1的菜單命令到該菜單中,可以用:
pSubMenu->AppendMenu(0,IDC_NAME_NEW1,"New&1");
2) 在New1前插入New2,可以用:
pSubMenu->InsertMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW2, "New&2");
3) 把New1改變成New3,可以用:
pSubMenu->ModifyMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW3, "New&3");
4) 刪除該菜單中第二項,可以用:
pSubMenu->RemoveMenu(1,MF_BYPOSITION);
23、SetCapture的具體功能並不像MSDN中所說的那樣:調用SetCapture一次直到使用ReleaseCapture終止鼠標捕獲前都會起到對鼠標的捕獲作用。實際上,在使用過程中,用戶肯定會發現,在進行了一次鼠標捕獲之後,SetCapture便失去了作用,這可能是SetCapture函數的一個Bug。所以在編程時,最好能夠不斷地調用SetCapture函數,以保證SetCapture能夠對鼠標進行正確無誤的捕獲。
24、透明位圖的顯示
包含透明色的位圖的繪製方法有多種,最簡單的方法是調用現成的函數:TransparentBlt,也可以通過自己的代碼實現類似TransparentBlt的功能,實現過程也有兩種形式,一種是事先做一張掩碼位圖,另一種是動態生成掩碼位圖。本文將介紹動態生成掩碼位圖繪製具有透明區域位圖的方法。
http://www.vckbase.com/document/viewdoc/?id=532
25、使用VC創建Office 應用程序自動化
http://blog.sina.com.cn/s/blog_557d25460100guyb.html
http://blog.csdn.net/sgdgoodboy/archive/2008/02/18/2102628.aspx
http://blog.csdn.net/sgdgoodboy/archive/2008/02/18/2102641.aspx
http://blog.csdn.net/sgdgoodboy/archive/2008/02/18/2102644.aspx
26、VC/MFC的HDC,CDC,CWindowDC,CClientDC,CPaintDC詳解:
首先說一下什麼是DC(設備描述表)
解:Windows應用程序通過爲指定設備(屏幕,打印機等)創建一個設備描述表(Device Context, DC)在DC表示的邏輯意義的“畫布”上進行圖形的繪製。DC是一種包含設備信息的數據結構,它包含了物理設備所需的各種狀態信息。Win32程序在繪製圖形之前需要獲取DC的句柄HDC,並在不繼續使用時釋放掉。
在c++ 編程中常會見到HDC,CDC,CClientDC,CPaintDC,CWindowDC這樣的類
HDC是DC的句柄,API中的一個類似指針的數據類型.
CDC是MFC的DC的一個類
CDC等設備上下分類,都含有一個類的成員變量:m_nHdc;即HDC類型的句柄.
CDC及其派生類的繼承視圖:
CObject
public |------CDC
public |------|------CClientDC
public |------|------CPaintDC
public |------|------CWindowDC
public |------|------CMetaFileDC
(注意: 除CMetaFileDC以外的三個派生類用於圖形繪製.)
CDC類定義了一個設備描述表相關的類,其對象提供成員函數操作設備描述表進行工作,如顯示器,打印機,以及顯示器描述表相關的窗口客戶區域。
通過CDC的成員函數可進行一切繪圖操作。CDC提供成員函數進行設備描述表的基本操作,使用繪圖工具,選擇類型安全的圖形設備結構(GDI),以及色彩,調色板。除此之外還提供成員函數獲取和設置繪圖屬性,映射,控制視口,窗體範圍,轉換座標,區域操作,裁減,劃線以及繪製簡單圖形(橢圓,多邊形等)。成員函數也提供繪製文本,設置字體,打印機換碼,滾動,處理元文件。
其派生類:
CPaintDC: 封裝BeginPaint和EndPaint兩個API的調用。
(1)用於響應窗口重繪消息(WM_PAINT)是的繪圖輸出。
(2)CPaintDC 在構造函數中調用BeginPaint()取得設備上下文,在析構函數中調用EndPaint()釋放設備上下文。EndPaint()除了釋放設備上下文外,還負責從消息隊列中清除WM_PAINT消息。因此,在處理窗口重畫時,必須使用CPaintDC,否則WM_PAINT消息無法從消息隊列中清除,將引起不斷的窗口重畫。
(3)CPaintDC也只能用在WM_PAINT消息處理之中。
CClientDC(客戶區設備上下文): 處理顯示器描述表的相關的窗體客戶區域。用於客戶區的輸出,與特定窗口關聯,可以讓開發者訪問目標窗口中客戶區,其構造函數中包含了GetDC,析構函數中包含了ReleaseDC。
CWindowDC: 處理顯示器描述表相關的整個窗體區域,包括了框架和控件(子窗體)。
(1)可在非客戶區繪製圖形,而CClientDC,CPaintDC只能在客戶區繪製圖形。
(2)座標原點是在屏幕的左上角,CClientDC,CPaintDC下座標原點是在客戶區的左上角。
(3)關聯一特定窗口,允許開發者在目標窗口的任何一部分進行繪圖,包含邊界與標題,這種DC同WM_NCPAINT消息一起發送。
CMetaFileDC: 與元文件相關的設備描述表關聯。
CDC提供兩個函數,GetLayout和SetLayout用於反轉設備描述表的佈局。用於方便阿拉伯,希伯來的書寫文化習慣的設計,以及非歐洲表中的字體佈局。
CDC 包含兩個設備描述表,m_hDC和m_hAttribDC對應於相同的設備,CDC爲m_hDC指定所有的輸出GDI調用,大多數的GDI屬性調用由 m_hAttribDC控制。(如,GetTextColor是屬性調用,而SetTextColor是一種輸出調用。)
下面用一些簡單的代碼看看如果使用這些類
HDC使用, 每次畫線等操作都不MFC封裝的類多了個HDC的參數
執行在哪個設備描述表操作
HDC hdc=::GetDC(m_hWnd);//m_hWnd == this->m_hWnd 即當前窗口句柄
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);//必須和GetDC配對
可以看到HDC的使用較麻煩, 而且如果::GetDC和::ReleaseDC不配對的話,會造成錯誤
CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CWindowDC dc(this);
CWindowDC dc2(GetDesktopWindow());//獲得整個桌面的句柄, 一些桌面特效程序使用
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CPaintDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
可以看到 MFC 的類使用方便很多, 因爲它們都在構造函數和析構函數調用了響應的函數進行DC的獲取和釋放.
下面說下一些細點的知識點
CClientDC,CWindowDC 區別不大, 可以說 CWindowDC包含了CClientDC 就拿記事本來說
CClientDC 就只是白白的我們可以編輯文字的那個區域是客戶區
CWindowDC 除了上面說的白白區域, 還包括菜單欄和工具欄等
CClientDC和CWindowDC 與 CPaintDC 的區別大點
在DC的獲取方面 CClientDC和CWindowDC 使用的是並只能是 GetDC 和 ReleaseDC
CPaintDC 使用的是並只能是 BeginPaint 和 EndPaint
CPaintDC 只能用在響應 WM_PAINT 事件
CClientDC,CWindowDC 只能用在響應 非WM_PAINT 事件
關於 WM_PAINT 事件
系統會在多個不同的時機發送WM_PAINT消息:當第一次創建一個窗口時,當改變窗口的大小時,當把窗口從另一個窗口背後移出時,當最大化或最小化窗口時,等等,這些動作都是由系統管理的,應用只是被動地接收該消息,在消息處理函數中進行繪製操作;大多數的時候應用也需要能夠主動引發窗口中的繪製操作,比如當窗口顯示的數據改變的時候,這一般是通過InvalidateRect和InvalidateRgn函數來完成的。InvalidateRect和 InvalidateRgn把指定的區域加到窗口的Update Region中,當應用的消息隊列沒有其他消息時,如果窗口的Update
Region不爲空時,系統就會自動產生WM_PAINT消息。系統爲什麼不在調用Invalidate時發送 WM_PAINT消息呢?又爲什麼非要等應用消息隊列爲空時才發送WM_PAINT消息呢?這是因爲系統把在窗口中的繪製操作當作一種低優先級的操作,於是儘可能地推後做。不過這樣也有利於提高繪製的效率:兩個WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,然後在一個WM_PAINT消息中一次得到更新,不僅能避免多次重複地更新同一區域,也優化了應用的更新操作。像這種通過
InvalidateRect和InvalidateRgn來使窗口區域無效,依賴於系統在合適的時機發送WM_PAINT消息的機制實際上是一種異步工作方式,也就是說,在無效化窗口區域和發送WM_PAINT消息之間是有延遲的;有時候這種延遲並不是我們希望的,這時我們當然可以在無效化窗口區域後利用SendMessage 發送一條WM_PAINT消息來強制立即重畫,但不如使用Windows GDI爲我們提供的更方便和強大的函數:UpdateWindow和RedrawWindow。UpdateWindow會檢查窗口的Update
Region,當其不爲空時才發送WM_PAINT消息;RedrawWindow則給我們更多的控制:是否重畫非客戶區和背景,是否總是發送 WM_PAINT消息而不管Update Region是否爲空等。
27、如何讓工具條具有按下狀態
CToolBar m_wndFuncBar;
int m_curTool;
m_wndFuncBar.GetToolBarCtrl().CheckButton(m_curTool,FALSE);
CToolBarCtrl::CheckButton(int nID, BOOL bCheck = TRUE);