目錄
◆ 獲取啟動參數◆ 調整窗體大小◆ 關閉Dialog窗體◆ Dialog啟動時指定控件為焦點◆ Dialog中禁止ESC回車關閉窗體◆ 回車后焦點自動跳到下一個控件◆ 窗體中某個控件捕獲右鍵菜單◆ 獲取指定窗體hWnd下的所有子窗體◆ MainFrame啟動時居中◆ 非Dialog結構, 初始化時隱藏主窗口避免發生閃爍◆ 設置MainFrame標題欄, 不顯示文檔名稱◆ CListCtrl 的使用1. Item失去焦點時也處於選中狀態◆ CRichEditCtrl 的使用1. 設置字體格式◆ CComboBox 的使用1. CComboBox 為焦點時獲取其ID2. 輸入自動匹配功能的實現◆ CTreeCtrl 的使用1. 初始化時SetCheck無效2. 雙擊不展開或收縮節點的辦法。3. 實現CTreeCtrl父子節點的聯動選擇◆ CMFCStatusBar 的使用◆ CDockablePane 的使用1. CDockablePane 的布局2. CDockablePane 的顯示與隱藏3. 背景刷新問題.4. 如何自定義左右兩個並列CDockablePane的大小◆
◆ 獲取啟動參數
在 XXXApp 類的 InitInstance 函數中通過宏 __argc 與 __targv 即可獲取到程序的啟動參數. 代碼如下:
BOOL XXXApp::InitInstance()
{
for (int i = 0; i < __argc; i++)
{
AfxMessageBox(__targv[i]);
}
...
return FALSE;
}
◆ 調整窗體大小
使用 SetWindowPos 或 GetWindowRect 均可實現. 代碼如下:
// SetWindowPos 實現
CRect rc1(0, 0, 800, 600);
SetWindowPos(NULL, 0, 0, rc1.Width(), rc1.Height(), SWP_NOZORDER | SWP_NOMOVE);
// MoveWindow 實現
CRect rc2;
GetWindowRect(&rc2);
rc2.bottom += 100;
rc2.right += 100;
MoveWindow(&rc2);
◆ 關閉Dialog窗體
通過 PostMessage 函數發送消息實現. 代碼如下:
// close dialog
::PostMessage(pDlg->GetSafeHwnd(), WM_CLOSE, 0, 0);
// end dialog with idok
::PostMessage(pDlg->GetSafeHwnd(), WM_COMMAND, IDOK, 0);
◆ Dialog啟動時指定控件為焦點
在 OnInitDialog() 中調用 BringWindowToTop(). 代碼如下:
GetDlgItem(IDC_EDIT_XXX)->BringWindowToTop();
◆ Dialog中禁止ESC回車關閉窗體
通過在 PreTranslateMessage(…) 中屏蔽對 VK_ESCAPE, VK_RETURN 的處理即可. 代碼如下:
BOOL CDlgXXX::PreTranslateMessage(MSG* pMsg)
{
if (VK_RETURN == pMsg->wParam || VK_ESCAPE == pMsg->wParam)
{
return TRUE;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
◆ 回車后焦點自動跳到下一個控件
通過在 PreTranslateMessage(…) 中對 WM_KEYDOWN, VK_RETURN 的處理來實現. 代碼如下:
BOOL CDlgXXX::PreTranslateMessage(MSG* pMsg)
{
if (WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam)
{
int id = GetFocus()->GetDlgCtrlID();
if (id == IDC_EDIT_X1)
{
// 兩種方法都可以重置焦點
GotoDlgCtrl(GetDlgItem(IDC_EDIT_X2));
// GetDlgItem(IDC_EDIT_X2)->SetFocus();
}
else if (id == IDC_EDIT_X2)
{
OnBnClickedBtn();
}
return TRUE;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
◆ 窗體中某個控件捕獲右鍵菜單
處理消息 WM_CONTEXTMENU 來實現. 代碼如下:
void CDlgXXX::OnContextMenu(CWnd* pWnd, CPoint point)
{
if (pWnd->m_hWnd == 控件.m_hWnd)
{
CMenu m;
m.LoadMenu(IDR_MENU);
CMenu* pPopMenu = menu.GetSubMenu(0);
if (!pPopMenu)
{
return ;
}
pPopMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y);
}
}
◆ 獲取指定窗體hWnd下的所有子窗體
通過 GetWindow 可以實現, 代碼如下:
HWND hwndChild = ::GetWindow(hWnd, GW_CHILD); //列出所有控件
while (hwndChild)
{
hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
}
◆ MainFrame啟動時居中
在 OnCreate 中調用 CenterWindow();
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
CenterWindow()
...
}
◆ 非Dialog結構, 初始化時隱藏主窗口避免發生閃爍
- 在應用程序構造函數 CxxxApp::CxxxApp(){} 中添加代碼:
CXXXApp::CXXXApp()
{
EnableLoadWindowPlacement(FALSE);
...
}
- 應用程序初始化 CETSPApp::InitInstance() 中設置
BOOL CMFCApplication1App::InitInstance()
{
...
// The one and only window has been initialized, so show and update it
// m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->ShowWindow(SW_HIDE);
....
m_pMainWnd->UpdateWindow();
return TRUE;
}
- 重載 CMainFrame 的 ActivateFrame 函數.
void CMainFrame::ActivateFrame(int nCmdShow)
{
nCmdShow = SW_HIDE;
CFrameWndEx::ActivateFrame(nCmdShow);
}
- 要顯示 MainFrame 時調用
ShowWindow(SW_SHOW)
◆ 設置MainFrame標題欄, 不顯示文檔名稱
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWndEx::PreCreateWindow(cs) )
return FALSE;
cs.style &= ~(LONG)FWS_ADDTOTITLE;
return TRUE;
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
SetWindowText(_T("xxx"));
...
}
◆ CListCtrl 的使用
1. Item失去焦點時也處於選中狀態
設置 LVS_SHOWSELALWAYS. 代碼如下:
m_ctrlList.ModifyStyle(0, LVS_SHOWSELALWAYS | LVS_XXX(其它需要的選項));
◆ CRichEditCtrl 的使用
要使用 CRichEditCtrl, 需要在 App 的 InitInstance 中調用 AfxInitRichEdit2 . 代碼如下:
BOOL CXXXApp::InitInstance()
{
AfxInitRichEdit2();
...
return FALSE;
}
1. 設置字體格式
通過 GetDefaultCharFormat, SetDefaultCharFormat, SetWordCharFormat, SetSelectionCharFormat 這四個函數即可實現對 CRichEditCtrl 的字體設置(函數的功能與用法查詢MSDN即可).
說明:
1.同一個函數中 SetSelectionCharFormat 之前一定要有一次 SetWordCharFormat, 否則第一次 SetSelectionCharFormat 不生效.
2.設置顏色時,CHARFORMAT2 結構中的 dwMask 要具有 CFM_COLOR 標志,dwEffects 要清除 CFE_AUTOCOLOR 標志(設置為0即可),crTextColor 指定顏色.
◆ CComboBox 的使用
1. CComboBox 為焦點時獲取其ID
問題: 通過 GetFocus() 獲取 CComboBox 的焦點時, 當焦點在編輯框和按鈕上時沒有問題,一旦焦點在 CComboBox 框上, GetFocus() 的返回就有問題,用 UINT ID = GetFocus()-> GetDlgCtrlID(); 得到的返回值始終是 1001.
原因: MSDN 上的解釋 A combo box consists of a list box combined with either a static control or edit control. 所以上面問題中的第2種情況實際上獲取到的是 static control 的 ID.
解決:
UINT ID = GetFocus()->GetParent()->GetDlgCtrlID();
2. 輸入自動匹配功能的實現
◆ CTreeCtrl 的使用
1. 初始化時SetCheck無效
對於對話框中的TreeView控件,如果想在初始化(OnInitDialog)中SetCheck,必須:
m_tree.ModifyStyle( TVS_CHECKBOXES, 0 );
m_tree.ModifyStyle( 0, TVS_CHECKBOXES );
m_tree.SetCheck(hItem, TRUE);
即即使在對話框編輯器中為 TreeView 增加了 Check Boxes 屬性,也必須重新設一次 TVS_CHECKBOXES,SetCheck 才能起作用, 而對於非初始化中的SetCheck,則不受影響.
2. 雙擊不展開或收縮節點的辦法。
void CTreeView::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = TRUE;
}
3. 實現CTreeCtrl父子節點的聯動選擇
◆ CMFCStatusBar 的使用
… 這個不得不吐槽下, 非常難用.
CMFCStatusBar m_wndStatusBar;
// 注意, 這些ID必須在資源的字符表里設置值, 要不然展現出來的效果是狀態欄上對應的panel的背景色為黑色
static UNIT indicators[] =
{
IDS_STATUS_0,
IDS_STATUS_1,
IDS_STATUS_2,
IDS_STATUS_3,
IDS_STATUS_4,
};
// 創建
m_wndStatusBar.Create(this);
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UNIT));
// 設置樣式, 這里如果使用CStatusBar能實現相同效果的函數, 達不到預期效果
m_wndStatusBar.SetPanelStyle(0, SBPS_STRETCH);
m_wndStatusBar.SetPanelWidth(1, 80);
// 設置文字
m_wndStatusBar.SetPanelText
m_wndStatusBar.SetPanelTextColor
m_wndStatusBar.SetPanelBackgroundColor
// ... 最最重要的. 自定義的狀態欄字體為灰色的問題
// 按網上的添加映射 ON_COMMAND(IDS_STATUS_0, NULL) 這樣根本不能解決問題(第一個Panel始終為灰色, 后面的Panel可以解決)
// 方法如下:
// 通過更新UI的方式來解決
// IDS_STATUS_0 到 IDS_STATUS_4 不連續, 使用ON_UPDATE_COMMAND_UI分開實現即可
ON_UPDATE_COMMAND_UI_RANGE(IDS_STATUS_0, IDS_STATUS_4, &CMainFrame::OnUpdateStatusBar)
void CMainFrame::OnUpdateStatusBar(CCmdUI* pCmdUI)
{
pCmdUI->Enable(TRUE);
}
// 事件, 進度條, 圖標 ... 暫時未使用, 遇到時添加
◆ CDockablePane 的使用
1. CDockablePane 的布局
2. CDockablePane 的顯示與隱藏
m_wndXXXPane.ShowPane(TRUE,FALSE,TRUE); // 顯示
m_wndXXXPane.ShowPane(FALSE,FALSE,FALSE); // 隱藏
3. 背景刷新問題.
在框架的 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)中創建了幾個CDockablePane,里面是空的,運行,改變大小就會看到這些 CDockablePane 出現背景不會自動刷新.
重寫 OnPanit()
void CPropertyPane::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rc;
GetClientRect(rc);
CBrush brush;
brush.CreateSolidBrush(RGB(255, 255, 255));
dc.FillRect(&rc,&brush);
// Do not call CDockablePane::OnPaint() for painting messages
}
4. 如何自定義左右兩個並列CDockablePane的大小
注:
- 本方法僅是通過重置窗體的屬性來實現的, 如果您有好的方法請告知, 謝謝.
- 本方法同樣適合設置上下兩個並列CDockablePane的大小.
按系統默認的實現方式, 左右兩個並列 CDockablePane 的布局會如下:
|------------|------------|
| | |
| pane1 | pane2 |
| | |
|------------|------------|
為了實現下圖的樣式
|-------|-----------------|
| | |
| pane1 | pane2 |
| | |
|------ |-----------------|
請參考如下代碼:
BOOL CMainFrame::CreateDockingWindows()
{
BOOL bNameValid;
...
// Create pane1 window
CString strPane1;
bNameValid = strPane1.LoadString(ID_PANE_1);
ASSERT(bNameValid);
if (!m_wndPane1.Create(strPane1, this, CRect(0, 0, 100, 100), TRUE, ID_PANE_1, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_BOTTOM | CBRS_FLOAT_MULTI))
{
TRACE0("Failed to create pane1 window\n");
return FALSE; // failed to create
}
// Create pane2 window
CString strPane2;
bNameValid = strPane2.LoadString(ID_PANE_2);
ASSERT(bNameValid);
if (!m_wndPane2.Create(strPane2, this, CRect(0, 0, 200, 200), TRUE, ID_PANE_2, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_BOTTOM | CBRS_FLOAT_MULTI))
{
TRACE0("Failed to create pane2 window\n");
return FALSE; // failed to create
}
...
return TRUE;
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// TRUE : 允許加載上次的docking狀態
// FALSE: 不允許加載上次的docking狀態
EnableLoadDockState(FALSE);
...
// create docking windows
if (!CreateDockingWindows())
{
TRACE0("Failed to create docking windows\n");
return -1;
}
// 記住 Dock 前 m_wndPane1 的位置與大小
CRect r1;
m_wndPane1.GetWindowRect(&r1);
// DockPane
DockPane(&m_wndPane1);
DockPane(&m_wndPane2);
// 讓 m_wndPane1 在 m_wndPane2 的左邊, 函數中會改變兩個Pane的大小, 使其大小一致, 各占 CMainFrame 寬度的一半
m_wndPane1.DockToWindow(&m_wndPane2, CBRS_LEFT);
// 還原 m_wndPane1 的位置與大小
m_wndPane1.SetWindowPos(NULL, r1.left, r1.top, r1.Width(), r1.Height(), SWP_NOZORDER | SWP_NOMOVE);
...
return 0;
}
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CRect r1;
if (m_wndPane1.GetSafeHwnd())
{
// 獲取 Pane1 改變前的位置與大小
m_wndPane1.GetWindowRect(&r1);
}
// 會觸發所有 Pane 的 WM_SIZE 消息, 將所有 Pane 的大小重置
// 還會調用 AdjustDockingLayout 重新計算停靠到框架窗口的所有窗格的布局
CFrameWndEx::OnSize(nType, cx, cy);
if (m_wndPane1.GetSafeHwnd())
{
// 獲取 Pane2 的位置與大小, 使 Pane1 的 top, bottom 與 Pane2的一致
CRect r2;
m_wndPane2.GetWindowRect(&r2);
r1.top = r2.left;
r1.bottom = r2.bottom;
// 還原 m_wndPane1 的位置與大小
m_wndPane1.SetWindowPos(NULL, r1.left, r1.top, r1.Width(), r1.Height(), SWP_NOZORDER | SWP_NOMOVE);
// 重新計算停靠到框架窗口的所有窗格的布局
AdjustDockingLayout();
}
}
◆
本文持續更新中...