1."屬性頁的添加:
建立對話框的類,該類要從CpropertyPage繼承;然後在要添加該對話框為屬性頁的類(頭檔案)裡建立CpropertySheet類的一個對象m_tabsheet和新建立的對話框類的對象m_skatch;最後,在.cpp檔案裡的OnInitDialog()之類的函數裡實作如下代碼:
m_tabsheet.Create(this, WS_CHILD | WS_VISIBLE, 0);
"//使頁籤的按鈕在下面
"if(m_tabsheet.m_hWnd)
"m_tabsheet.ShowWindow(SW_MAXIMIZE);//顯示頁籤
//加入标簽,标簽名由各個子對話框的标題欄決定
"m_tabsheet.AddPage(&m_skatch);
"//用Create來建立一個屬性頁
"m_tabsheet.Create(this, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT);
"
RECT rect;
"m_tabsheet.GetWindowRect(&rect);
"int width = rect.right - rect.left;
"int height = rect.bottom - rect.top;
"
"//調整屬性頁的大小和位置
"m_tabsheet.SetWindowPos(NULL, 225, 225, width-82, height,SWP_NOACTIVATE);
屬性頁的添加完成。如果要添加多個屬性頁,則隻需要增加多個對象,如下:m_tabsheet.AddPage(&m_skatch1);
m_tabsheet.AddPage(&m_skatch2);
. . . . . .
2."List Control中标題欄(Column)的添加:
建立一個List Control,其ID為IDC_LIST,在其Styles屬性項下的View項裡選擇Report、Align項裡選擇Top、Sort項裡選擇None.
然後在該List所在對話框的類(頭檔案)裡建立ClistCtrl的一個對象m_list然後在.cpp檔案的OnInitDialog()之類的函數裡實作如下代碼:
CString strname[3];
strname[0]="Screen Name";
strname[1]="Form ID";
strname[2]="Category Path";
for(int i=0;i<3;i++)
{
m_List.InsertColumn(i,strname[i],LVCFMT_LEFT,130);
}
在這之前也要将List Control的ID與ClistCtrl的對象m_list在DoDataExchange(CDataExchange* pDX)函數裡綁定,如下:
DDX_Control(pDX, IDC_LIST, m_List);
3."ToolBar和StatusBar中控件的添加:
方法⑴.隻能在ToolBar裡建立控件:首先,在ToolBar中建立一個Button,其ID為ID_TOOL_COMBO(我們要将建立的控件放在該Button的位置上).
其次,新建立一個類CMainToolBar,要從CToolBar繼承(建立過程大概如下:選擇工程/增加到工程/新的類;也可以選擇工程的根,然後點選右鍵,選擇新的類;或者CTL+W,選擇增加類/新的類 --- 然後在class type裡選擇Generic Class,在Name欄裡輸入新類的名字,Base class裡輸入CToolBar),建立成功後在該類裡建立要增加的控件的對象,如:
CComboBox""m_wndMyCombo;
CStatic""m_wndCategory, m_wndCategoryPath;
CButton""m_wndOpenButton;
Cedit"""m_wndEdit;
然後在構造函數裡初始化如:
m_wndMyCombo.m_hWnd = NULL;
m_wndCategory.m_hWnd = NULL;
m_wndCategoryPath.m_hWnd = NULL;
m_wndOpenButton.m_hWnd = NULL;
m_wndEdit.m_hWnd = NULL;
接着在CMainframe的頭檔案裡建立CMainToolBar的一個對象m_wndToolBar,最後在.cpp檔案的OnCreate函數的最後實作如下:
"int index = 0;
"CRect rect; // 可定義在頭檔案當中
"// ComboBox
"{
""//找到指定的工具項
""while(m_wndToolBar.GetItemID(index)!=ID_TOOL_COMBO)
"""index++;
""//設定指定工具項的寬度并擷取新的區域 120是寬度
""m_wndToolBar.SetButtonInfo(index, ID_TOOL_COMBO, TBBS_SEPARATOR, 120);
""m_wndToolBar.GetItemRect(index, &rect);
""
""//設定位置
""rect.top+=1;
""rect.bottom += 200;
""
""// 建立并顯示控件
""if(!m_wndToolBar.m_wndMyCombo.Create(WS_CHILD|WS_VISIBLE| CBS_AUTOHSCROLL|
"""CBS_DROPDOWNLIST | CBS_HASSTRINGS , rect, &m_wndToolBar, ID_TOOL_COMBO))
""{
"""TRACE0("Failed to create combo-box/n");
"""return FALSE;
""}
""m_wndToolBar.m_wndMyCombo.ShowWindow(SW_SHOW);
""
""//填充内容"
""m_wndToolBar.m_wndMyCombo.AddString("25%");
""m_wndToolBar.m_wndMyCombo.AddString("50%");
""m_wndToolBar.m_wndMyCombo.AddString("75%");
"
""//選擇預設項
""m_wndToolBar.m_wndMyCombo.SetCurSel(0);
""
""//擷取到内容并MSGBOX顯示出來
""CString strContent;
""m_wndToolBar.m_wndMyCombo.GetWindowText(strContent);
""index = 0;
"}
其他控件都類似建立(隻需要注意一下各自的Create函數的參數即可)。
方法⑵.這種方法建立不太容易控制:直接在CMainframe的頭檔案中建立要增加的控件的對象,如CButton"的對象m_wndAboutButton,然後建立CToolBar或者CstatusBar的對象,如:CstatusBar的對象_wndStatusBar;再增加幾個函數如下:
Protected:
virtual void RecalcLayout(BOOL bNotify = TRUE);
"afx_msg void CMainFrame::OnViewStatusBar();
接着在.cpp檔案中将StatusBar的ID和OnViewStatusBar 函數綁定在一起,如下所示:BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
" // {{AFX_MSG_MAP(CMainFrame)
" ON_COMMAND(ID_VIEW_STATUS_BAR, OnViewStatusBar)
" ON_WM_CREATE()
" // }}AFX_MSG_MAP
END_MESSAGE_MAP()
然後Create函數的最後(傳回值之前)實作如下代碼:
CRect rc;
"VERIFY(m_wndAboutButton.Create(_T("MyAbout"),
"" WS_VISIBLE,rc,this,ID_APP_ABOUT));
"// TODO: Remove this if you don't want tool tips or a resizeable toolbar
"m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
"CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
再在RecalcLayout函數裡實作:
CRect rc;
if (m_wndStatusBar.m_hWnd)
{
""m_wndStatusBar.GetWindowRect(&rc);
""ScreenToClient(&rc);
""rc.right -= 50;
""m_wndStatusBar.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);
""rc.left = rc.right;
""rc.right += 50;
""m_wndAboutButton.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);
"}
最後在OnViewStatusBar()裡實作:
BOOL bShow = m_wndStatusBar.GetStyle() & WS_VISIBLE;
"m_wndAboutButton.SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
(bShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
ToolBar中的建立與此相同,隻需更改一下句柄即可。
4."通過Control建立的控件,對其屬性的動态控制:
在對話框類的頭檔案裡建立所要改變屬性的控件的對象,如要改變一個Button(其ID為IDC_MyButton)的屬性,則需建立Cbutton的對象m_button。然後在.cpp中的DoDataExchange函數裡将Button的ID和建立的對象綁定在一起:
//{{AFX_DATA_MAP(CPrintDlg)
""// NOTE: the ClassWizard will add DDX and DDV calls here
"DDX_Control(pDX, IDC_MyButton, m_button);
"//}}AFX_DATA_MAP
然後可以在該函數的最後進行初始化:
"m_button.EnableWindow(FALSE);
到這裡已經實作了改變屬性。如果要動态改變其屬性,可如下實作(通過兩個Button的點選改變起屬性):
// RadioAll Button的點選響應函數
void CPrintDlg::OnRadioAll()
{
""// TODO: Add your control notification handler code here
""m_button.EnableWindow(TRUE);
}
// RadioSelect Button的點選響應函數
void CPrintDlg::OnRadioSelect()
{
""// TODO: Add your control notification handler code here
""m_button.EnableWindow(FALSE);
}
也可以通過一個Check Button的點選來改變,在其點選響應函數裡實作:
m_button.EnableWindow(!m_button.IsWindowEnabled());
其餘控件屬性的改變都如此。
5."視窗的分割與停靠:
一、建立一個類CMySplitter,基類為CSplitterWnd
二、重載該類的OnMouseMove函數:
void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{
"// 限制切分條的運動範圍。
"if(point.x<228||point.x>600)
"{
""CWnd::OnMouseMove(nFlags, point);
"}
"else
"{
""CSplitterWnd::OnMouseMove(nFlags, point);
"}
}
三、 然後就可以跟一般的視窗分割那樣去做了,if(point.x<228||point.x>600)這裡的範圍可以随你去設定了 ^_^,夠簡單吧。
四、切分視窗
在MaiFram.h建立切分條對象:
protected:
CMySplitter m_wndSplitter; //切分視窗對象
//在MaiFram.cpp中實作視窗切分:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT ,CCreateContext* pContext)
{
"// 建立拆分器視窗
if (!m_wndSplitter.CreateStatic(this, 1, 2))
""return FALSE;
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftView),CSize(228,100), pContext) ||!m_wndSplitter.CreateView(0,1, RUNTIME_CLASS(CDataEditView), CSize(100, 100), pContext))
"{
""m_wndSplitter.DestroyWindow();
""return FALSE;
"}
"return TRUE;
}
6. ①怎樣在程式開始的時候讓它最大化?
②vc++做出來的exe檔案在窗體的右上方是沒有最大化和最小化按鈕的,怎樣實作這一功能?
③如何在顯示視窗時,使最大化按鈕變灰?
①在App類裡的C…App::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);
②在CreateWidnow時用WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX 風格.
③ 第一種方法:
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);
這個函數也可以是最大化按鈕失效!
并且可以在程式中動态的改變視窗的風格
7. 更改屬性頁标題
void CProSheet::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行有注釋符的代碼前的注釋符去掉
}
8. 建立動态菜單
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();
}
9.關于列印
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. 下面是從MSDN中摘出來的一段,是用來改變消息路由的。用了這段代碼之後,CView中的消息(菜單,控件,子視窗)将先被CMyShape類來處理。不知道你要的是不是這樣的效果。
// This example illustrates extending the framework's standard command
// route from the view to objects managed by the view. This example
// is from an object-oriented drawing application, similar to the
// DRAWCLI sample application, which draws and edits "shapes".
BOOL CMyView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// Extend the framework's command route from the view to
// the application-specific CMyShape that is currently selected
// in the view. m_pActiveShape is NULL if no shape object
// is currently selected in the view.
if ((m_pActiveShape != NULL)
&& m_pActiveShape->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// If the object(s) in the extended command route don't handle
// the command, then let the base class OnCmdMsg handle it.
return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
// The command handler for ID_SHAPE_COLOR (menu command to change
// the color of the currently selected shape) was added to
// the message map of CMyShape (note, not CMyView) using ClassWizard.
// The menu item will be automatically enabled or disabled, depending
// on whether a CMyShape is currently selected in the view, that is,
// depending on whether CMyView::m_pActiveView is NULL. It is not
// necessary to implement an ON_UPDATE_COMMAND_UI handler to enable
// or disable the menu item.
BEGIN_MESSAGE_MAP(CMyShape, CCmdTarget)
//{{AFX_MSG_MAP(CMyShape)
ON_COMMAND(ID_SHAPE_COLOR, OnShapeColor)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
如果你隻是想調用OnFilePrint( )函數,可以試一試下面的代碼,就和調用其它類中的函數一樣。
CMDIFrameWnd *pFrame =
(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
// Get the active MDI child window.
CMDIChildWnd *pChild =
(CMDIChildWnd *) pFrame->GetActiveFrame();
// or CMDIChildWnd *pChild = pFrame->MDIGetActive();
// Get the active view attached to the active MDI child
// window.
CMyView *pView = (CMyView *) pChild->GetActiveView();
pView->OnFilePrint( );
4.
void CMyReportView::OnFileOpen()
{
char Filter[] = "Crystal Report files(*.rpt)|*.rpt|All files(*.*)|*.*||";
CRect rect;
CFileDialog OpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(OpenDlg.DoModal()!=IDOK) ///顯示檔案對話框
return;
CString m_fName=OpenDlg.GetPathName(); ///取得檔案名
if(m_CrystalReport)
m_CrystalReport.DestroyWindow();
GetClientRect(rect);
///建立控件///
if (!m_CrystalReport.Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))
{
AfxMessageBox("控件建立失敗!");
return ;
}
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));///設定父視窗
m_CrystalReport.SetWindowBorderStyle(0); ///設定為沒有邊框
m_CrystalReport.SetWindowLeft(0); ///左空間
m_CrystalReport.SetWindowTop(0); ///頂部空間
m_CrystalReport.SetWindowControls(FALSE); ///不顯示工具條
m_CrystalReport.SetReportFileName(m_fName); ///設定報表檔案
m_CrystalReport.SetWindowWidth(rect.Width()); ///設定視窗寬度
m_CrystalReport.SetWindowHeight(rect.Height()); ///設定視窗高度
m_CrystalReport.SetFormulas(0, "Company=/"VC知識庫/""); ///将報表中的Company變量的值設定為VC知識庫
m_CrystalReport.SetDestination(0); ///設定輸出對象是螢幕
m_CrystalReport.PrintReport(); ///顯示報表
}
void CMyReportView::OnFilePrint()
{
if(m_CrystalReport && m_CrystalReport.GetReportFileName() != "")
{
m_CrystalReport.SetDestination(1); ///設定輸出對象是列印機
m_CrystalReport.PrintReport(); ///列印
}
10. Scroll
建立一個基于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);
}
11. 修改主視窗風格
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);
}
12. 控制滾動條
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);
}
13. 屬性頁處理通知消息
CPropertyPageImpl有一個消息映射處理WM_NOTIFY。如果通知代碼是PSN_*的值,OnNotify()就會調用相應的通知處理函數。這使用了編譯階段虛函數機制,進而使得派生類可以很容易的重載這些處理函數。
由于WTL 3和WTL 7設計的改變,進而存在兩套不同的通知處理機制。在WTL 3中通知處理函數傳回的值與PSN_*消息的傳回值不同,例如,WTL 3是這樣處理PSN_WIZFINISH的:
case PSN_WIZFINISH:
lResult = !pT->OnWizardFinish();
break;
OnWizardFinish()期望傳回TRUE結束向導,FALSE阻止關閉向導。這個方法很簡陋,但是IE5的通用控件對PSN_WIZFINISH處理的傳回值添加了新解釋,他傳回需要獲得焦點的視窗的句柄。WTL 3的程式将不能使用這個特性,因為它對所有非0的傳回值都做相同的處理。
在WTL 7中,OnNotify() 沒有改變 PSN_* 消息的傳回值,處理函數傳回任何文檔中規定的合法數值和正确的行為。當然,為了向前相容,WTL 3 仍然使用目前預設的工作方式,要使用WTL 7的消息處理方式,你必須在中including atldlgs.h一行之前添加一行定義:
#define _WTL_NEW_PAGE_NOTIFY_HANDLERS
編寫新的代碼沒有理由不使用WTL 7的消息處理函數,是以這裡就不介紹WTL 3的消息處理方式。
CPropertyPageImpl 為所有消息提供了預設的通知消息處理函數,你可以重載與你的程式有關的消息處理函數完成特殊的操作。預設的消息處理函數和相應的行為如下:
int OnSetActive() - 允許頁面成為激活狀态
BOOL OnKillActive() - 允許頁面成為非激活狀态
int OnApply() - 傳回 PSNRET_NOERROR 表示應用操作成功完成
void OnReset() - 無相應的動作
BOOL OnQueryCancel() - 允許取消操作
int OnWizardBack() - 傳回到前一個頁面
int OnWizardNext() - 進行到下一個頁面
INT_PTR OnWizardFinish() - 允許向導結束
void OnHelp() - 無相應的動作
BOOL OnGetObject(LPNMOBJECTNOTIFY lpObjectNotify) - 無相應的動作
int OnTranslateAccelerator(LPMSG lpMsg) - 傳回 PSNRET_NOERROR 表示消息沒有被處理
HWND OnQueryInitialFocus(HWND hWndFocus) - 傳回 NULL 表示将按Tab Order順序的第一個控件設為焦點狀态
14.使工具條上的按鈕點選一次為按下,再點選才彈起
bCheck=m_RtfEditToolBar.GetToolBarCtrl().IsButtonChecked(ID_TB_BOLD);
m_RtfEditToolBar.GetToolBarCtrl().CheckButton(ID_TB_BOLD, !bCheck);
15. VC中基于 Windows 的精确定時
在工業生産控制系統中,有許多需要定時完成的操作,如定時顯示目前時間,定時重新整理螢幕上的進度條,上位 機定時向下位機發送指令和傳送資料等。特别是在對控制性能要求較高的實時控制系統和資料采集系統中,就更需要精确定時操作。
衆所周知,Windows 是基于消息機制的系統,任何事件的執行都是通過發送和接收消息來完成的。 這樣就帶來了一些問題,如一旦計算機的CPU被某個程序占用,或系統資源緊張時,發送到消息隊列 中的消息就暫時被挂起,得不到實時處理。是以,不能簡單地通過Windows消息引發一個對定時要求 嚴格的事件。另外,由于在Windows中已經封裝了計算機底層硬體的通路,是以,要想通過直接利用 通路硬體來完成精确定時,也比較困難。是以在實際應用時,應針對具體定時精度的要求,采取相适 應的定時方法。
VC中提供了很多關于時間操作的函數,利用它們控制程式能夠精确地完成定時和計時操作。本文詳細介紹了 VC中基于Windows的精确定時的七種方式.
方式一:VC中的WM_TIMER消息映射能進行簡單的時間控制。首先調用函數SetTimer()設定定時 間隔,如SetTimer(0,200,NULL)即為設定200ms的時間間隔。然後在應用程式中增加定時響應函數 OnTimer(),并在該函數中添加響應的處理語句,用來完成到達定時時間的操作。這種定時方法非常 簡單,可以實作一定的定時功能,但其定時功能如同Sleep()函數的延時功能一樣,精度非常低,最小 計時精度僅為30ms,CPU占用低,且定時器消息在多任務作業系統中的優先級很低,不能得到及時響 應,往往不能滿足實時控制環境下的應用。隻可以用來實作諸如位圖的動态顯示等對定時精度要求不高的情況。如示例工程中的Timer1。
方式二:VC中使用sleep()函數實作延時,它的機關是ms,如延時2秒,用sleep(2000)。精度非常 低,最小計時精度僅為30ms,用sleep函數的不利處在于延時期間不能處理其他的消息,如果時間太 長,就好象當機一樣,CPU占用率非常高,隻能用于要求不高的延時程式中。如示例工程中的Timer2。
方式三:利用COleDateTime類和COleDateTimeSpan類結合WINDOWS的消息處理過程來實作秒級延時。如示例工程中的Timer3和Timer3_1。以下是實作2秒的延時代碼:
COleDateTime start_time = COleDateTime::GetCurrentTime();
COleDateTimeSpan end_time= COleDateTime::GetCurrentTime()-start_time;
while(end_time.GetTotalSeconds()< 2) //實作延時2秒
{
MSG msg;
GetMessage(&msg,NULL,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
//以上四行是實作在延時或定時期間能處理其他的消息,
//雖然這樣可以降低CPU的占有率,
//但降低了延時或定時精度,實際應用中可以去掉。
end_time = COleDateTime::GetCurrentTime()-start_time;
}//這樣在延時的時候我們也能夠處理其他的消息。
方式四:在精度要求較高的情況下,VC中可以利用GetTickCount()函數,該函數的傳回值是 DWORD型,表示以ms為機關的計算機啟動後經曆的時間間隔。精度比WM_TIMER消息映射高,在較 短的定時中其計時誤差為15ms,在較長的定時中其計時誤差較低,如果定時時間太長,就好象當機一樣,CPU占用率非常高,隻能用于要求不高的延時程式中。如示例工程中的Timer4和Timer4_1。下列代碼可以實作50ms的精确定時:
DWORD dwStart = GetTickCount();
DWORD dwEnd = dwStart;
do
{
dwEnd = GetTickCount()-dwStart;
}while(dwEnd <50);
為使GetTickCount()函數在延時或定時期間能處理其他的消息,可以把代碼改為:
DWORD dwStart = GetTickCount();
DWORD dwEnd = dwStart;
do
{
MSG msg;
GetMessage(&msg,NULL,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
dwEnd = GetTickCount()-dwStart;
}while(dwEnd <50);
雖然這樣可以降低CPU的占有率,并在延時或定時期間也能處理其他的消息,但降低了延時或定時精度。
方式五:與GetTickCount()函數類似的多媒體定時器函數DWORD timeGetTime(void),該函數定時精 度為ms級,傳回從Windows啟動開始經過的毫秒數。微軟公司在其多媒體Windows中提供了精确定時器的底 層API持,利用多媒體定時器可以很精确地讀出系統的目前時間,并且能在非常精确的時間間隔内完成一 個事件、函數或過程的調用。不同之處在于調用DWORD timeGetTime(void) 函數之前必須将 Winmm.lib 和 Mmsystem.h 添加到工程中,否則在編譯時提示DWORD timeGetTime(void)函數未定義。由于使用該 函數是通過查詢的方式進行定時控制的,是以,應該建立定時循環來進行定時事件的控制。如示例工程中的Timer5和Timer5_1。
方式六:使用多媒體定時器timeSetEvent()函數,該函數定時精度為ms級。利用該函數可以實作周期性的函數調用。如示例工程中的Timer6和Timer6_1。函數的原型如下:
MMRESULT timeSetEvent( UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
WORD dwUser,
UINT fuEvent )
該函數設定一個定時回調事件,此事件可以是一個一次性事件或周期性事件。事件一旦被激活,便調用指定的回調函數, 成功後傳回事件的辨別符代碼,否則傳回NULL。函數的參數說明如下:
uDelay:以毫秒指定事件的周期。
Uresolution:以毫秒指定延時的精度,數值越小定時器事件分辨率越高。預設值為1ms。
LpTimeProc:指向一個回調函數。
DwUser:存放使用者提供的回調資料。
FuEvent:指定定時器事件類型:
TIME_ONESHOT:uDelay毫秒後隻産生一次事件
TIME_PERIODIC :每隔uDelay毫秒周期性地産生事件。
具體應用時,可以通過調用timeSetEvent()函數,将需要周期性執行的任務定義在LpTimeProc回調函數 中(如:定時采樣、控制等),進而完成所需處理的事件。需要注意的是,任務處理的時間不能大于周期間隔時間。另外,在定時器使用完畢後, 應及時調用timeKillEvent()将之釋放。
方式七:對于精确度要求更高的定時操作,則應該使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函數。這兩個函數是VC提供的僅供Windows 95及其後續版本使用的精确時間函數,并要求計算機從硬體上支援精确定時器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。
QueryPerformanceFrequency()函數和QueryPerformanceCounter()函數的原型如下:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
資料類型ARGE_INTEGER既可以是一個8位元組長的整型數,也可以是兩個4位元組長的整型數的聯合結構, 其具體用法根據編譯器是否支援64位而定。該類型的定義如下:
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart ;// 4位元組整型數
LONG HighPart;// 4位元組整型數
};
LONGLONG QuadPart ;// 8位元組整型數
}LARGE_INTEGER ;
在進行定時之前,先調用QueryPerformanceFrequency()函數獲得機器内部定時器的時鐘頻率, 然後在需要嚴格定時的事件發生之前和發生之後分别調用QueryPerformanceCounter()函數,利用兩次獲得的計數之差及時鐘頻率,計算出事件經 曆的精确時間。下列代碼實作1ms的精确定時:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 獲得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//獲得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 獲得對應的時間值,機關為秒
}while(dfTim<0.001);
其定時誤差不超過1微秒,精度與CPU等機器配置有關。 下面的程式用來測試函數Sleep(100)的精确持續時間:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 獲得初始值
Sleep(100);
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//獲得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 獲得對應的時間值,機關為秒
由于Sleep()函數自身的誤差,上述程式每次執行的結果都會有微小誤差。下列代碼實作1微秒的精确定時:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 獲得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//獲得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 獲得對應的時間值,機關為秒
}while(dfTim<0.000001);
其定時誤差一般不超過0.5微秒,精度與CPU等機器配置有關。
16. 為對話框中的控件增加提示的簡單方法
我學VC從VC知識庫中得到不少好處,相來都是一些熱心朋友們的幫助,在此表示感謝!本工程可分五步:
1、建一個基于對話框的程式TipTest,在CTipTestDlg中增加成員變量:CToolTipCtrl m_tip[2],CWnd *m_pSub[2];
2、在CTipTestDlg::OnInitDialog()函數中增加如下代碼:
pSub[0] = GetDlgItem(IDC_RADIO1); //得到單選按鈕的指針
pSub[1] = GetDlgItem(IDC_BUTTON1);
"m_tip[0].Create(pSub[0],TTS_ALWAYSTIP); //建立CToolTipCtrl
"m_tip[0].AddTool(pSub[0]); //将CToolTipCtrl與相應的控件對應起來
"m_tip[1].Create(pSub[1],TTS_ALWAYSTIP);
"m_tip[1].AddTool(pSub[1]);
"m_tip[0].SetTipTextColor(RGB(0,0,255)); //設定文字的顔色
m_tip[0].SetDelayTime(150); //設定提示文字在控件上停留的時間
3、重載CTipTestDlg::PreTranslateMessage(MSG* pMsg)函數,增加如下代碼:
if(m_tip[0].m_hWnd!=NULL)
m_tip[0].RelayEvent(pMsg); //如果m_tip[0]句柄不為空,就從主視窗中捕獲消息,如WM_MOUSEMOVE,WM_LBUTTONDOWN等消息
if(m_tip[1].m_hWnd!=NULL)
m_tip[1].RelayEvent(pMsg);
4、捕獲主視窗的WM_MOUSEMOVE消息,在CTipTestDlg::OnMouseMove(UINT nFlags, CPoint point)函數中增加如下代碼:
m_tip[0].UpdateTipText("VC知識庫歡迎你!",pSub[0]); //滑鼠在相應的控件上移動時顯示提示文字
"m_tip[1].UpdateTipText("http://vckbase.com",pSub[1]);
17.删除檔案夾
// 删除檔案夾及其所有内容
void CBaseDoc::RemoveFolder(const CString &strPathName)
{
CString path = strPathName;
if (path.Right(1) != _T("//"))
path += _T("//");
path += _T("*.*");
CFileFind ff;
BOOL res = ff.FindFile(path);
while (res)
{
res = ff.FindNextFile();
// 是檔案時直接删除
if (!ff.IsDots() && !ff.IsDirectory())
DeleteFile(ff.GetFilePath());
else if (ff.IsDots())
continue;
else if (ff.IsDirectory())
{
path = ff.GetFilePath();
// 是目錄時繼續遞歸,删除該目錄下的檔案
RemoveFolder(path);
::RemoveDirectory(path);
}
}
}
18.消息映射
有對話框A,B
從A中發消息給B然後B處理。
準備工作,先定義消息,如下
#define WM_B_NOTIFY WM_USER + 300
首先,必須将B的對話框句柄傳送給A,暫時叫m_hWndB;
在A的發送消息的地方這樣寫:
::SendMessage( m_hWndB,WM_B_NOTIFY,TRUE,NULL );
這樣A中的處理就完了,下面說B 中的
首先定義消息處理函數,如下
void B::ModiNotify( WPARAM wParam, LPARAM lParam )
{
MessageBox("小樣,我就不信,搞不定你!");
}
然後加消息隐射,如下:
BEGIN_MESSAGE_MAP(CB, CDialog)
//{{AFX_MSG_MAP(CRPServerDlg)
ON_MESSAGE( WM_B_NOTIFY,ModiNotify )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
19.給從CWnd派生的視窗添加滾動條
ModifyStyle(0,WS_VSCROLL);
20. SetWindowPos
函數功能:該函數改變一個子視窗,彈出式視窗式頂層視窗的尺寸,位置和Z序。子視窗,彈出式視窗,及頂層視窗根據它們在螢幕上出現的順序排序、頂層視窗設定的級别最高,并且被設定為Z序的第一個視窗。
函數原型:BOOL SetWindowPos(HWN hWnd,HWND hWndlnsertAfter,int X,int Y,int cx,int cy,UNIT.Flags);
參數:
hWnd:視窗句柄。
hWndlnsertAfter:在z序中的位于被置位的視窗前的視窗句柄。該參數必須為一個視窗句柄,或下列值之一:
HWND_BOTTOM:将視窗置于Z序的底部。如果參數hWnd辨別了一個頂層視窗,則視窗失去頂級位置,并且被置在其他視窗的底部。
HWND_DOTTOPMOST:将視窗置于所有非頂層視窗之上(即在所有頂層視窗之後)。如果視窗己經是非頂層視窗則該标志不起作用。
HWND_TOP:将視窗置于Z序的頂部。
HWND_TOPMOST:将視窗置于所有非頂層視窗之上。即使視窗未被激活視窗也将保持頂級位置。
查g看該參數的使用方法,請看說明部分。
x:以客戶坐标指定視窗新位置的左邊界。
Y:以客戶坐标指定視窗新位置的頂邊界。
cx:以像素指定視窗的新的寬度。
cy:以像素指定視窗的新的高度。
uFlags:視窗尺寸和定位的标志。該參數可以是下列值的組合:
SWP_ASNCWINDOWPOS:如果調用程序不擁有視窗,系統會向擁有視窗的線程發出需求。這就防止調用線程在其他線程處理需求的時候發生死鎖。
SWP_DEFERERASE:防止産生WM_SYNCPAINT消息。
SWP_DRAWFRAME:在視窗周圍畫一個邊框(定義在視窗類描述中)。
SWP_FRAMECHANGED:給視窗發送WM_NCCALCSIZE消息,即使視窗尺寸沒有改變也會發送該消息。如果未指定這個标志,隻有在改變了視窗尺寸時才發送WM_NCCALCSIZE。
SWP_HIDEWINDOW;隐藏視窗。
SWP_NOACTIVATE:不激活視窗。如果未設定标志,則視窗被激活,并被設定到其他最進階視窗或非最進階組的頂部(根據參數hWndlnsertAfter設定)。
SWP_NOCOPYBITS:清除客戶區的所有内容。如果未設定該标志,客戶區的有效内容被儲存并且在視窗尺寸更新和重定位後拷貝回客戶區。
SWP_NOMOVE:維持目前位置(忽略X和Y參數)。
SWP_NOOWNERZORDER:不改變z序中的所有者視窗的位置。
SWP_NOREDRAW:不重畫改變的内容。如果設定了這個标志,則不發生任何重畫動作。适用于客戶區和非客戶區(包括标題欄和滾動條)和任何由于窗回移動而露出的父視窗的所有部分。如果設定了這個标志,應用程式必須明确地使視窗無效并區重畫視窗的任何部分和父視窗需要重畫的部分。
SWP_NOREPOSITION;與SWP_NOOWNERZORDER标志相同。
SWP_NOSENDCHANGING:防止視窗接收WM_WINDOWPOSCHANGING消息。
SWP_NOSIZE:維持目前尺寸(忽略cx和Cy參數)。
SWP_NOZORDER:維持目前Z序(忽略hWndlnsertAfter參數)。
SWP_SHOWWINDOW:顯示視窗。
傳回值:如果函數成功,傳回值為非零;如果函數失敗,傳回值為零。若想獲得更多錯誤消息,請調用GetLastError函數。
備注:如果設定了SWP_SHOWWINDOW和SWP_HIDEWINDOW标志,則視窗不能被移動和改變大小。如果使用SetWindowLoog改變了視窗的某些資料,則必須調用函數SetWindowPos來作真正的改變。使用下列的組合标志:SWP_NOMOVEISWP_NOSIZEISWP_FRAMECHANGED。
有兩種方法将視窗設為最頂層視窗:一種是将參數hWndlnsertAfter設定為HWND_TOPMOST并確定沒有設定SWP_NOZORDER标志;另一種是設定視窗在Z序中的位置以使其在其他存在的視窗之上。當一個視窗被置為最頂層視窗時,屬于它的所有視窗均為最頂層視窗,而它的所有者的z序并不改變。
如果HWND_TOPMOST和HWND_NOTOPMOST标志均未指定,即應用程式要求視窗在激活的同時改變其在Z序中的位置時,在參數hWndinsertAfter中指定的值隻有在下列條件中才使用:
在hWndlnsertAfter參數中沒有設定HWND_NOTOPMOST和HWND_TOPMOST标志。
由hWnd參數辨別的視窗不是激活視窗。
如果未将一個非激活視窗設定到z序的頂端,應用程式不能激活該視窗。應用程式可以無任何限制地改變被激活視窗在Z序中的位置,或激活一個視窗并将其移到最進階視窗的頂部或非最進階視窗的頂部。
如果一個頂層視窗被重定位到z序的底部(HWND_BOTTOM)或在任何非最高序的視窗之後,該視窗就不再是最頂層視窗。當一個最頂層視窗被置為非最頂級,則它的所有者視窗和所屬者視窗均為非最頂層視窗。
一個非最頂端視窗可以擁有一個最頂端視窗,但反之則不可以。任何屬于頂層視窗的視窗(例如一個對話框)本身就被置為頂層視窗,以確定所有被屬視窗都在它們的所有者之上。
如果應用程式不在前台,但應該位于前台,就應調用SetForegroundWindow函數來設定。
Windows CE:如果這是一個可見的頂層視窗,并且未指定SWP_NOACTIVATE标志,則這個函數将激活視窗、如果這是目前的激活視窗,并且指定了SWP_NOACTIVATE或SWP_HIDEWINDOW标志,則激活另外一個可見的頂層視窗。
當在這個函數中的nFlags參數裡指定了SWP_FRAMECHANGED标志時,WindowsCE重畫視窗的整個非客戶區,這可能會改變客戶區的大小。這也是重新計算客戶區的唯一途徑,也是通過調用SetwindowLong函數改變視窗風格後通常使用的方法。
SetWindowPos将使WM_WINDOWPOSCHANGED消息向視窗發送,在這個消息中傳遞的标志與傳遞給函數的相同。這個函數不傳遞其他消息。
Windows CE 1.0不支援在hWndlnsertAber參數中的HWND_TOPMOST和HWND_NOTOPMOST常量。
Windows CE1.0不支援在fuFags參數中的SWP_DRAWFRAME和SWP_NOCOPYBITS标志。
速查:Windows NT:3.1以上版本;Windows:95以上版本;Windows CE:1.0以上版本;頭檔案:winuser.h庫檔案:eser32lib
21. 介紹函數過程中一種任意鍵退出同時能處理消息的實作方法
1. 設定定時器,用于使::GetMessage(...)函數總能快速取到消息.
2. 在函數進行中加入:
函數每執行完一步後執行下面的代碼.
if (::GetMessage(&msg, 0, 0, 0))
{
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) return ;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else ::PostQuitMessage(0);
22. 如何隐藏工具欄
添加如下兩個函數
隐藏:
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);
}
23. 如何動态擷取工具條指針并給工具條加标題?
[問題提出]
工具條也是視窗,是視窗就有标題,如何給工具條加标題?
[程式實作]
不想動态改變工具條的标題就在CMainFrame::OnCreate()中:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
m_wndToolBar.SetWindowText(_T("Standdard"));
return 0;
}
若想動态改變工具條的标題,如下:
聲明一個菜單,并響應事件,如響應:OnMyToolBar()函數
void CMainFrame::OnMyToolBar()
{
// TODO: Add your command handler code here
CToolBar *pToolBar = (CToolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);
pToolBar->SetWindowText (_T("Standdard"));
}
不要在TooBar懸浮時做OnMyToolBar()會出錯的.
順便提一下如何獲得狀态條的指針:
CStatusBar * pStatusBar =(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
24. 在狀态條中顯示滑鼠的裝置坐标與邏輯坐标
顯示器的裝置坐标系的原點在客戶區的左上角,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);
}
25. 如何用VC++ 動态修改應用程式菜單
[問題提出]
本文将介紹一些使用CMenu的方法,如查找指定菜單,在指定選項前添加菜單項.....
[解決方法]
使用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);
26. VC++中的3D按鈕的程式設計
運作AppWizard生成一個基于對話框的test工程,在對話框中加入一個CButton控件。在CButton控件的General屬性頁将控件的ID改為IDC_3DTEXTBTN,Caption改為“誰與争瘋”,在控件Styles屬性頁選中OwnerDraw,其餘設定保持預設。
用classwizard建立一個新類:C3dTextButton,基類為CButton。為C3dTextButton類添加一個protected的函數void Draw(CDC* pDC, const CRect& rect, UINT state)。如下所示編寫代碼:
void C3dTextButton::Draw(CDC *pDC, const CRect &rect, UINT state)
{
CString text; GetWindowText(text);
int l=text.GetLength();
CRect rectClient=rect;
//獲得控件的字型
CFont* pFont=GetFont();
//确定所選字型有效高度和寬度
LOGFONT logfont;
pFont->GetObject(sizeof(LOGFONT),&logfont);
if(logfont.lfHeight==0)logfont.lfHeight=20;
logfont.lfWidth=0;//寬度設為0,寬度值由高度确定
logfont.lfWeight=1000;
logfont.lfEscapement=logfont.lfOrientation=0;
CFont tryfont; VERIFY(tryfont.CreateFontIndirect(&logfont));
CFont* pFontOld=pDC->SelectObject(&tryfont);
//根據控件大小,調整字型的高度,使文本與控件協調
CSize textSizeClient=pDC->GetTextExtent(text,l);
if(rectClient.Width()*textSizeClient.cy>rectClient.Height()*textSizeClient.cx)
{
logfont.lfHeight=::MulDiv(logfont.lfHeight,rectClient.Height(),textSizeClient.cy);
}
else{
logfont.lfHeight = ::MulDiv(logfont.lfHeight,rectClient.Width(),textSizeClient.cx);
}
//建立并選擇協調後的字型
CFont font; font.CreateFontIndirect(&logfont);
pDC->SelectObject(&font);
textSizeClient=pDC->GetTextExtent(text,l);
//确定文本與控件邊界的距離minx,miny
int minx=rectClient.left+(rectClient.Width()-textSizeClient.cx)/2;
int miny=rectClient.top+(rectClient.Height()-textSizeClient.cy)/2;
int oldBkMode=pDC->SetBkMode(TRANSPARENT);
COLORREF textcol=::GetSysColor(COLOR_BTNTEXT);
COLORREF oldTextColor=pDC->SetTextColor(textcol);
int cx = minx;
int cy = miny;
int s=(state&ODS_SELECTED)?-1:+1;
cx+= 3; cy+= 3;
//實作3D效果
pDC->SetTextColor(::GetSysColor(COLOR_3DDKSHADOW));
pDC->TextOut(cx-s*2,cy+s*2,text);
pDC->TextOut(cx+s*2,cy-s*2,text);
pDC->TextOut(cx+s*2,cy+s*2,text);
pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
pDC->TextOut(cx+s*1,cy-s*2,text);
pDC->TextOut(cx-s*2,cy+s*1,text);
pDC->TextOut(cx-s*2,cy-s*2,text);
pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
pDC->TextOut(cx-s*1,cy+s*1,text);
pDC->TextOut(cx+s*1,cy-s*1,text);
pDC->TextOut(cx+s*1,cy+s*1,text);
pDC->SetTextColor(::GetSysColor(COLOR_3DLIGHT));
pDC->TextOut(cx,cy-s*1,text);
pDC->TextOut(cx-s*1,cy,text);
pDC->TextOut(cx-s*1,cy-s*1,text);
pDC->SetTextColor(textcol);
//輸出标題
pDC->TextOut(cx,cy,text);
//恢複裝置描述表
pDC->SetTextColor(oldTextColor);
pDC->SetBkMode(oldBkMode);
pDC->SelectObject(pFontOld);
}
用classwizard重載C3dTextButton類的DrawItem函數。編寫代碼如下所示:
void C3dTextButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
ASSERT_VALID(pDC);
CRect rectClient=lpDrawItemStruct->rcItem;
Draw(pDC,rectClient,lpDrawItemStruct->itemState);
}
用classwizard為IDC_3DTEXTBTN建立一個C3dTextButton控件變量m_3dTextButton1。
把“3dTextButton.h”加入testDlg頭檔案。編譯并測試應用程式。
27. 如何正确的得到ComBox的指針
CComboBox *mComb = (CComboBox*)GetDlgItem(IDC_DuanCB);
CComboBox *mComb = (CComboBox*)::GetDlgItem(m_hWnd,IDC_DuanCB);
28. 如何讓對話框中的CEdit控件類接收對話框的消息
// 如何讓對話框中的CEdit控件類接收對話框的消息
1、在對話框中增加一個ID 為IDC_EDIT1的CEdit1控件
2、通過ClassWizard 生成一個基于CEdit的新類CMyEdit,
CMyEdit m_wndEdit;
3、在對話框OnInitDialog()中,将m_wndEdit子類化,使其能夠接受對話框的消息。
m_wndEdit.SubclassDlgItem (IDC_EDIT1,this);
29.利用WM_CTLCOLOR消息實作編輯控制(Edit Control)的文本與背景色的改變
首先要明白:WM_CTLCOLOR是一個由控制(Control)發送給它父視窗的通知消息(Notification message)。
實作步驟:
生成一個标準的單文檔應用程式架構,假設應用程式的名稱為Color。我将利用它的About對話框做示範。在About dialog中添加兩個Edit control,設定其ID為IDC_EDIT1與IDC_EDIT2。
第一種方法(對應于IDC_EDIT1): 按照标準的Windows程式設計,由其父視窗的消息處理函數負責處理WM_CTLCOLOR消息。
1. 在CAboutDlg中添加一個資料成員:HBRUSH m_brMine;
2. 利用向導映射AboutDlg的WM_CTLCOLOR消息,産生函數:HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
pDC是AboutDlg的裝置上下文,pWnd是AboutDlg中發送該消息的control指針,nCtlColor市Control的類型編碼。對其進行如下修改:
HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if ((pWnd->GetDlgCtrlID() == IDC_EDIT1) && (nCtlColor == CTLCOLOR_EDIT))
{
COLORREF clr = RGB(255,0,0);
pDC->SetTextColor(clr); //設定紅色的文本
clr = RGB(0,0,0);
pDC->SetBkColor(clr); //設定黑色的背景
m_brMine = ::CreateSolidBrush(clr);
return m_brMine; //作為約定,傳回背景色對應的刷子句柄
}
else
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
}
第二種方法(對應于IDC_EDIT2):
利用MFC 4.0的新特性: Message reflection。
1.利用向導添加一個新的類:CColorEdit,基類為CEdit;
2.在CColorEdit中添加一個資料成員: HBRUSH m_bkBrush;
3.利用向導映射CColorEdit的"=WM_CTLCOLOR"消息,産生函數:
HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor);
對其進行如下修改:
HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
COLORREF clr = RGB(0,0,0);
pDC->SetTextColor(clr); //設定黑色的文本
clr = RGB(255,0,0);
pDC->SetBkColor(clr); //設定紅色的背景
m_bkBrush = ::CreateSolidBrush(clr);
return m_bkBrush; //作為約定,傳回背景色對應的刷子句柄
}
4.利用向導為IDC_EDIT2生成一個資料成員CColorEdit m_coloredit;
5.在定義CAboutDlg的color.cpp檔案中加入:#include "coloredit.h"
30. 如何防止密碼被非法擷取?
[問題提出]
這兩天大家比較專注在擷取Edit密碼框的密碼.在盜取時,我們如何防範呢?
[解決方法]
此方法針對于通過SendMessage向此視窗發送WM_GETTEXT或EM_GETLINE消息來取得密碼.跟我來.
[程式實作]
方法很簡單,用CWnd::DefWindowProc函數攔截得到的消息(向Edit發的).
建立名為My的對話框工程.建立一個Edit控件ID=IDC_EDIT1.建一個新類名為CMyProtectEdit,派生于CEdit.
在MyDlg.cpp中聲明全局變量:BOOL g_bIdentity;
BOOL g_bIdentity;
在MyProtecEdit.cpp中:
extern BOOL g_bIdentity;
響應CMyProtectEdit的DefWindowProc函數:
LRESULT CMyProtectEdit::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
// 對Edit的内容擷取必須通過以下兩個消息之一,不對其采用預設的處理:
if(( message == WM_GETTEXT) || ( message == EM_GETLINE))
{ //檢查是否為合法
if(!g_bIdentity)
{ //非法擷取,顯示非法資訊
AfxMessageBox(_T("不能讓你看我的密碼,:( !"));
return 0;
)
g_bIdentity = FALSE;//合法擷取
}
return CEdit::DefWindowProc(message, wParam, lParam);
}
然後在MyDlg.cpp中
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGetPasswordDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
if( pDX->m_bSaveAndValidate)
{
g_bIdentity = TRUE;
}
//}}AFX_DATA_MAP
}
即可.找個程式(盜取)的試試.
31. 如何在編輯控件中以追加的方式添入字元?
[問題提出]
SetDlgItemText可以向Edit控件中輸入字元,發送更新的消息也可是Edit控件顯示與其關聯的變量的值,但若是向已有的Edit字元後追加字元,該如何做?
[程式實作]
建立名為My的對話框工程,添加一個Edit和一個Button控件.Edit的ID=IDC_EDIT1,Button的ID=IDC_BUTTON1.建立和IDC_BUTTON1的響應函數:OnButton1()
void CMyDlg::OnButton1()
{
CString pText="你好";
CEdit *m_Edit=(CEdit *)GetDlgItem(IDC_EDIT1);
int nLen=m_Edit->GetWindowTextLength();
m_Edit->SetFocus();
m_Edit->SetSel(nLen, nLen);
m_Edit->ReplaceSel(pText);
}
在Edit控件中輸入字元,想追加時按IDC_BUTTON1按鈕.看看效果.
32.屬性頁标題改名
我用CPropertySheet建立屬性頁,用的CPropertyPage對象隻有一個,也就是每個屬性頁的内容一樣.現在的問題是:這樣每個屬性頁的标題都是一樣的,是對話框的标題!怎樣動态的改變這個标題,使每個屬性頁的标簽的名稱都不同??
CTabCtrl * pCtrl = pSheet->GetTabControl();
TCITEM tc;
tc.mask = TCIF_TEXT;
tc.pszText = "新标題";
pCtrl->SetItem(0,&tc);//0即是你要改的TAb的索引
33. 怎樣去掉屬性頁的Apply與Help按鈕?
//去掉Help
m_psh.dwFlags |= PSH_HASHELP ;
m_psh.dwFlags &= ~PSH_HASHELP ;
//除掉應用按鈕 m_psh.dwFlags|=PSH_NOAPPLYNOW;
34. 如何給樹控件加入工具提示
1.首先給樹控件加入TVS_INFOTIP屬性風格,如下所示:
if (!m_ctrlTree.Create(WS_CHILD|WS_VISIBLE|
TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|TVS_SHOWSELALWAYS|TVS_INFOTIP, //加入提示TVS_INFOTIP,jingzhou xu(樹控件ID:100)
CRect(0, 0, 0, 0), &m_wndTreeBar, 100))
{
TRACE0("Failed to create instant bar child/n");
return -1;
}
2.其次加入映射消息聲明,如下所示:
afx_msg void OnGetInfoTip(NMHDR* pNMHDR,LRESULT* pResult); //樹控件上加入提示消息,jingzhou xu
ON_NOTIFY(TVN_GETINFOTIP, 100, OnGetInfoTip) //樹控件條目上加入提示,jingzhou xu
3.最後加入呼應涵數處理:
void CCreateTreeDlg::OnGetInfoTip(NMHDR* pNMHDR,
LRESULT* pResult)
{
*pResult = 0;
NMTVGETINFOTIP* pTVTipInfo = (NMTVGETINFOTIP*)pNMHDR;
LPARAM itemData = (DWORD) pTVTipInfo->lParam;
//對應每個條目的資料
HTREEITEM hItem = pTVTipInfo->hItem;
CString tip;
HTREEITEM hRootItem = m_chassisTree.GetRootItem();
if (hRootItem != pTVTipInfo->hItem)
{
tip = "樹結點的提示";
}
else
{
tip = "樹根上的提示";
}
strcpy(pTVTipInfo->pszText, (LPCTSTR) tip);
}
35. 如何在TreeList中加圖示?
[問題提出]
請問treeview控件和treectrl控件的用法有何不同呢?向如何imagelist控件中加圖象呀?
[解決方法]
1)
HICON hicon[8];
m_imageList.Create(16,16,0,8,8);
hicon[0]=AfxGetApp()->LoadIcon(IDI_ICON0);
hicon[1]=AfxGetApp()->LoadIcon(IDI_ICON1);
hicon[2]=AfxGetApp()->LoadIcon(IDI_ICON2);
hicon[3]=AfxGetApp()->LoadIcon(IDI_ICON3);
hicon[4]=AfxGetApp()->LoadIcon(IDI_ICON4);
hicon[5]=AfxGetApp()->LoadIcon(IDI_ICON5);
hicon[6]=AfxGetApp()->LoadIcon(IDI_ICON6);
hicon[7]=AfxGetApp()->LoadIcon(IDI_ICON7);
for(int n=0;n<8;n++)
m_imageList.Add(hicon[n]);
CTreeCtrl *pTree=(CTreeCtrl *)GetDlgItem(IDC_TREE);
pTree->SetImageList(&m_imageList,TVSIL_NORMAL);
2)
CImageList cil1;
cil1.Create(32,32,TRUE,2,2);
cil1.Add(pApp->LoadIcon(IDI_DAO1));
cil1.Add(pApp->LoadIcon(IDI_DAO2));
cil1.Add(pApp->LoadIcon(IDI_DAO3));
cil1.Add(pApp->LoadIcon(IDI_DAO4));
cil1.Add(pApp->LoadIcon(IDI_DAO5));
cil1.Add(pApp->LoadIcon(IDI_DAO6));
cil1.Add(pApp->LoadIcon(IDI_DAO7));
cil1.Add(pApp->LoadIcon(IDI_DAO8));
cil1.Add(pApp->LoadIcon(IDI_DAO9));
//設定圖象清單
m_list.SetImageList(&cil1,LVSIL_NORMAL);
36. 如何輕按兩下清單框項啟動一個與檔案關聯的程式?
有人問我如何輕按兩下清單框項啟動一個程式?其實這個問題很簡單,Windows中有一個API函數可以打開任何類型的檔案:
ShellExecute(NULL,"open",lpFileName,NULL,NULL,SW_SHOWNORMAL);
參數 lpFileName 是檔案的全路徑名。用這個變量你可以傳遞象“C://MyExcelFile.xls”或者“http://www.vckbase.com”啟動Excel程式或者浏覽器程式。如果你隻是想擷取與檔案關聯的程式名,而不是要運作程式,那麼調用::FindExecutable就可以了。
37. 如何防止在listbox中添加很多資料出現不停的重新整理?
[問題提出]
在listbox添加很多資料的時候,由于控件不停的重新整理,導緻出現閃爍,如何解決?
[解決方法]
再添加資料以前,禁止控件重新整理,資料添加完畢以後,再重新整理一次。
[程式實作](其中:m_ListBox是CListBox的控件類型的變量)
m_ListBox.LockWindowUpdate();//禁止本listbox重新整理。
for(int i=0;i<9999;i++)
{
m_ListBox.AddString("test");
}//添加資料。
this->RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
38. 如何得到CListBox所選擇項的String?
[問題提出]
如何得到CListBox所選擇項的String
[解決方法]
用到:CListBox::GetText()
[程式實作]
CString scInfo;
pList->GetText( GetCurSel(),scInfo);
39. 用滑鼠移動基于對話框的無标題欄程式的簡單方法
void CVCTestDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
//一句話解決問題
SendMessage(WM_SYSCOMMAND,0xF012,0);
CDialog::OnLButtonDown(nFlags, point);
}
40. 如何改變框對話或窗體視窗的背景顔色
調用CWinApp : : SetDialogBkColor可以改變所有應用程式的背景顔色。第一個參數指定了背景顔色,第二個參數指定了文本顔色。下例将應用程式對話設定為藍色背景和黃色文本。
BOOL CSampleApp : : InitInstance ( )
{
…
//use blue dialog with yellow text .
SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 , 255 , 0 ) ) ;
…
}
需要重畫對話(或對話的子控件)時,Windows向對話發送消息WM_CTLCOLOR,通常使用者可以讓Windows選擇繪畫背景的刷子,也可重置該消息指定刷子。下例說明了建立一個紅色背景對話的步驟。
首先,給對話基類增加一人成員變量CBursh :
class CMyFormView : public CFormView
{
…
private :
CBrush m_ brush ; // background brush
…
} ;
其次, 在類的構造函數中将刷子初始化為所需要的背景顔色。
CMyFormView : : CMyFormView ( )
{
// Initialize background brush .
m_brush .CreateSolidBrush (RGB ( 0, 0, 255 ) )
}
最後,使用ClassWizard處理WM_CTLCOLOR消息并傳回一個用來繪畫對話背景的刷子句柄。注意:由于當重畫對話控件時也要調用該函數,是以要檢測nCtlColor參量。
HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor )
{
// Determine if drawing a dialog box . If we are , return +handle to
//our own background brush . Otherwise let windows handle it .
if (nCtlColor = = CTLCOLOR _ DLG )
return (HBRUSH) m_brush .GetSafeHandle ( ) ;
return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor );
}
41.如何禁止對話框關閉按鈕和浮動工具條上的系統菜單
1、禁止對話框中的關閉按鈕有二種方法。
第一種方法,用ModiftMenu()涵數來實作:
CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->ModifyMenu(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );
第二種方法,用EnableMenuItem()涵數來實作:
CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->EnableMenuItem( SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
2、禁止浮動工具條上的系統菜單。
建立一個CToolBar的派生類CxxToolBar,在新類中的左鍵輕按兩下(CxxToolBar::OnLButtonDblClk(...))
和左鍵單擊(CxxToolBar:: OnLButtonDown(...))涵數中分别加入下面代碼既可:
if (IsFloating()) //工具條正在浮動狀态中
{
CWnd* pMiniFrame;
CWnd* pDockBar;
pDockBar = GetParent();
pMiniFrame = pDockBar->GetParent();
//去除其上系統菜單
pMiniFrame->ModifyStyle(WS_SYSMENU, NULL);
//重繪工具條
pMiniFrame->ShowWindow(SW_HIDE);
pMiniFrame->ShowWindow(SW_SHOW);
}
3、禁止視窗最大化按鈕
在PreCreateWindow()涵數中去掉WS_MAXIMIZEBOX風格顯示既可。
BOOL CxxFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style &= ~WS_MAXIMIZEBOX;
return CFrameWnd::PreCreateWindow(cs);
}
42.如何拷貝一個工程的對話框資源到另一個工程中?
有兩種方法可以實作:
1)你可以直接拷貝resource,用VC++以文本的方式或者直接用文本編輯器打開.rc檔案,将有關的片段從
一個工程拷貝到另一個工程.你可以通過查找如下字樣的片段(此片段用來定義對話框資源)來拷貝你要
的部分:
IDD_MYDIALOG_ID DIALOG DISCARDABLE 0, 0, 235, 55
這裡的IDD_MYDIALOG_ID是你的對話框的ID,将到此片段結尾的部分全拷下來,通常你還要給新的工程
加一個ID(通過DevStudio的工具或者直接修改resource.h檔案).
2)可以通過DevStudio的copy/paste功能.首先,在編輯器以"auto"模式打開.rc檔案,這時resource
正确的顯示出來.然後,選中要拷貝的對話框的ID,在Edit菜單裡選Copy或者按住Ctrl+C.然後打開目标
resource檔案,在Edit菜單裡選Paste或者按住Ctrl+V.
43.如何實作點一下對話框外面的區域,自動隐藏對話框?
[問題提出]
如果想在點選對話框外面的地方使得對話框關閉,該如何做?
[解決方法]
試試下面的代碼,原理是在激活對話框時,捕獲滑鼠的動作,當滑鼠點選時判斷是否點選在對話框外,是的話就釋放對話框.
[程式實作]
建立名為My的對話框程式.實作如下步驟:
在MyDlg.h中加入:
class CShowWindow1Dlg : public CDialog
{
// Construction
public:
int m_cx;
int m_cy;
......
};
在MyDlg.cpp中:
//定義消息映象,處理滑鼠單擊及激活
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_LBUTTONDOWN()
ON_WM_ACTIVATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rect;
GetClientRect(&rect);
rect.InflateRect(m_cx, m_cy);
//Release dialog if the user click outside it.
if(!rect.PtInRect(point))
{
EndDialog(IDCANCEL);
}
CDialog::OnLButtonDown(nFlags, point);
}
void CMyDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
CDialog::OnActivate(nState, pWndOther, bMinimized);
if( nState == WA_ACTIVE || nState == WA_CLICKACTIVE)
SetCapture();
else
ReleaseCapture();
}
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
.....
OSVERSIONINFO info;
memset((char*)&info, 0, sizeof(OSVERSIONINFO));
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(GetVersionEx(&info))
{ //we don't run on Win32s, so check only two values
if(info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{ //On windows 95
m_cx = GetSystemMetrics(SM_CXFIXEDFRAME);
m_cy = GetSystemMetrics(SM_CYFIXEDFRAME);
}
else
{ //On NT
m_cx = GetSystemMetrics(SM_CXDLGFRAME);
m_cy = GetSystemMetrics(SM_CYDLGFRAME);
}
}
}
說明:
1)WM_ACTIVATE消息在ClassWizard中沒有,按如下步驟添加,右擊CMyDlg類,選Add Windows Message Handle,接着在Filter for messages available to中選Window,在New Windows messages/events清單中就會出現WM_ACTIVATE,選中,點選Add Handler
2)SM_CXDLGFRAME,SM_CYDLGFRAME NT中取得有WS_DLGFRAMEstyle風格的視窗的高和寬 95中已經廢棄而采用SM_CX_FIXEDFRAME和SM_CYFIXEDFRAME
44. 初始化應用程式的大小
如果想使應用程式界面(文檔)在開始運作是按你的尺寸展現在螢幕上,
添加代碼如下:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
int xsize=::GetSystemMetrics(SM_CXSCREEN);
int ysize=::GetSystemMetrics(SM_CYSCREEN);
cs.cx=xsize*5/10;
cs.cy=ysize*5/10;
cs.x=(xsize-cs.cx)/2;
cs.y=(ysize-cs.cy)/2;
}
其中的5/10是你的初始界面占螢幕的百分比,可以自己修改。如果想使應用程式大小固定添加cs.style&=~WS_THICKFRAME;
45. 如何得到視圖指針?
[問題提出]
現在你有一個多線程的Demo,你想在多線程裡處理視圖指針裡的函數,我們給這個函數起個名字:Put();該如何實作呢?
//有兩種方法可以實作你的要求:
//1)第一種方法:
//要是多線程不是在App.cpp裡出現,那麼要在多線程的.cpp中加上extern CYourApp theApp;
//獲得文檔模闆:
POSITION curTemplatePos = theApp.GetFirstDocTemplatePosition();
CDocTemplate *m_doc=theApp.GetNextDocTemplate(curTemplatePos);
//獲得文檔:
curTemplatePos=m_doc->GetFirstDocPosition();
CYourDoc *m_pdoc=(CA8Doc*)m_doc->GetNextDoc(curTemplatePos);
//獲得視圖:
curTemplatePos=m_pdoc->GetFirstViewPosition();
CYourView *m_pview=(CYourView*)m_pdoc->GetNextView(curTemplatePos);
//調用視圖函數:
m_pview->Put();
//2)第二種方法:
//獲得窗體指針:
CMainFrame *pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
//獲得與該窗體符合的視圖:
CYourView *m_pView = (CYourView *) pFrame->GetActiveView();
//調用視圖函數:
m_pView->Put();
46. 如何使我的程式在啟動時不建立一個新文檔?
[問題]
如何使我的程式在啟動時不建立一個新文檔?
[解答]
在程式的InitInstance中的ProcessShellCommand函數之前加入: cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
47. 如何将标題欄上的右鍵菜單屏蔽掉?
[解決方法]
右鍵菜單是系統菜單,隻要将其WS_SYSMENU的屬性去掉即可.
[程式實作]
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
........
long style = GetWindowLong(m_hWnd, GWL_STYLE);
style &= ~WS_SYSMENU;
SetWindowLong(m_hWnd, GWL_STYLE, style);
return 0;
}
48.如何全屏顯示(沒有标題,沒有菜單,沒有工具條)
[解決方法]
重載CMainFrame的ActivateFrame函數:
void CMainFrame::ActivateFrame(int nCmdShow)
{
CRect cRectdesktop;
WINDOWPLACEMENT windowplacement;
::GetWindowRect(::GetDesktopWindow(),&cRectdesktop);
::AdjustWindowRectEx(&cRectdesktop,GetStyle(),TRUE,GetExStyle());
windowplacement.rcNormalPosition=cRectdesktop;
windowplacement.showCmd=SW_SHOWNORMAL;
SetWindowPlacement(&windowplacement);
CFrameWnd::ActivateFrame(nCmdShow);
}
49.如何設定有背景顔色的文本
(1)[解決方法]
用到了CDC::SetBkMode();
[程式實作]
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rcView;//加這兩句
GetClientRect(rcView);
// TODO: add draw code for native data here
CString str (_T("Perfect Text..."));
pDC->SetBkMode(TRANSPARENT);
rcView.OffsetRect (1,1);
pDC->SetTextColor(RGB (0,0,0));
pDC->DrawText(str,str.GetLength(),rcView,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
rcView.OffsetRect(-1,-1);
pDC->SetTextColor(RGB (255,0,0));
pDC->DrawText(str,str.GetLength(),rcView,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
(2) 建立名為My的SDI或MDI,并響應WM_ERASEBKGND.
BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CBrush Brush (RGB(114,147,171));
// Select the brush into the device context .
CBrush* pOldBrush = pDC->SelectObject(&Brush);
// Get the area that needs to be erased .
CRect ViewClip;
pDC->GetClipBox(&ViewClip);
//Paint the area.
pDC->PatBlt(ViewClip.left,ViewClip.top,ViewClip.Width(),ViewClip.Height(),PATCOPY);
//Unselect brush out of device context .
pDC->SelectObject (pOldBrush );
// Return nonzero to half fruther processing .
return TRUE;
return CView::OnEraseBkgnd(pDC);
}
此方法也适合基類是EditView的SDI或MDI的情況,但是字型的顔色和底色不行.建議用WM_CTLCOLOR.
50.串太長時往讓其末尾顯示一個省略号(在SDI或MDI的View中)
[問題提出]
如何在串太長時往讓其末尾顯示一個省略号(在SDI或MDI的View中)?
[程式實作]
建立名為My的SDI或MDI工程.
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->DrawText(CString("It's a long string,so we will add a '...' at the end."),CRect (110, 110, 180, 130),DT_LEFT | DT_END_ELLIPSIS);
//Add ellpsis to middle of string if it does not fit
pDC->DrawText(CString("It's a long string,so we will add a '...' at the end."),CRect (110, 140, 300, 160),DT_LEFT | DT_PATH_ELLIPSIS);
}
51. 如何獲得其他程式的圖示,并顯示在View中
[問題提出]
有的時候,如:類資料總管會遇到獲得程式圖示并顯示的操作,如何實作呢?
[解決方法]
SDK函數SHGetFileInfo來獲得有關檔案的很多資訊:如大小圖示,屬性,類型等.
[程式實作]
建立名為My的SDI工程.在OnPaint()函數中加入:
void CMyView::OnPaint()
{
CPaintDC dc(this); // device context for painting
HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);
if (hIcon && hIcon!=(HICON)-1)
dc.DrawIcon(10,10,hIcon);
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
}
說明:_T("NotePad.exe")指的是要獲得什麼程式的圖示.
或者在OnDraw()中(此時必須保證沒有OnPaint()函數,想想為何?)
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);
if (hIcon &&hIcon!=(HICON)-1)
pDC->DrawIcon(10,10,hIcon);
}
52 .RichEdit
在Dialog(FormView中打開)中加入CRichEdit控件後,這個dialog 為什麼打不開如何處理?
[解決方法]
在函數:InitInstance的第一句加入AfxInitRichEdit();
53. 如何使FormView中顯示dialog時,不是凹的?
[問題提出]
為什麼FormView中顯示dialog時,是凹的,能不能不這樣
[解決方法]
在Dialog的屬性中:
增加屬性WS_BORDER 或者 WS_EX_WINDOWEDGE
用程式實作:
pView->ModifyStyle(,WS_BORDER) 或者pView->ModifyStyleEx(,WS_EX_WINDOWEDGE )
54. 如何改變視窗标題?
[問題提出]
在應用程式的不同運作時期,要反映目前狀态往往會修改應用程式标題.
[解決方法]
在MFC類庫中提供了CWnd::SetWindowText函數,通過該函數可以改變任何窗體(包括控件)的标題.
改變主窗體的标題:
CWnd *m_pMainWnd;
m_pMainWnd=AfxGetMainWnd();
m_pMainWnd->SetWindowText(_T("改變标題"));
當改變多視MDI的子視窗的标題時,用:
GetParentFrame()->SetWindowText(_T("MDI Child改變标題"));
當改變按鈕的标題時(假設按鈕的ID=IDC_BUTTON1):
GetDlgItem(IDC_BUTTON1)->SetWindowText(_T("Button 改變标題"));
運作看看.
55.圖示透明
(1).Windows中的圖示其實是有兩個圖像組成的,其中一個用于與它要顯示的位置的圖像做“AND”操作,另一個作“XOR”操作。
透明:用“白色”AND,用“黑色”XOR
反色:用“白色”AND,用“白色”XOR
正常色:用“黑色”AND,用正常顔色XOR.
(2). WIN9X中好像是對像素的操作實作透明的
WIN2K中就有API直接實作透明了!
WIN2K中
GetWindowLong
SetWindowLong
SetLayeredWindowAttributes
三個API就可以實作透明了!
(3)
::DrawIconEx(pDC->GetSafeHdc(),point.x,point.y,icon,icosize,icosize,0,NULL,DI_NORMAL);
56.ASSERT()是幹什麼用的
ASSERT()是一個調試程式時經常使用的宏,在程式運作時它計算括号内的表達式,如果表達式為FALSE (0), 程式将報告錯誤,并終止執行。如果表達式不為0,則繼續執行後面的語句。這個宏通常原來判斷程式中是否出現了明顯非法的資料,如果出現了終止程式以免導緻嚴重後果,同時也便于查找錯誤。例如,變量n在程式中不應該為0,如果為0可能導緻錯誤,你可以這樣寫程式:
......
ASSERT( n != 0);
k = 10/ n;
......
ASSERT隻有在Debug版本中才有效,如果編譯為Release版本則被忽略。
assert()的功能類似,它是ANSI C标準中規定的函數,它與ASSERT的一個重要差別是可以用在Release版本中。
56. 将RADIO控件初始狀态設定成為選中
1、"在OnInitialDialog中用CButton::CheckRadioButton(...)
2、"在OnInitialDialog中用CButton::SetCheck(...)
3、"關聯一個整型值,在構造函數中設為0。
57.獲得視圖
CFrameWnd* pFrameWnd = (CFrameWnd*)theApp.GetMainWnd();
CMyView* pView = (CMyView*)pFrameWnd->GetActiveView();
58.如何得到螢幕的真實尺寸
[問題提出]
我的螢幕是1024*800,如何得到螢幕的真實大小,我用GetSystemMetrics(SM_CYFULLSCREEN)得到的高度總是小于800
[問題解答]
GetSystemMetrics(SM_CYFULLSCREEN)得到的隻是螢幕使用者區的大小。要得到螢幕的真實大小需要使用
GetDeviceCaps函數,該API函數原型是這樣的:
int GetDeviceCaps(
HDC hdc, // handle to DC
int nIndex // index of capability
);
///得到螢幕尺寸的代碼如下
void CMyDlg::OnPaint()
{
CPaintDC dc(this);
int cx = ::GetDeviceCaps(dc.m_hDC,HORZRES);///得到寬度
int cy = ::GetDeviceCaps(dc.m_hDC,VERTRES);///得到高度
CDialog::OnPaint();
59. 修改标題欄高度
NONCLIENTMETRICS nm
調用SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(nm),&nm,0)
重設SystemParametersInfo(SPI_SETNONCLIENTMETRICS,sizeof(nm),&nm,0)
60. 如何實作“氣球式”工具提示。
本程式介紹一個與CToolTipCtrl相似的類CTooolTipWnd。
使用該類的方法如下:
1. 增加ToolTipWnd.cpp到工程檔案。
2. 在頭檔案中添加#include "ToolTipWnd.h" 。
3. 在類聲明中添加:
CToolTipWnd m_BalloonToolTip;
4. 在OnInitDialog(對話框)或OnInitialUpdate(表單視)中添加下面代碼:
m_BalloonToolTip.Create(this);
m_BalloonToolTip.AddTool(GetDlgItem(), , [text color]);
eg.
m_BalloonToolTip.AddTool(GetDlgItem(IDC_EDIT1),"Tooltip", RGB(255,0,0));
第三個參數為可選,預設為RGB(0, 0, 0)。預設文本顔色可以用SetDefTextColor進行設定。
4. 重載PreTranslateMessage并添加下面代碼:
if(m_BalloonToolTip)
m_BalloonToolTip.RelayEvent(pMsg);
61. dlg 上建立View的方法:
OnInitDialog()
{
CDialog:;OnInitDialog();
CRect rectWindows;
GetWinodwRect(&rectWindows);
CRuntimeClass *pViewClass=RUNTIME_CLASS(CXXXView);
CCreateContext *pContext=new CCreateContext;
pContext->m_pCurrentDoc=NULL;
pContext->m_pCurrentFrame=NULL;
pContext->m_pLastView=NULL;
pContext->m_pNewDocTemplate=NULL;
pContext->m_pNewViewClass=pViewClass;
CWnd *pWnd=DYNAMIC_DOWNCAST(CWnd,pviewClass->CreateObject());
pWnd->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW,CRect(0,0,0,0),this,pContext);
delete pContext;
CXXXView *pView=DYUNAMIC_DOWNCAST(CXXXView,pWnd);
...............
}
62. 視窗最大化、最小化及關閉的消息是什麼?如何截獲?
最大化、最小化将發送WM_SYSCOMMAND消息。要處理該消息,可以這麼做:
1、在Form的頭檔案中添加:
void __fastcall RestrictMinimizeMaximize(TMessage &Msg);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SYSCOMMAND, TMessage, RestrictMinimizeMaximize)
END_MESSAGE_MAP(TForm)
2、在Form的單元檔案中添加:
void __fastcall TForm1::RestrictMinimizeMaximize(TMessage& Msg)
{
if (Msg.WParam == SC_MINIMIZE)
{
//catches minimize...
}
else if (Msg.WParam == SC_MAXIMIZE)
{
//catches maximize...
}
TForm::Dispatch(&Msg);
// or "else TForm::Dispatch(&Msg)" to trap
}
關閉視窗的消息為WM_CLOSE,C++Builder提供了OnClose事件。
63. 如何周遊整個目錄樹查找檔案
在應用程式的開發過程中,會遇到如何查找某一檔案以确定此檔案路徑的問題。利用CFileFind類可以比較友善地在目前目錄下進行檔案查找,但卻不能對其子目錄中的檔案進行搜尋。而實際應用中往往需要對某一整個目錄樹,甚至是整個C槽或D盤驅動器進行檔案搜尋。通過實踐,我們在Visual C++ 6.0中程式設計實作了如何周遊任意目錄樹,以查找某一特定的檔案。
在下面的具體陳述中可以看到,在确定要查找的檔案名和要進行搜尋的目錄的名稱後,将調用函數Search_Directory進行檔案的查找。首先依次查找目前目錄下的每一個實體(檔案或是子目錄),如果是某一子目錄,則進入該子目錄并遞歸調用函數Search_Dirctory進行查找,查找完畢之後, 再傳回上一級目錄;如果不是子目錄而是某一檔案,則判斷其是否就是我們要查找的檔案,如果是則輸出其完整的檔案路徑。這樣,通過Search_Directory函數的反複遞歸調用,就可以實作對整個目錄,包括子目錄的周遊搜尋。下面将舉例詳細講述如何在VC++中程式設計實作在整個目錄樹中的檔案查找。
1. 在Visual C++ 6.0(VC++ 5.0與之類似)中用預設方式建立了一基于對話框的應用程式Search。在主視窗對話框上放置一指令按鈕,其Caption為“Search File”,ID為ID_BUTTON_SEARCH。單擊此按鈕将完成檔案的查找工作。
2. 利用ClassWizard為“Search File”按鈕的BN_CLICKED 事件添加處理函數OnButtonSearch,代碼如下:
#include 〈direct.h〉
#include 〈io.h〉
void CSearchDlg::OnButtonSearch()
{
// TODO: Add your control notification handler code here
char szFilename[80];
// 字元串 szFilename 表示要查找的檔案名
strcpy(szFilename,"Mytext.txt");
_chdir("d://"); // 進入要查找的路徑(也可為某一具體的目錄)
// 查找檔案, 如果查到則顯示檔案的路徑全名
Search_Directory(szFilename);
// 為CSearchDlg類的一成員函數
MessageBox(″查找檔案完畢!″);
// 顯示查找完畢的資訊
}
3. 在CSearchDlg類中增加成員函數Search_Directory,它将完成具體的檔案查找工作,代碼如下:
void CSearchDlg::Search_Directory(char* szFilename)
{
long handle;
struct _finddata_t filestruct;
//表示檔案(或目錄)的資訊
char path_search[_MAX_PATH];
//表示查找到的路徑結果
// 開始查找工作, 找到目前目錄下的第一個實體(檔案或子目錄),
// "*"表示查找任何的檔案或子目錄, filestruct為查找結果
handle = _findfirst("*", &filestruct);
// 如果handle為-1, 表示目前目錄為空, 則結束查找而傳回
if((handle == -1)) return;
// 檢查找到的第一個實體是否是一個目錄(filestruct.name為其名稱)
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
// 如果是目錄, 則進入該目錄并遞歸調用函數Search_Dirctory進行查找,
// 注意: 如果目錄名的首字元為'.'(即為"."或".."), 則不用進行查找
if( filestruct.name[0] != '.' )
{
_chdir(filestruct.name);
Search_Directory(szFilename);
// 查找完畢之後, 傳回上一級目錄
_chdir("..");
}
}
else // 如果第一個實體不是目錄, 則檢查是否是要查找的檔案
{
// stricmp對兩字元串進行小寫形式的對比, 傳回為0表示完全一緻
if( !stricmp(filestruct.name, szFilename) )
{
// 先獲得目前工作目錄的全路徑
_getcwd(path_search,_MAX_PATH);
// 再獲得檔案的完整的路徑名(包含檔案的名稱)
strcat(path_search,"//");
strcat(path_search,filestruct.name);
MessageBox(path_search); //輸出顯示
}
}
// 繼續對目前目錄中的下一個子目錄或檔案進行與上面同樣的查找
while(!(_findnext(handle,&filestruct)))
{
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
if(*filestruct.name != '.')
{
_chdir(filestruct.name);
Search_Directory(szFilename);
_chdir("..");
}
}
else
{
if(!stricmp(filestruct.name,szFilename))
{
_getcwd(path_search,_MAX_PATH);
strcat(path_search,"//");
strcat(path_search,filestruct.name);
MessageBox(path_search);
}
}
}
_findclose(handle);
// 最後結束整個查找工作
}
這樣我們就可以對整個目錄進行周遊搜尋,查找某一特定的檔案,并輸出顯示其完整的檔案路徑。以上的程式在Visual C++ 6.0中已調試通過。
64. Richedit control的設定背景圖檔辦法
1:繼承CRichEditCtrl::OnEraseBkgnd(CDC* pDC)消息事件中,給Richedit控件繪制上背景圖檔:m_bmpBackground.DrawDIB(pDC, 0, 0, rc.Width(), rc.Height());當然也可以通過subclass richedit window之後,在回調函數中處理WM_ERASEBKGND消息。
2:設定了Richedit控件的透明屬性;
3:依照kenwhale所說的,Hook了GDI32.DLL中的ExtTextOut函數,将RichEdit的text-output options去除ETO_OPAQUE style
。綜上所述,即可實作RichEdit控件的背景圖檔效果。
據此,我還實作了RichEdit控件背景繪制AVI動畫效果。
65. MFC程式中如何建立多級目錄
BOOL mkdirEx(const char* lpPath)
{
CString pathname = lpPath;
if(pathname.Right(1) != "/")
pathname += "/" ;
int end = pathname.ReverseFind('/');
int pt = pathname.Find('/');
if (pathname[pt-1] == ':')
pt = pathname.Find('/', pt+1);
CString path;
while(pt != -1 && pt<=end)
{
path = pathname.Left(pt+1);
if(_access(path, 0) == -1)
_mkdir(path);
pt = pathname.Find('/', pt+1);
}
return true;
}
66. 解決外部符号錯誤:_main,[email protected],__beginthreadex
在建立MFC項目時, 不使用MFC AppWizard向導, 如果沒有設定好項目參數, 就會在編譯時産生很多連接配接錯誤, 如error LNK2001錯誤, 典型的錯誤提示有:
libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol [email protected]
msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol [email protected]
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
下面介紹解決的方法:
1). Windows子系統設定錯誤, 提示:
libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Windows項目要使用Windows子系統, 而不是Console, 可以這樣設定:
[Project] --> [Settings] --> 選擇"Link"屬性頁,
在Project Options中将/subsystem:console改成/subsystem:windows
2). Console子系統設定錯誤, 提示:
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol [email protected]
控制台項目要使用Console子系統, 而不是Windows, 設定:
[Project] --> [Settings] --> 選擇"Link"屬性頁,
在Project Options中将/subsystem:windows改成/subsystem:console
3). 程式入口設定錯誤, 提示:
msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol [email protected]
通常, MFC項目的程式入口函數是WinMain, 如果編譯項目的Unicode版本, 程式入口必須改為wWinMainCRTStartup, 是以需要重新設定程式入口:
[Project] --> [Settings] --> 選擇"C/C++"屬性頁,
在Category中選擇Output,
再在Entry-point symbol中填入wWinMainCRTStartup, 即可
4). 線程運作時庫設定錯誤, 提示:
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
這是因為MFC要使用多線程時庫, 需要更改設定:
[Project] --> [Settings] --> 選擇"C/C++"屬性頁,
在Category中選擇Code Generation,
再在Use run-time library中選擇Debug Multithreaded或者multithreaded
其中,
Single-Threaded單線程靜态連結庫(release版本)
Multithreaded多線程靜态連結庫(release版本)
multithreaded DLL多線程動态連結庫(release版本)
Debug Single-Threaded單線程靜态連結庫(debug版本)
Debug Multithreaded多線程靜态連結庫(debug版本)
Debug Multithreaded DLL多線程動态連結庫(debug版本)
單線程: 不需要多線程調用時, 多用在DOS環境下
多線程: 可以并發運作
靜态庫: 直接将庫與程式Link, 可以脫離MFC庫運作
動态庫: 需要相應的DLL動态庫, 程式才能運作
release版本: 正式釋出時使用
debug版本: 調試階段使用
67. 建立包含多個子目錄的目錄
void CreateAllDirectories(CString strDir)
{
//remove ending / if exists
if(strDir.Right(1)=="//")
strDir=strDir.Left(strDir.GetLength()-1);
// base case . . .if directory exists
if(GetFileAttributes(strDir)!=-1)
return;
// recursive call, one less directory
int nFound = strDir.ReverseFind('//');
CreateAllDirectories(strDir.Left(nFound));
// actual work
CreateDirectory(strDir,NULL);
}
68. ReverseFind()
#include <STDIO.H>
#include <AFX.H>
int main()
{
CString s;
s.Format("abcdefghijk");
int nPos = s.ReverseFind('a');
printf("nPos is %d/n",nPos);
return 0;
}
其中,'a'對應的nPos是0,'h'對應的nPos是7,以此類推。但是:s.ReverseFind('a')和s.Find('a')的結果是一樣的。
問題是:ReverseFind() 和 Find() 有什麼差別呢:
對于ReverseFind(),查找順序是從後往前,找到後的nPos是按前後順序排列的。
而Find()是從前往後查的,找到後的nPos也是按前後順序排列的。
69. MDI中如何隻屏蔽掉子架構的右上角的關閉按鈕
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
return -1;
。。。
CMenu* pSysMenu = GetSystemMenu(FALSE);
pSysMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND |MF_DISABLED|MF_GRAYED);
return 0;
}
70. 程式如何删除自己
/
int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {
// Is this the Original EXE or the clone EXE?
// If the command-line 1 argument, this is the Original EXE
// If the command-line >1 argument, this is the clone EXE
if (__argc == 1) {
// Original EXE: Spawn clone EXE to delete this EXE
// Copy this EXEcutable image into the user''s temp directory
TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
GetTempPath(_MAX_PATH, szPathClone);
GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone);
CopyFile(szPathOrig, szPathClone, FALSE);
/,NULL);
//注意此處DLGPROC為NULL,并不要緊,因為接下要subclass啦
m_dlgTest->SubclassWindow (hwndDlg);//挂接到成員變量!
m_dlgTest->ShowWindow (SW_SHOW);
//這時可以看到一個"自由"的對話框彈出,和你的主視窗是平起平坐的.
}
當然不要忘了在對話框關閉時DestroyWindow()..那都是在對話框類中的标準處理了.
74. 隐藏視窗(子視窗沒有焦點時)
在程式啟動時 InitDialog 中使用 SetWindowPos 将窗體設定到螢幕以外
然後再隐藏
1.在OnInitDialog()函數裡設定定時器:(WINDOWS API裡面響應消息WM_INITDIALOG)
SetTimer(1, 1, NULL);
2.添加處理WM_TIMER的消息處理函數OnTimer,添加代碼:
if(nIDEvent == 1)
{
DeleteTimer(1);
ShowWindow(SW_HIDE);
}
75.修改視圖背景
How do I change the background color of a view?
To change the background color for a CView, CFrameWnd, or CWnd object, process the WM_ERASEBKGND message. The following code shows how:
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
// Set brush to desired background color.
CBrush backBrush(RGB(255, 128, 128));
// Save old brush.
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // Erase the area needed.
pDC->PatBlt(rect.left, rect.top, rect.Width(),
rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
I solved the problem like this:
HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_BTN:
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(TRANSPARENT);
}
case CTLCOLOR_DLG:
{
CBrush* back_brush;
COLORREF color;
color = (COLORREF) GetSysColor(COLOR_BTNFACE);
back_brush = new CBrush(color);
return (HBRUSH) (back_brush->m_hObject);
}
}
return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
76. 如何實作點選對話框外的地方使對話框到主視窗的後面
隻能将桌面做為父視窗
pMDlg = new CMDlg;
pMDlg->Create(IDD_M_DIALOG,CWnd::GetDesktopWindow());
pMDlg->ShowWindow(SW_SHOW);
然後在工作列裡隐藏對話框程式
如何讓對話框應用程式在在工作列上不出現,并且不隐藏視窗。
[解決方法]
把對話框的擴充屬性修改成為WS_EX_TOOLWINDOW。
[程式實作]
把對話框的屬性設定成為toolwindow,然後在需要的地方執行本代碼。
DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
Style = WS_EX_TOOLWINDOW ;
AfxGetMainWnd()->ShowWindow(FALSE);
::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style);
AfxGetMainWnd()->ShowWindow(TRUE);
77. 想在程式一啟動時就自動關閉視窗,不在工作列裡顯示
用CTRL+W打開ClassWizard;
點選Class Info頁,類名是工程名Dlg,
再在左下方的"Filter"中選擇"Windows";
回到Message Maps頁,就可以看到消息中有WM_WINDOWPOSCHANGING,
加入代碼,如上所示.
這樣運作*.EXE,不但看不到主界面,工作列也沒有,就是任務管理器中的"應用程式"中也不列出,那該如何關閉它?
在任務管理器的"程序"中可以找到它,這是黑客程式常用的方法.
如果需要的話,連"程序"中也看不到.這樣要終止它就是問題了.
78.修改列印預覽的ToolBar
為AFX_IDD_PREVIEW_TOOLBAR這個ID建立一個DialogBar。則系統就會用新建立的DialogBar代替系統預設的那個
79. 如何實作SDI與MDI的轉換?
我想将一個編好的SDI應用程式轉換為MDI,很明顯要有多處的改變。
你可以這樣做:建立一個繼承于CMDIChidWnd的類,不防設為CChldFrm.在CWinApp中作如下變化。
InitInstance()
{
. ...
//instead of adding CSingleDocTemplate
// Add CMultiDocTemplate.
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSDIDoc),
RUNTIME_CLASS(CChldFrm),
// For Main MDI Frame change this frame window from
// CFrameWnd derivative ( i.e. CMainFrame )
// to your CMDIChildWnd derived CChldFrm.
RUNTIME_CLASS(CSDIView));
/// After this it is required to create the main frame window
// which will contain all the child windows. Now this window is
// what was initially frame window for SDI.
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
.....
}
在從CMDIFrameWnd中繼承的類CMainFrame代替CFramWnd後,所有的類都将從CMDIFrame繼承,而不是CFrameWnd,編譯運作後你就會發現程式已經從SDI變換到MDI。
注意:在CMainFram中必須将構造函數從private改為public.否則會出錯。
80. CDC中的豎排文本?
在OnDraw成員函數中我想讓文本豎直對齊,但CDC類似乎不支援該處理
方法一:如果你的豎直對齊是指旋轉文本的話,下面的代碼會對你有幫助:該代碼檢查一個Check box控制,檢視文本是否需要旋轉.
// m_pcfYTitle is a CFont* to the selected font.
// m_bTotateYTitle is a bool (==TRUE if rotated)
void CPage1::OnRotateytitle()
{
LOGFONT lgf;
m_pcfYTitle->GetLogFont(&lgf);
m_bRotateYTitle=
((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0;
// escapement is reckoned clockwise in 1/10ths of a degree:
lgf.lfEscapement=-(m_bRotateYTitle*900);
m_pcfYTitle->DeleteObject();
m_pcfYTitle->CreateFontIndirect(&lgf);
DrawSampleChart();
}
注意如果你從CFontDialog中選擇了不同的字型,你應該自己設定LOGFONT的lfEscapement成員.将初始化後的lfEscapement值傳到CFontDialog中.
方法二:還有一段代碼可參考:
LOGFONT LocalLogFont;
strcpy(LocalLogFont.lfFaceName, TypeFace);
LocalLogFont.lfWeight = fWeight;
LocalLogFont.lfEscapement = Orient;
LocalLogFont.lfOrientation = Orient;
if (MyFont.CreateFontIndirect(&LocalLogFont))
{
cMyOldFont = cdc->SelectObject(&MyFont);
}
81. 如何用鍵盤滾動分割的視口?
我的問題是當我用滑鼠滾動分割視窗時,視口滾動都很正常,但用鍵盤時,卻什麼也沒有發生.
在你的視圖繼承類中加入如下兩個函數,假定該類為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;
}
82. 如何改變預設的光标形狀?
我試着将光标改變為其它的形狀和顔色,但卻沒有變化.
在對話框/視窗/你需要的地方加上對WM_SETCURSOR消息的處理.
BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TOD Add your message handler code here and/or call default
::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR));
return TRUE;
//return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
你沒有成功的原因是因為視窗類光标風格不能為NULL.
83. 如何選擇CTreeCtrl中的節點文本進行編輯?
在向CTreeCtrl中加入一項後,有什麼方法可以編輯該節點的文本呢?
首先設定你的CcompTreeCtrl具有TVS_EDITLABELS屬性.在設計時用控件屬性來設定在運作時用GetStyle()/SetStyle()成員函數來設定.然後請看下述代碼:
HTREEITEM CCompTreeCtrl::AddSet()
{
static int setCnt =3D 1;
HTREEITEM hItem;
CString csSet;
//create text for new note: New Set 1, New Set 2 ...
csSet.Format( _T( "New Set %d" ), setCnt++ );
hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER );
if( hItem !=3D NULL )
EditLabel( hItem );
return hItem;
}
84. CListCtrl中選擇變化時如何獲得通知?
我在Report View中使用了一個CListCtrl(自繪制類型),我想知道什麼時候選擇項發生了改變.
在選擇項變化時,可以使用按鈕有效或失效,按如下操作:
加入LVN_ITEMCHANGED消息處理.
void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
if (pNMListView->uChanged == LVIF_STATE)
{
if (pNMListView->uNewState)
GetDlgItem(IDC_DELETE)->EnableWindow(TRUE);
else
GetDlgItem(IDC_DELETE)->EnableWindow(FALSE);
}
}
85. List控件中整欄選擇?
我在處理List控件時碰到了麻煩,我想建立一個ListView,來依據Tree控件的選擇同時在ListView和ReportView中顯示清單的資訊.以下是相關的代碼:
// Set full line select
ListView_SetExtendedListViewStyle(m_plstCustomers->GetSafeHwnd(),
LVS_EX_FULLROWSELECT);
按如下方法處理:
// -------------------- begin of snippet --------------------------------
bool CCommCtrlUtil32::ListCtrl_ModifyExtendedStyle(CListCtrl& p_rListCtrl,
const DWORD p_dwStyleEx,
const bool p_bAdd)
{
HWND t_hWnd = p_rListCtrl.GetSafeHwnd();
DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd);
if(p_bAdd)
{
if(0 == (p_dwStyleEx & t_dwStyleEx))
{
// add style
t_dwStyleEx |= p_dwStyleEx;
}
}
else
{
if(0 != (p_dwStyleEx & t_dwStyleEx))
{
// remove style
t_dwStyleEx &= ~p_dwStyleEx;
}
}
ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx);
return true;
}
86. 如何限制mdi子架構最大化時的大小?
用ptMaxTrackSize代替prMaxSize,如下所示:
void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// TOD Add your message handler code here and/or call default
CChildFrame::OnGetMinMaxInfo(lpMMI);
lpMMI->ptMaxTrackSize.x = 300;
lpMMI->ptMaxTrackSize.y = 400;
}
87. 怎樣實作3D效果?
在對話框中怎樣實作Edit和Listboxes控件的3D效果?(環境95/NT VC5.0)
1). 使用帶WS_EX_CLIENTEDGE标志的::CreateWindowEx來替換::CreateWindow 或者用CWnd::CreateEx替換CWnd::Create.
2).在建立控件之後,調用ModifyStyleEx(0, WS_EX_CLIENTEDGE).
88. How do I update the text of a pane in a status bar?
By default, a CStatusBar pane is not enabled when the pane is created. To activate a pane, you must call the ON_UPDATE_COMMAND_UI() macro for each pane on the status bar and update the panes. Because panes do not send WM_COMMAND messages, you cannot use ClassWizard to activate panes; you must type the code manually. For example, suppose one pane has ID_INDICATOR_PAGE as its identifier and that it contains the current page number in a document. To make the ID_INDICATOR_PAGE pane display text, add the following to a header file (probably the MAINFRM.H file):
afx_msg void OnUpdatePage(CCmdUI *pCmdUI);
Add the following to the application message map:
ON_UPDATE_COMMAND_UI(ID_INDICATOR_PAGE, OnUpdatePage)
Add the following to a source code file (probably MAINFRM.CPP):
void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
}
To display text in the panes, either call SetPaneText() or call CCmdUI::SetText() in the OnUpdate() function. For example, you might want to set up an integer variable m_nPage that contains the current page number. Then, the OnUpdatePage() function might read as follows:
void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
char szPage[16];
wsprintf((LPSTR)szPage, "Page %d", m_nPage);
pCmdUI->SetText((LPSTR)szPage);
}
This technique causes the page number to appear in the pane during idle processing in the same manner that the application updates other indicators.
89. 動态修改對話框的大小
[問題提出]
關于如何動态改變對話框的大小,我做了個Demo,大家看看.
[程式實作]
//本函數使用方法:
//第一個參數:如果是TRUE表示顯示擴充的對話框,如果是FALSE,表示縮小對話框。
//第二個參數:表示本對話框的HWND,
//第三個參數:表示縮小後大小的控件的ID
void COptionDlg::ExpandBox(BOOL fExpand, HWND hwnd, int nIDDefaultBox)
{
CWnd *pWndBox=GetDlgItem(nIDDefaultBox);
RECT rcDefaultBox,rcChild,rcIntersection,rcWnd;
pWndBox->GetWindowRect(&rcDefaultBox);
HWND hwndChild = ::GetTopWindow(hwnd);
for (; hwndChild != NULL; hwndChild = ::GetNextWindow(hwndChild,GW_HWNDNEXT))
{
::GetWindowRect(hwndChild, &rcChild);
if (!IntersectRect(&rcIntersection, &rcChild, &rcDefaultBox))
::EnableWindow(hwndChild, fExpand);
}
::GetWindowRect(hwnd, &rcWnd);
if (GetWindowLong(hwnd, GWL_USERDATA) == 0)
{
SetWindowLong(hwnd, GWL_USERDATA,
MAKELONG(rcWnd.right - rcWnd.left,
rcWnd.bottom - rcWnd.top));
::ShowWindow(pWndBox->m_hWnd, SW_HIDE);
}
::SetWindowPos(hwnd, NULL, 0, 0,
rcDefaultBox.right - rcWnd.left,
rcDefaultBox.bottom - rcWnd.top,
SWP_NOZORDER | SWP_NOMOVE);
if(fExpand)
{
DWORD dwDims = GetWindowLong(hwnd, GWL_USERDATA);
::SetWindowPos(hwnd, NULL, 0, 0,
LOWORD(dwDims), HIWORD(dwDims), SWP_NOZORDER | SWP_NOMOVE);
::SendMessage(hwnd, DM_REPOSITION, 0, 0);
}
}
90. 用DoModal()調用模态對話框,總是顯示在正中,我重載了它,并添加了MoveWindow(),可是其m_hWnd是一串零,調用失敗。請問有何方法可使調用的模态對話框顯示于自定義位置?多謝
我不清楚你把MoveWindow()加在什麼地方了,正确的方法是在OnInitDialog中添加MoveWindow,如:
MoveWindow(0, 1, 300, 200);
需要注意的是前兩個參數不能都為0。如果你确實希望把視窗放在(0, 0)處,可以在對話框設計視窗的屬性中選中Absolute Align,然後再加入
MoveWindow(0, 0, 300, 200);
為什麼會是這樣?你看了MFC的源程式就會明白。原來MFC在調用你的OnInitDialog之後,會調用CDialog::CheckAutoCenter()(