Visual C++ 编程技巧之三和四

本文介绍MFC中窗口和对话框的各种实用技巧,包括创建特定类型的窗口、调整窗口属性、实现窗口移动及大小调整等功能,同时也涵盖了对话框背景颜色设定等细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



17、如何创建一个字回绕的CEditView
18、通用控件的显示窗口
19、移动窗口
20、重置窗口的大小
21、如何单击除了窗口标题栏以外的区域使窗口移动
22、如何改变视窗的背景颜色
23、如何改变窗口标题
24、如何防止主框窗口在其说明中显示活动的文档名
25、如何获取有关窗口正在处理的当前消息的信息
26、如何创建一个不规则形状的窗口
27、如何在代码中获取工具条和状态条的指针
28、如何使能和禁止工具条的工具提示
29、如何设置工具条标题
30、如何创建和使用无模式对话框
31、如何在对话框中显示一个位图
32、如何改变对话或窗体视窗的背景颜色

17、如何创建一个字回绕的CEditView  
 
重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设置cs. style,调用基类函数后要修改cs . style

BOOL CSampleEDitView::PreCreateWindow (CREATESTRUCT&cs)  
{  
    //First call basse class function .  
    BOOL bResutl =CEditView : : PreCreateWindow (cs) ; 
    // Now specify the new window style .  
    cs.style &= ~ (ES_AUTOHSCROLL|WS_HSCROLL);  
    return bResult ;  
}  


18、通用控件的显示窗口  
MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。  
 
19、移动窗口   
调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用

SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER);  

 
20、重置窗口的大小   
调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。 

CRect reWindow ;  
GetWindowRect (&reWindow );  
//Make the window twice as wide and twice as tall .  
SetWindowPos (NULL,0,0 ,reWindow.Width()*2,reWindow.Height() * 2,SWP_NOMOVE|SWP_NOZORDER );   
 
21、如何单击除了窗口标题栏以外的区域使窗口移动   
当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。

LRESULT C***Dlg::OnNcHitTest(CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	UINT nHitTest=CDialogEx::OnNcHitTest(point);
	if (nHitTest==HTCLIENT)
		nHitTest=HTCAPTION;	
	return nHitTest;
}


 
上述技术有两点不利之处, 其一是在窗口的客户区域双击时, 窗口将极大;  
其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。  
void CSampleView::OnLButtonDown (UINT nFlags , CPoint point )  
{  
    CView::OnLButtonDown (nFlags,point );  
	//Fool frame window into thinking somene clicked on its caption bar .  
	GetParentFrame()->PostMessage ( WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (point .x , point .y) );  
} 


该技术也适用于对话框和基于对的应用程序,只是不必调用CWnd::GetParentFrame 。  
 
22、如何改变视窗的背景颜色  
Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。  

BOOL CPlayNewDlg::OnEraseBkgnd(CDC* pDC)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	// Create a pruple brush.  
	CBrush Brush (RGB(199,237,204));  
	// Select the brush into the device context .  
	CBrush* pOldBrush = pDC->SelectObject(&Brush);  
	// Get the area that needs to be erased .  
	CRect reClip ;  
	pDC->GetClipBox(&reClip);  
	//Paint the area.  
	pDC->PatBlt(reClip.left,reClip.top,reClip.Width(),reClip.Height(),PATCOPY);  
	//Unselect brush out of device context .  
	pDC->SelectObject (pOldBrush );  
	// Return nonzero to half fruther processing .  
	return TRUE;  
	//return CDialogEx::OnEraseBkgnd(pDC);
}


23、如何改变窗口标题  
 
调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。 
//Set title for application's main frame window .  
AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") );   
//Set title for View's MDI child frame window .  
GetParentFrame ( ) —> SetWindowText (_T ("MDI Child Frame new title") );   
//Set title for dialog's push button control.  
GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") );  

如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。  
AfxSetWindowText的实现如下:  
void AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )  
{  
	int nNewLen= Istrlen (Ipaznew);  
	TCHAR szOld [256];  
	//fast check to see if text really changes (reduces flash in the controls )  
	if (nNewLen >_countof(szOld)||::GetWindowText (hWndCtrl,szOld,_countof (szOld) !=nNewLen||Istrcmp (szOld , IpszNew )! = 0 ) 
	{  
		//change it  
		::SetWindowText (hWndCtrl , IpszNew );  
	}  
} 


 
24、如何防止主框窗口在其说明中显示活动的文档名   
创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位, 如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。  
BOOL CMainFrame::PreCreateWindow (CREATESTRUCT &cs)  
{  
	//Turn off FWS_ADDTOTITLE in main frame .  
	cs.style & = ~FWS_ADDTOTITLE ; 
	return CMainFrame::PreCreateWindow (cs);  
}  

关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。   
 

25、如何获取有关窗口正在处理的当前消息的信息   
调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。  

void CMainFrame::OnCommmonMenuHandler() 
{  
	//Display selected menu item in debug window .  
	TRACE ("Menu item %u was selected . /n",GetCurrentMessage()->wParam);  
}  

 
26、如何创建一个不规则形状的窗口   
可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。 给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。   

Class CRoundDlg::public CDialog  
{  
	…  
private :  
	CRgn m_rgn : // window region  
	…  
} ;  

 
修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口:  
 

BOOL CRoundDlg::OnInitDialog()
{  
    CDialog::OnInitDialog();  
	//Get size of dialog .  
	CRect rcDialog ;  
	GetClientRect(&rcDialog);  
	// Create region and assign to window .  
	m_rgn.CreateEllipticRgn (0,0,rcDialog.Width(), rcDialog .Height());  
	SetWindowRgn (GetSafeHwnd(),(HRGN) m_rgn,TRUE );  
	return TRUE ;  
}  

 
通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体。  

CPaintDC dc(this);
	//draw ellipse with out any border 
	dc.SelectStockObject ( NULL_PEN ); 
	//get the RGB colour components of the sphere color 
	COLORREF color = RGB ( 0 , 0 , 255 ); 
	BYTE byRed = GetRValue ( color ); 
	BYTE byGreen = GetGValue ( color ); 
	BYTE byBlue = GetBValue ( color ); 
	// get the size of the view window 
	CRect rect ; 
	GetClientRect ( rect ); 
	// get minimun number of units 
	int nUnits = min ( rect.right , rect.bottom ); 
	//calculate he horiaontal and vertical step size 
	float fltStepHorz = ( float ) rect.right / nUnits ; 
	float fltStepVert = ( float ) rect.bottom / nUnits ; 
	int nEllipse = nUnits / 3; // calculate how many to draw 
	int nIndex ; // current ellipse that is being draw 
	CBrush brush ; // bursh used for ellipse fill color 
	CBrush *pBrushOld; // previous brush that was selected into dc 
	//draw ellipse , gradually moving towards upper-right corner 
	for ( nIndex = 0 ; nIndex< + nEllipse ; nIndex ++ ) 
	{ 
		//creat solid brush 
		brush . CreateSolidBrush ( RGB( ( ( nIndex *byRed ) / nEllipse ), 
			( ( nIndex * byGreen ) / nEllipse ), ( ( nIndex * byBlue ) / nEllipse ) ) ); 
		//select brush into dc 
		pBrushOld = dc .SelectObject ( &brush ); 
		//draw ellipse 
		dc .Ellipse ( ( int ) fltStepHorz * 2, ( int ) fltStepVert * nIndex , 
			rect. right - ( ( int ) fltStepHorz * nIndex ) + 1, 
			rect . bottom - ( ( int ) fltStepVert * ( nIndex *2 ) ) + 1 ) ; 
		//delete the brush 
		brush.DeleteObject(); 
	} 


 最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。  

UINT CRoundDlg : :OnNchitTest ( Cpoint point ) 
{ 
    //Let user move window by clickign anywhere on the window . 
    UINT nHitTest = CDialog : :OnNcHitTest ( point ) ; 
    return ( nHitTest = = HTCLIENT ) ? HTCAPTION : nHitTest ; 
}  

 
27、如何在代码中获取工具条和状态条的指针   
缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针:  

// Get the size of the window . 
//Get pointer to status bar .  
CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STUTUS_BAR);  
//Get pointer to toolbar .  
CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd()->GetDescendantWindow (AFX_IDW_TOOLBAR);  

 
28、如何使能和禁止工具条的工具提示   
如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle 和CControlBar : : SetBarStyle建立一个完成此功能的成员函数:   
void CMainFrame::EnableToolTips ( BOOL bDisplayTips )  
{  
	ASSERT_VALID (m_wndToolBar);  
	DWORD dwStyle = m_wndToolBar.GetBarStyle() ;  
	if (bDisplayTips)  
		dwStyle|=CBRS_TOOLTIPS ;  
	else  
		dwStyle &=~ CBRS_TOOLTIPS ;  
	m_wndToolBar.SetBarStyle (dwStyle);  
}  

   
29、如何设置工具条标题   
工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下:

int CMainFrame::OnCreate (LPCREATESTRUCT lpCreateStruct )  
{  
		// Set the caption of the toolbar .  
		m_wndToolBar.SetWindowText(_T ("Standdard"));  
}

  
 
30、如何创建和使用无模式对话框   
MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。   

void CSampleDialog::OnOK()
{  
	// Retrieve and validate dialog data .  
	if (! UpdateData(TRUE))  
	{  
		// the UpdateData rountine will set focus to correct item  
		TRACEO(" UpdateData failed during dialog termination ./n") ;  
		return ;  
	}  
	//Call DestroyWindow instead of EndDialog .  
	DestroyWindow(); 
}  

void CSampleDialog::OnCancel() 
{  
	//Call DestroyWindow instead of EndDialog .  
	DestroyWindow();  
}  

 
其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。  
 

void CSampleDialog::PostNcDestroy ( )  
{  
	// Declete the C++ object that represents this dialog .  
	delete this ;  
} 

 
最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放, 要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明了应用程序是如何创建无模式对话的:

void CMainFrame::OnSampleDialog()
{  
	//Allocate a modeless dialog object .  
	CSampleDilog * pDialog =new CSampleDialog ;  
	ASSERT_VALID (pDialog) ;  
	//Create the modeless dialog .  
	BOOL bResult = pDialog->Create(IDD_IDALOG) ;  
	ASSERT (bResult ) ;  
}   


  
 
31、如何在对话框中显示一个位图   
这要归功于Win 32先进的静态控件和Microsoft的资源编辑器, 在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。  
 
32、如何改变对话或窗体视窗的背景颜色   
调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。   

SetDialogBkColor(RGB (0, 0, 255 ),RGB ( 255 , 255 , 0 ) ) ;

 
需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,通常用户可以让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。   
首先,给对话基类增加一人成员变量CBursh 
 
其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。
    m_brush .CreateSolidBrush (RGB ( 00255 ) ) ; 
   
最后,使用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 );  
}  


 见22:Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。  

BOOL CPlayNewDlg::OnEraseBkgnd(CDC* pDC)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	// Create a pruple brush.  
	CBrush Brush (RGB(199,237,204));  
	// Select the brush into the device context .  
	CBrush* pOldBrush = pDC->SelectObject(&Brush);  
	// Get the area that needs to be erased .  
	CRect reClip ;  
	pDC->GetClipBox(&reClip);  
	//Paint the area.  
	pDC->PatBlt(reClip.left,reClip.top,reClip.Width(),reClip.Height(),PATCOPY);  
	//Unselect brush out of device context .  
	pDC->SelectObject (pOldBrush );  
	// Return nonzero to half fruther processing .  
	return TRUE;  
	//return CDialogEx::OnEraseBkgnd(pDC);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值