Visual C++
编程技巧
整理
Ackarlix
1.
如何获取应用程序的实例句柄
?
应用程序的 实例句柄保存在
CWinAppIm_hInstance
中
,
可以这么调用
AfxGetInstancdHandle
获得句柄
.
Example: HANDLE hInstance=AfxGetInstanceHandle();
2.
如何通过代码获得应用程序主窗口的指针
?
主窗口的 指针保存在
CWinThread::m_pMainWnd
中
,
调用
AfxGetMainWnd
实现。
AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //
使程序最大化
.
3.
如何在程序中获得其他程序的图标
?
两种方法
:
(1) SDK
函数
SHGetFileInfo
或使用
ExtractIcon
获得图标资源的
handle,
(2) SDK
函数
SHGetFileInfo
获得有关文件的 很多信息
,
如大小图标
,
属性
,
类型等
.
Example(1):
在程序窗口左上角显示
NotePad
图标
.
void CSampleView: OnDraw(CDC * pDC)
{
if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0,
&stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
{
pDC ->DrawIcon(10,10,stFileInfo.hIcon);
}
}
Example(2):
同样功能
,Use ExtractIcon Function
void CSampleView:: OnDraw(CDC *pDC)
{
HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T
("NotePad.exe"),0);
if (hIcon &&hIcon!=(HICON)-1)
pDC->DrawIcon(10,10,hIcon);
}
说明
:
获得
notepad.exe
的路径正规上来说用
GetWindowsDirectory
函数得到
,
如果是调用
win95
下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点
.
4.
如何编程结束应用程序
?
如何编程控制
windows
的重新引导
?
这是个很简单又是编程中经常要遇到的问题
.
第一问
,
向窗口发送
WM_CLOSE
消息
,
调用
CWnd::OnClose
成员函数
.
允许对用户提示
是否保存修改过的数据
.
Example: AfxGetMainWindow()->SendMessage(WM_CLOSE);
还可以创建一个自定义的函数
Terminate Window
void Terminate Window(LPCSTR pCaption)
{
CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption);
if (pWnd)
pWnd ->SendMessage(WM_CLOSE);
}
说明
: FindWindow
函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测
Notepad
是不是已运行而事先不知道
Notepad
的标题栏
,
这时
FindWindow
就无能为力了,可以通过枚举
windows
任务列表的办法来实现。 在 机械出版社
"Windows 95 API
开发人员指南
"
一书有比较详细的介绍
,
这里就不再多说乐。
第二问
,Use ExitWindowsEx Function
函数控制系统是重新引导,还是重启
windows.
前面已经有人讲过乐,就不再提了。
5.
怎样加栽其他的应用程序
?
我记得这好象是出场频度很高的问题。
三个
SDK
函数
winexec, shellexecute,createprocess
可以使用。
WinExec
最简单,两个参数,前一个指定路径,后一个指定显示方式
.
后一个参数值得说一下,比如泥用
SW_SHOWMAXMIZED
方式去加栽一个无最大化按钮的 程序,呵呵就是
Neterm,calc
等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。
ShellExecute
较
WinExex
灵活一点,可以指定工作目录
,
下面的
Example
就是直接打开
c:/temp/1.txt,
而不用加栽与
txt
文件关联的应用程序
,
很多安装程序完成后都会打开一个窗口,来显示
Readme or Faq,
偶猜就是这么作的啦
.
ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c://temp"),SW_SHOWMAXMIZED);
CreateProcess
最复杂,一共有十个参数,不过大部分都可以用
NULL
代替,它可以指定进程的安全属性,继承信息,类的优先级等等
.
来看个很简单的
Example:
STARTUPINFO stinfo; //
启动窗口的信息
PROCESSINFO procinfo; //
进程的信息
CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_
CLASS,NULL,NULL, &stinfo,&procinfo);
6.
确定应用程序的路径
前些天好象有人问过这个问题
.
Use GetModuleFileName
获得应用程序的路径,然后去掉可执行文件名。
Example:
TCHAR exeFullPath[MAX_PATH]; // MAX_PATH
在
API
中定义了吧,好象是
128
GetModuleFileName(NULL,exeFullPath,MAX_PATH)
7.
获得各种目录信息
Windows
目录
: Use "GetWindowsDirectory
“
Windows
下的
system
目录
: Use "GetSystemDirectory"
temp
目录
: Use "GetTempPath "
当前目录
: Use "GetCurrentDirectory"
请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区
;
后两个相反
.
8.
如何自定义消息
也有人问过的,其实不难。
(1)
手工定义消息,可以这么写
#define WM_MY_MESSAGE(WM_USER+100),
MS
推荐的至少是
WM_USER+100;
(2)
写消息处理函数
,
用
WPARAM,LPARAM
返回
LRESULT.
LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)
{
//
加入你的处理函数
}
(3)
在类的
AFX_MSG
处进行声明,也就是常说的
"
宏映射
"
9.
如何改变窗口的图标
?
向窗口发送
WM_SECTION
消息。
Example:
HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon);
10.
如何改变窗口的缺省风格
?
重栽
CWnd:: PreCreateWindow
并修改
CREATESTRUCT
结构来指定窗口风格和其他
创建信息
.
Example: Delete "Max" Button and Set Original Window's Position and Size
BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs)
{
cs.style &=~WS_MAXINIZEMOX;
cs.x=cs.y=0;
cs.cx=GetSystemMetrics(SM_CXSCREEN/2);
cs.cy=GetSystemMetrics(SM_CYSCREEN/2);
return CMDIFramewnd ::PreCreateWindow(cs);
}
11.
如何将窗口居中显示
?
Easy, Call Function CWnd:: Center Windows
Example(1): Center Window( ); //Relative to it's parent
// Relative to Screen
Example(2): Center Window(CWnd:: GetDesktopWindow( ));
//Relative to Application's MainWindow
AfxGetMainWnd( ) -> Center Window( );
12.
如何让窗口和
MDI
窗口一启动就最大化和最小化
?
先说窗口。
在
InitStance
函数中设定
m_nCmdShow
的 取值
.
m_nCmdShow=SW_SHOWMAXMIZED ; //
最大化
m_nCmdShow=SW_SHOWMINMIZED ; //
最小化
m_nCmdShow=SW_SHOWNORMAL ; //
正常方式
MDI
窗口
:
如果是创建新的应用程序
,
可以用
MFC AppWizard
的
Advanced
按钮并在
MDI
子窗口风格组中检测最大化或最小化
;
还可以重载
MDI Window
的
PreCreateWindow
函数,设置
WS_MAXMIZE or WS_MINMIZE;
如果从
CMDIChildWnd
派生
,
调用
OnInitialUpdate
函数中的
CWnd::Show
Window
来指定
MDI Child Window
的 风格。
13.
如何使程序保持极小状态
?
很有意思的 问题
这么办
:
在恢复程序窗体大小时,
Windows
会发送
WM_QUERY-OPEN
消息,
用
ClassWizard
设置成员函数
OnQueryOpen() ,add following code:
Bool CMainFrame:: OnQueryOpen( )
{
Return false;
}
14.
如何限制窗口的大小
?
也就是
FixedDialog
形式。
Windows
发送
WM_GETMAXMININFO
消息来跟踪
,
响应它
,
在
OnGetMAXMININFO
中写代码
:
15.
如何使窗口不可见?
很简单
,
用
SW_HIDE
隐藏窗口,可以结合
FindWindow,ShowWindow
控制
.
16.
如何使窗口始终在最前方
?
两种途径
.
BringWindowToTop(Handle);
SetWindowPos
函数,指定窗口的 最顶风格
,
用
WS_EX_TOPMOST
扩展窗口的 风格
Example:
void ToggleTopMost( CWnd *pWnd)
{
ASSERT_VALID(pWnd);
pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?
&wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE);
}
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
标志。目的位置与父窗口
有关(顶层窗口与屏幕有关)。调用
CWnd : : MoveWindow
时必须要指定窗口
的大小。
//Move window to positoin 100 , 100 of its parent window .
SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE
|
SWP_NOAORDER);
20
、重置窗口的大小
调用
CWnd: : SetWindowPos
并指定
SWP_NOMOVE
标志, 也可调用
CWnd : : MoveWindow
但必须指定窗口的位置。
// Get the size of the window .
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
的标题栏中。
UINT CSampleDialog : : OnNcHitTest (Cpoint point )
{
UINT nHitTest =Cdialog: : OnNcHitTest (point );
return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest ;
}
上述技术有两点不利之处, 其一是在窗口的客户区域双击时, 窗口将极大;
其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键
使主框窗口认为鼠标在其窗口标题上,使用
ClassWizard
在视窗中处理
WM_LBUTTODOWN
信息并向主框窗口发送一个
WM_NCLBUTTONDOWN
信息和一个单击测试
HTCAPTION
。
void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point )
{
CView : : OnLButtonDow (nFlags , pont );
//Fool frame window into thinking somene clicked on
its caption bar .
GetParentFrame ( )
—
> PostMessage (
WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) );
}
该技术也适用于对话框和基于对的应用程序,只是不必调用
CWnd : : GetParentFrame
。
void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point )
{
Cdialog : : OnLButtonDow (nFlags, goint );
//Fool dialog into thinking simeone clicked on its caption bar .
PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) )
}
22
、如何改变视窗的背景颜色
Windows
向窗口发送一个
WM_ERASEBKGND
消息通知该窗口擦除背景,可以使用
ClassWizard
重载该消息的缺省处理程序来擦除背景(实际是画),并返回
TRUE
以
防止
Windows
擦除窗口。
//Paint area that needs to be erased.
BOOL CSampleView : : OnEraseBkgnd (CDC* pDC)
{
// Create a pruple brush.
CBrush Brush (RGB (128 , 0 , 128) );
// Select the brush into the device context .
CBrush* pOldBrush = pDC
—
>SelcetObject (&brush);
// Get the area that needs to be erased .
CRect reClip ;
pDC
—
>GetCilpBox (&rcClip);
//Paint the area.
pDC
—
> PatBlt (rcClip.left , rcClip.top ,
rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY );
//Unselect brush out of device context .
pDC
—
>SelectObject (pOldBrush );
// Return nonzero to half fruther processing .
return TRUE;
}
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
的实现如下:
voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )
{
itn nNewLen= Istrlen (Ipaznew);
TCHAR szOld [256];
//fast check to see if text really changes (reduces flash in the controls )
if (nNewLen >_contof (szOld)
||
: : GetWindowText (hWndCrtl , 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.styel & = ~FWS_ADDTOTITLE ;
return CMDIFrameWnd : : PreCreateWindow (cs );
}
关闭
MDI
子窗口的
FWS _ADDTOTITLE
风格将创建一个具有空标题的窗口,可以调
用
CWnd: : SetWindowText
来设置标题。记住自己设置标题时要遵循接口风格指南。
25
、如何获取有关窗口正在处理的当前消息的信息
调用
CWnd: : GetCurrentMessage
可以获取一个
MSG
指针。例如,可以使用
ClassWizard
将几个菜单项处理程序映射到一个函数中,然后调用
GetCurrentMessage
来确定所选中的菜单项。
viod CMainFrame : : OnCommmonMenuHandler ( )
{
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . /n" ,
GetCruuentMessage ( )
—
> 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
函数使窗口形状看起来象一个球形体。
voik CRoundDlg : : OnPaint ( )
{
CPaintDC de (this) ; // device context for painting .
//draw ellipse with out any border
dc. SelecStockObject (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 ; nIndes < + nEllipse ; nIndes ++)
{
//creat solid brush
brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ).
( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) );
//select brush into dc
pBrushOld= dc .SelectObject (&brhsh);
//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.DelecteObject ( );
}
}
最后,处理
WM_NCHITTEST
消息,使当击打窗口的任何位置时能移动窗口。
UINT CRoundDlg : : OnNchitTest (Cpoint point )
{
//Let user move window by clickign anywhere on the window .
UINT nHitTest = CDialog : : OnNcHitTest (point) ;
rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ;
}
27
、如何在代码中获取工具条和状态条的指针
缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条
有一个
AFX_IDW_STATUS_BAR
标识符,工具条有一个
AFX_IDW_TOOLBAR
标识符,下例说
明了如何通过一起调用
CWnd: : GetDescendantWindow
和
AfxGetMainWnd
来获取这些
子窗口的指针:
//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
—
> Creste (IDD_IDALOG) ;
ASSERT (bResult ) ;
}
31
、如何在对话框中显示一个位图
这要归功于
Win 32
先进的静态控件和
Microsoft
的资源编辑器, 在对话框中显示位图是很容易的,只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。
32
、如何改变对话或窗体视窗的背景颜色
调用
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 );
}
33
、如何获取一个对话控件的指针
有两种方法。其一,调用
CWnd: : GetDlgItem
,获取一个
CWnd*
指针调用成员函数。下例调用
GetDlgItem
,将返回值传给一个
CSpinButtonCtrl*
以便调用
CSpinButtonCtrl : : SetPos
函数:
BOOL CSampleDialog : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//Get pointer to spin button .
CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem (IDC_SPIN) ;
ASSERT _ VALID (pSpin) ;
//Set spin button's default position .
pSpin
—
> SetPos (10) ;
return TRUE ;
}
其二, 可以使用
ClassWizard
将控件和成员变量联系起来。在
ClassWizard
中简单地选择
Member Variables
标签,然后选择
Add Variable
…
按钮。如果在对话资源编辑器中,按下
Ctrl
键并双击控件即可转到
Add Member Variable
对话。
34
、如何禁止和使能控件
控件也是窗口,所以可以调用
CWnd : : EnableWindow
使能和禁止控件。
//Disable button controls .
m_wndOK.EnableWindow (FALSE ) ;
m_wndApply.EnableWindow (FALSE ) ;
35
、如何改变控件的字体
由于控件是也是窗口,用户可以调用
CWnd: : SetFont
指定新字体。该函数用一个
Cfont
指针,要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字体改为
8
点
Arial
字体:
//Declare font object in class declaration (.H file ).
private :
Cfont m_font ;
// Set font in class implementation (.Cpp file ). Note m_wndButton is a
//member variable added by ClassWizard.DDX routines hook the member
//variable to a dialog button contrlo.
BOOL CSampleDialog : : OnInitDialog ( )
{
…
//Create an 8-point Arial font
m_font . CreateFont (MulDiv (8 , -pDC
—
> GetDeviceCaps (LOGPIXELSY) , 72).
0 , 0 , 0 , FW_NORMAL , 0 , 0, 0, ANSI_CHARSER, OUT_STROKE_PRECIS ,
CLIP_STROKE _PRECIS , DRAFT _QUALITY
VARIABLE_PITCH
|
FF_SWISS, _T ("Arial") );
//Set font for push button .
m_wndButton . SetFont (&m _font );
…
}
36
、如何在
OLE
控件中使用
OLE_COLOR
数据类型
诸如
COleControl : : GetFortColor
和
COleControl : : GetBackColor
等函数返回
OLE _COLOR
数据类型的颜色,而
GDI
对象诸如笔和刷子使用的是
COLORREF
数据类型,调用
COleControl : : TranslateColor
可以很容易地将
OLE_COLOR
类型改为
COLORREF
类型。下例创建了一个当前背景颜色的刷子:
void CSampleControl : : OnDraw (CDC* pdc
const Crect& rcBounds , const Crect& rcInvalid )
{
//Create a brush of the cuttent background color .
CBrush brushBack (TranslateColor (GetBackColor ( ) ) );
//Paint the background using the current background color .
pdc
—
> FilllRect (rcBounds , &brushBack) ;
//other drawign commands
…
}
37
、在不使用通用文件打开对话的情况下如何显示一个文件列表
调用
CWnd: : DlgDirList
或者
CWnd: : DlgDirListComboBox
,
Windows
将自动地向列表框或组合框填充可用的驱动器名或者指定目录中的文件,下例将
Windows
目录中的文件填充在组合框中:
BOOL CSampleDig : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( )
TCHAR szPath [MAX_PATH] = {"c://windows"} ;
int nReslt = DlgDirListComboBox (szPath , IDC_COMBO , IDC_CURIDIR,
DDL_READWRITE
|
DDL_READONLY
|
DDL_HIDDEN
|
DDL_SYSTEM
|
DDL_ARCHIVE ) ;
return TRUE ;
}
38
、为什么旋转按钮控件看起来倒转
需要调用
CSpinCtrl : : SetRange
设置旋转按钮控件的范围,旋转按钮控件的缺省上限为
0
,缺省下限为
100
,这意味着增加时旋转按控件的值由
100
变为
0
。下例将旋转按钮控件的范围设置为
0
到
100
:
BOOL CAboutDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( )
//set the lower and upper limit of the spin button
m_wndSpin . SetRange ( 0 ,100 ) ;
return TRUE ;
}
Visual C++ 4.0 Print
对话中的
Copise
旋转按钮控件也有同样的问题:按下
Up
按钮时拷贝的数目减少,而按下
Down
按钮时拷贝的数目增加。
39
为什么旋转按钮控件不能自动地更新它下面的编辑控件
如果使用旋转按钮的
autu buddy
特性, 则必须保证在对话的标记顺序中
buddy
窗口优先于旋转按钮控件。从
Layout
菜单中选择
Tab Order
菜单项(或者按下
Crtl+D
)可以设置对话的标签顺序。
40
、如何用位图显示下压按钮
Windows 95
按钮有几处新的创建风格,尤其是
BS_BITMAP
和
BS_ICON
,要想具有位图按钮,创建按钮和调用
CButton : : SetBitmap
或
CButton : : SetIcon
时要指定
BS_BITMAP
或
BS_ICON
风格。
首先,设置按钮的图标属性。
然后,当对话初始化时调用
CButton: : SetIcon
。注意:下例用图标代替位图,使用位图时要小心,因为不知道背景所有的颜色——并非每个人都使用浅灰色。
BOOL CSampleDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
//set the images for the push buttons .
m_wndButton1.SetIcon (AfxGetApp ( )
—
> LoadIcon (IDI _ IPTION1) )
m_wndButton2.SetIcon (AfxGetApp ( )
—
> LoadIcon (IDI _ IPTION2) )
m_wndButton3.SetIcon (AfxGetApp ( )
—
> LoadIcon (IDI _ IPTION3) )
return TRUE ;
}
41
、如何一个创建三态下压按钮
可以使用新的
BS_PUSHBUTTON
风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性
Push
—
like
即可。不用任何附加程序就可以成为三态下压按钮。
42
、如何动态创建控件
分配一个控件对象的实例并调用其
Create
成员函数。开发者最容易忽略两件事:忘记指定
WS_VISBLE
标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件:
//In class declaration (.H file ).
private :
CButton* m _pButton ;
//In class implementation (.cpp file ) .
m_pButton =new CButton ;
ASSERT_VALID (m_pButton);
m_pButton
—
>Create (_T ("Button Title ") , WS_CHILD
|
WS_VISIBLE
|
BS_PUSHBUTTON.
Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )
43
、如何限制编辑框中的准许字符
如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志
ES_NUMBERS,
它是
Windows 95
新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件,可以使用
Microsoft
的屏蔽编辑控件,它是一个很有用的
OLE
定制控件。
如果希望不使用
OLE
定制控件自己处理字符,可以派生一个
CEdit
类并处理
WM_CHAR
消息,然后从编辑控件中过滤出特定的字符。首先,使用
ClassWizard
建立一个
CEdit
的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在
OnInitdialog
中调用
CWnd: : SubclassDlgItem .
//In your dialog class declaration (.H file )
private :
CMyEdit m_wndEdit ; // Instance of your new edit control .
//In you dialog class implementation (.CPP file )
BOOL CSampleDialog : : OnInitDialog ( )
{
…
//Subclass the edit lontrod .
m_wndEdit .SubclassDlgItem (IDC_EDIT,this );
…
}
使用
ClassWizard
处理
WM_CHAR
消息,计算
nChar
参量并决定所执行的操作,用户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用
CWnd ; OnChar
,否则不调用
OnChar.
//Only display alphabetic dharacters .
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )
{
//Determine if nChar is an alphabetic character .
if (: : IsCharAlpha ( ( TCHAR) nChar ) )
CEdit : : OnChar (nChar, nRepCnt , nFlags );
}
如果要修改字符,则不能仅仅简单地用修改过的
nChar
调用
CEdit : : OnChar
,然后
CEdit: : OnChar
调用
CWnd: : Default
获取原来的
wParam
和
lParam
的值 ,这样是不行的。要修改一个字符,需要首先修改
nChar
,然后用修改过的
nChar
调用
CWnd: : DefWindowProc
。下例说明了如何将字符转变为大写:
//Make all characters uppercase
void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )
{
//Make sure character is uppercase .
if (: : IsCharAlpha ( .( TCHAR) nChar)
nChar=: : CharUpper (nChar ) ;
//Bypass default OnChar processing and directly call
//default window proc.
DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;
}
44
、如何改变控件的颜色
有两种方法。其一,可以在父类中指定控件的颜色,或者利用
MFC4.0
新的消息反射在控件类中指定颜色。当控件需要重新着色时,工作框调用父窗口(通常是对话框)的
CWnd: : OnCrtlColor,
可以在父窗口类中重置该函数并指定控件的新的绘画属性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色:
HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor)
{
HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor );
//Draw red text for all edit controls .
if (nCtlColor= = CTLCOLOR_EDIT )
pDC
—
> SetTextColor (RGB (255 , 0 , 0 , ) ) ;
return hbr ;
}
然而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以,这种方法不是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。消息反射允许用户这样做。通知消息首先发送给父窗口,如果父窗口没有处理则发送给控件。创建一个定制彩色列表框控件必须遵循下述步骤。
首先,使用
ClassWizard
创建一个
CListBox
的派生类并为该类添加下述数据成员。
class CMyListBox ; publilc CListBox
{
…
private;
COLORREF m_clrFor ; // foreground color
COLORREF m_clrBack ; //background color
Cbrush m_brush ; //background brush
…
} ;
其次,在类的构造函数中,初始化数据中。
CMyListBox : : CMyListBox ()
{
//Initialize data members .
m_clrFore =RGB (255 , 255 , 0) ; // yellow text
m_clrBack=RGB (0 , 0 , 255) ; // blue background
m_brush . CreateSolidBrush (m _clrBack );
}
最后,使用
ClassWizard
处理反射的
WM_CTLCOLOR(=WM_CTLCOLOR)
消息并指定新的绘画属性。
HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor )
{
pDC
—
>SetTextColor (m_clrFore);
pDC
—
>SetBkColor (m_clrBack);
return (HBRUSH) m_brush.GetSafeHandle ()
}
现在,控件可以自己决定如何绘画,与父窗口无关。
45
、当向列表框中添加多个项时如何防止闪烁
调用
CWnd::SetRedraw
清除重画标志可以禁止
CListBox
(或者窗口)重画。当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画标志。为确保重画列表框的新项,调用
SetRedraw (TRUE)
之后调用
CWnd::Invalidate
。
//Disable redrawing.
pListBox->SetRedraw (FALSE);
//Fill in the list box gere
//Enable drwing and make sure list box is redrawn.
pListBox->SetRedraw (TRUE);
pListBox->Invalidate ();
46
、如何向编辑控件中添加文本
由于没有
CEdit:: AppendText
函数,用户只好自己做此项工作。调用
CEdit:: SetSel
移动到编辑控件末尾,然后调用
CEdit:: ReplaceSel
添加文本。下例是
AppendText
的一种实现方法:
void CMyEdit:: AppendText (LPCSTR pText)
{
int nLen=GetWindowTextLength ();
SetFocus ();
SetSel (nLen, nLen);
ReplaceSel (pText);
}
47
、如何访问预定义的
GDI
对象
可以通过调用
CDC:: SlectStockObject
使用
Windows
的几个预定义的对象,诸如刷子、笔以及字体。下例使用了
Windows
预定义的笔和刷子
GDI
对象在视窗中画一个椭圆。
//Draw ellipse using stock black pen and gray brush.
void CSampleView:: OnDraw (CDC* pDC)
{
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use stock black pen and stock gray brush to draw ellipse.
pDC->SelectStockObject (BLACK_PEN);
pDC->SelectStockObject (GRAY_BRUSH)
//Draw the ellipse.
pDC->Ellipse (reView);
}
也可以调用新的
SDK
函数
GetSysColorBrush
获取一个系统颜色刷子,下例用背景色在视窗中画一个椭圆:
void CsampleView:: OnDraw (CDC* pDC)
{
//Determine size of view.
CRect rcView;
GetClientRect (rcView);
//Use background color for tooltips brush.
CBrush * pOrgBrush=pDC->SelectObject (
CBrush::FromHandle (::GetSysColorBrush (COLOR_INFOBK)));
//Draw the ellipse.
pDC->Ellipse (rcView);
//Restore original brush.
pDC->SelectObject (pOrgBrush);
}
48
、如何获取
GDI
对象的属性信息
可以调用
GDIObject:: GetObject
。这个函数将指定图表设备的消息写入到缓冲区。下例创建了几个有用的辅助函数。
//Determine if font is bold.
BOOL IsFontBold (const CFont&font)
{
LOGFONT stFont;
font.GetObject (sizeof (LOGFONT), &stFont);
return (stFont.lfBold)? TRUE: FALSE;
}
//Return the size of a bitmap.
CSize GetBitmapSize (const CBitmap&bitmap)
{
BITMAP stBitmap;
bitmap.GetObject (sizeof (BITMAP), &stBitmap);
return CSize (stBitmap.bmWidth, stBitmap. bmHeight);
}
//Create a pen with the same color as a brush.
BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush)
{
LOGBRUSH stBrush;
brush.Getobject (sizeof (LOGBRUSH), &stBrush);
return pen. Createpen (PS_SOLID, 0, stBrush.ibColor);
}
49
、如何实现一个橡皮区矩形
CRectTracker
是一个很有用的类,可以通过调用
CRectTracker:: TrackRubberBand
响应
WM_LBUTTONDOWN
消息来创建一个橡皮区矩形。下例表明使用
CRectTracker
移动和重置视窗中的蓝色椭圆的大小是很容易的事情。
首先,在文件档中声明一个
CRectTracker
数据成员:
class CSampleView : Public CView
{
…
public :
CrectTracker m_tracker;
…
};
其次,在文档类的构造函数中初始化
CRectTracker
对象:
CSampleDoc:: CSampleDOC ()
{
//Initialize tracker position, size and style.
m_tracker.m_rect.SetRect (0, 0, 10, 10);
m_tracker.m_nStyle=CRectTracker:: resizeInside |
CRectTracker:: dottedLine;
}
然后,在
OnDraw
函数中画椭圆和踪迹矩形:
void CSampleView:: OnDraw (CDC* pDC)
{
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Select blue brush into device context.
CBrush brush (RGB (0, 0, 255));
CBrush* pOldBrush=pDC->SelectObject (&brush);
//draw ellipse in tracking rectangle.
Crect rcEllipse;
pDoc->m_tracker.GetTrueRect (rcEllipse);
pDC->Ellipse (rcEllipse);
//Draw tracking rectangle.
pDoc->m_tracker.Draw (pDC);
//Select blue brush out of device context.
pDC->Selectobject (pOldBrush);
}
最后,使用
ClassWizard
处理
WM_LBUTTONDOWN
消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。
void CSampleView::OnLButtonDown (UINT nFlags, CPoint point)
{
//Get pointer to document.
CSampleDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//If clicked on ellipse, drag or resize it. Otherwise create a
//rubber-band rectangle nd create a new ellipse.
BOOL bResult=pDoc->m_tracker.HitTest (point)!=
CRectTracker::hitNothing;
//Tracker rectangle changed so update views.
if (bResult)
{
pDoc->m_tracker.Track (this,point,TRue);
pDoc->SetModifiedFlag ();
pDoc->UpdateAllViews (NULL);
}
else
pDoc->m-tracker.TrackRubberBand (this,point,TRUE);
CView:: onLButtonDown (nFlags,point);
}
50
、如何更新翻转背景颜色的文本
调用
CDC:: SetBkmode
并传送
OPAQUE
用当前的背景颜色填充背景,或者调用
CDC::SetBkMode
并传送
TRANSPAARENT
使背景保持不变,这两种方法都可以设置背景模式。下例设置背景模式为
TRANSPARENT
,可以两次更新串,用花色带黑阴影更新文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determint size of view.
CRect rcView;
GetClientRect (rcVieew);
//Create sample string to display.
CString str (_T ("Awesome Shadow Text
...
"));
//Set the background mode to transparent.
pDC->SetBKMode (TRANSPARENT);
//Draw black shadow text.
rcView.OffsetRect (1, 1);
pDc->SetTextColor (RGB (0, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//Draw red text.
rcView.OffsetRect (-1,-1);
pDc->SetTextColor (RGB (255, 0, 0));
pDC->DrawText (str, str.GetLength (), rcView,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
51
、如何创建一个具有特定点大小的字体
可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一些。可以如下将字体的点转换为字体的高度:
int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72);
下例创建了一个
8
点的
Apial
字体:
CClientDC dc (AqfxGetMainWnd ());
m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY),
72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,
VARIABLE_PITCH | FF-SWISS,_T ("Arial"));
52
、如何计算一个串的大小
函数
CDC:: Det text Extent
根据当前选择的字体计算一个串的高度和宽度。如果使用的不是系统字体而是其他字体,则在调用
GetTextExtent
之前将字体选进设备上下文中是很重要的,否则计算高度和宽度时将依据系统字体,由此得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按钮的大小,按钮的大小由按钮的字体和标题的大小而定。响应消息
WM_SETTEXT
时调用
OnSetText
,该消息使用
ON_MESSAE
宏指令定义的用户自定义消息。
LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam)
{
//Pass message to window procedure.
LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr (),
m_hWnd, GetCurrentMessage () ->message,wParam,lParam);
//Get title of push button.
CString strTitle;
GetWindowText (strTitle);
//Select current font into device context.
CDC* pDC=GetDc ();
CFont*pFont=GetFont ();
CFont*pOldFont=pDC->SelectObject (pFont);
//Calculate size of title.
CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength ());
//Adjust the button's size based on its title.
//Add a 5-pixel border around the button.
SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
//Clean up.
pDC->SelectFont (pOldFont);
ReleaseDC (pDC);
return bResult;
}
53
、如何显示旋转文本
只要用户使用
TrueType
或者
GDI
笔或字体就可以显示旋转文本
(
有些硬件设备也支持旋转光栅字体)。
LOGFONT
结构中的
ifEscapement
成员指定了文本行和
x
轴的角度,角度的单位是十分之一度而不是度,例如,
ifEscapement
为
450
表示字体旋转
45
度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置
ifEscapement
成员的
CLIP_LH_ANGLES
位,否则,有些字体可能反向旋转。下例使用了
14
点
Arial
字体每间隔
15
度画一个串。
void CSampleView:: OnDraw (CDC* pDC)
{
//Determine the size of the window.
CRect rcClient;
GetClientRect (rcClient);
//Create sample string.
CString str (_T ("Wheeee
...
I am rotating!"));
//Draw transparent, red text.
pDC->SetBkMode (TRANSPARENT);
pDC->SetTextColor (RGB (255,0,0));
CFont font; //font object
LOGFONT stFont; //font definition
//Set font attributes that will not change.
memset (&stFont, 0, sizeof (LOGFONT));
stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps (LOGPIXELSY), 72);
stFont.ifWeight=FW_NORMAL;
stFont.ifClipPrecision=LCIP_LH_ANGLES;
strcpy (stFont.lfFaceName, "Arial");
//Draw text at 15degree intervals.
for (int nAngle=0; nAngle<3600; nAngle+=150)
{
//Specify new angle.
stFont.lfEscapement=nAngle;
//Create and select font into dc.
font.CreateFontIndirect (&stfont);
CFont* pOldFont=pDC->SelectObject (&font);
//Draw the text.
pDC->SelectObject (pOldFont);
font.DelectObjext ();
}
}
54
、如何正确显示包含标签字符的串
调用
GDI
文本绘画函数时需要展开标签字符,这可以通过调用
CDC:: TabbedTextOut
或者
CDC:: DrawText
并指定
DT_EXPANDTABS
标志来完成。
TabbedTextOut
函数允许指定标签位的数组,下例指定每
20
设备单位展开一个标签:
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoC);
CString str;
str.Format (_T ("Cathy/tNorman/tOliver"));
int nTabStop=20; //tabs are every 20 pixels
pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10);
}
55
、串太长时如何在其末尾显示一个省略号
调用
CDC:: DrawText
并指定
DT_END_ELLIPSIS
标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定
DT_END_ELLIPSIS
标志并省略号取代串中间的字符。
void CSampleView:: OnDraw (CDC* pDC)
{
CTestDoc* pDoc=GetDocument ();
ASSERT_VALID (pDoc);
//Add ellpsis to end of string if it does not fit
pDC->Drawtext (CString ("This is a long string"),
CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS);
//Add ellpsis to middle of string if it does not fit
pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath,
CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);
}
56
、如何快速地格式化一个
CString
对象
调用
CString:: Format
,该函数和
printf
函数具有相同的参数,下例说明了如何使用
Format
函数:
//Get size of window.
CRect rcWindow;
GetWindowRect (rcWindow);
//Format message string.
CString strMessage;
strMessage.Format (_T ("Window Size (%d, %d)"),
rcWindow.Width (), rcWindow.Height ());
//Display the message.
MessageBox (strmessage);
57
、为什么即使调用
EnableMenuItem
菜单项后,菜单项还处于禁止状态
需要将
CFrameWnd:: m_bAutomenuEnable
设置为
FALSE
,如果该数据成员为
TRUE
(缺省值),工作框将自动地禁止没有
ON_UPDATE_COMMAND_UI
或者
ON_COMMAND
的菜单项。
//Disable MFC from automatically disabling menu items.
m_bAuoMenuEnable=FALSE;
//Now enable the menu item.
CMenu* pMenu=GetMenu ();
ASSERT_VALID (pMenu);
pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED);
58
、如何给系统菜单添加一个菜单项
给系统菜单添加一个菜单项需要进行下述三个步骤:
首先,使用
Resource Symbols
对话(在
View
菜单中选择
Resource Symbols
...
可以显示该对话)定义菜单项
ID
,该
ID
应大于
0x0F
而小于
0xF000
;
其次,调用
CWnd::GetSystemMenu
获取系统菜单的指针并调用
CWnd:: Appendmenu
将菜单项添加到菜单中。下例给系统菜单添加两个新的菜单项:
int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct)
{
…
//Make sure system menu item is in the right range.
ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM);
ASSERT (IDM-MYSYSITEM<0xF000);
//Get pointer to system menu.
CMenu* pSysmenu=GetSystemmenu (FALSE);
ASSERT_VALID (pSysMenu);
//Add a separator and our menu item to system menu.
CString StrMenuItem (_T ("New menu item"));
pSysMenu->Appendmenu (MF_SEPARATOR);
pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem);
…
}
现在,选择系统菜单项时用户应进行检测。使用
ClassWizard
处理
WM_SYSCOMMAND
消息并检测用户菜单的
nID
参数:
void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam)
{
//Determine if our system menu item was selected.
if ( (nID & 0xFFF0)==IDM_MYSYSITEM)
{
//TODO-process system menu item
}
else
CMDIFrameWnd:: OnSysCommand (nID, lParam);
}
最后,一个设计良好的
UI
应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基
ID
的串表的入口来实现。
59
、如何确定顶层菜单所占据的菜单行数
这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。
int CMainFrame:: GetMenuRows ()
{
CRect rcFrame,rcClient;
GetWindowRect (rcFrame);
GetClientRect (rcClient);
return (rcFrame.Height () -rcClient.Height ()-
:: GetSystemMetrics (SM_CYCAPTION) -
(:: getSystemMetrics (SM_CYFRAME) *2)) /
:: GetSystemMetrics (SM_CYMENU);
}
60
、在用户环境中如何确定系统显示元素的颜色
调用
SDK
函数
GetSysColor
可以获取一个特定显示元素的颜色。下例说明了如何在
MFC
函数
CMainFrameWnd:: OnNcPaint
中调用该函数设置窗口标题颜色。
void CMiniFrameWnd:: OnNcPaint ()
{
…
dc.SetTextColor (:: GetSysColor (m_bActive ?
COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
…
}
61
、如何查询和设置系统参数
在
Windows 3.1 SDK
中介绍过
SDK
函数
SystemParametersInfo
,调用该函数可以查询和设置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体以及桌面覆盖位图等等。
//Create a font that is used for icon titles.
LOGFONT stFont;
:: SystemParametersInfo (SPIF_GETICONTITLELOGFONT,
sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE);
m_font.CreateFontIndirect (&stFont);
//Change the wallpaper to leaves.bmp.
:: SystemParametersInfo (SPI_SETDESKWALLPAPER, 0,
_T (" forest.bmp"), SPIF_UPDATEINIFILE);
62
、如何使用一个预定义的
Windows
光标
调用
CWinApp:: LoadStandardCursor
并传送光标标识符。
BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message)
{
//Display wait cursor if busy.
if (m_bBusy)
{
SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT));
return TRUE;
}
return CDialog:: OnSetCursor (pWnd. nHitTest,message);
}
63
、如何确定当前屏幕分辨率
调用
SDK
函数
GetSystemMetrics
,该函数可以检索有关
windows
显示信息,诸如标题大小、边界大小以及滚动条大小等等。
//Initialize CSize object with screen size.
CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN));
64
、如何检索原先的
Task Manager
应用程序使用的任务列表
原先的
Task Manager
应用程序显示顶层窗口的列表。为了显示该列表,窗口
必须可见、包含一个标题以及不能被其他窗口拥有。调用
CWnd:: GetWindow
可以
检索顶层窗口的列表,调用
IsWindowVisible
、
GetWindowTextLength
以及
GetOwner
可以确定窗口是否应该在列表中。下例将把
TaskManager
窗口的标题填充到列表中。
void GetTadkList (CListBox&list)
{
CString strCaption; //Caption of window.
list.ResetContent (); //Clear list box.
//Get first Window in window list.
ASSERT_VALID (AfxGetMainWnd ());
CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST);
//Walk window list.
while (pWnd)
{
// I window visible, has a caption, and does not have an owner?
if (pWnd ->IsWindowVisible () &&
pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ())
{
//Add caption o window to list box.
pWnd ->GetWindowText (strCaption);
list.AddString (strCaption);
}
//Get next window in window list.
pWnd=pWnd->GetWindow (GW_HWNDNEXT);
}
}
65
、如何确定
Windows
和
Windows
系统目录
有两个
SDK
函数可以完成该功能。
GetWindowsDirectory
和
GetSystemDirectory
,下例说明了如何使用这两个函数:
TCHAR szDir [MAX_PATH];
//Get the full path of the windows directory.
:: GetWindowsDirectory (szDir, MAX_PATH);
TRACE ("Windows directory %s/n", szDir);
//Get the full path of the windows system directory.
:: GetSystemDirectory (szDir, MAX_PATH);
TRACE ("Windows system directory %s/n", szDir);
66
、在哪儿创建临文件
调用
SDK
函数
GetTemPath
可以确定临时文件的目录,该函数首先为临时路径检测
TMP
环境变量:如果没有指定
TMP
,检测
TMP
环境变量,然后返回到当前目录。下例说明了如何创建一个临时文件。
…
//get unique temporary file.
CString strFile;
GetUniqueTempName (strFile);
TRY
{
//Create file and write data.Note that file is closed
//in the destructor of the CFile object.
CFile file (strFile,CFile:: modeCreate | CFile:: modeWrite);
//write data
}
CATCH (CFileException, e)
{
//error opening file
}
END_CATCH
…
Void GetuniqueTempName (CString& strTempName)
{
//Get the temporary files directory.
TCHAR szTempPath [MAX_PATH];
DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath);
ASSERT (dwResult);
//Create a unique temporary file.
TCHAR szTempFile [MAX_PATH];
UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile);
ASSERT (nResult);
strTempName=szTempFile;
}
67
、如何访问桌面窗口
静态函数
CWnd:: GetDesktopWindow
返回桌面窗口的指针。下例说明了
MFC
函数
CFrameWnd::BeginModalStae
是如何使用该函数进入内部窗口列表的。
void CFrameWnd::BeginModalState ()
{
…
//first count all windows that need to be disabled
UINT nCount=0;
HWND hWnd=:: GetWindow (:: GetDesktopWindow (), GW_CHILD);
while (hWnd!=NULL)
{
if (:: IsWindowEnabled (hwnd) &&
CWnd::FromHandlePermanent (hWnd)!=NULL &&
AfxIsDescendant (pParent->m_hWnd, hWnd) &&
:: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0)
{
++nCount;
}
hWnd=:: GetWindow (hWnd, GW_HWNDNEXT);
}
…
}
68.VC1.5
下如何跳到第一事例
?
各位大虾
: CWinApp::InitInstance()
中可知是第二事例
,
但如何在
return FALSE;
之前
FindWindow()
到第一事例呢
?
主要困难是
:
1).
主窗口类名可否得到
(
主窗口
==MainFrame ?
若是
,
怎知
MainFrame
类名
?
2).Title
因含有文档名
,
是一不确定串
.
1.
类名是动态的,所以应该不易得到。(不知是否如此?)
类名不是动态的,如果不作处理,
MFC
总是使用
AfxFrameOrView
为类名,
只有
MainFrame,
和
View
等等才会用
AfxFrameOrView,
我刚用
spy
看了我的一个程序,主窗口的
Class
为
Afx:b:13ce:6:3be7
至于如何注册自己定义的类,我还没有学会,望高手指教。
AfxRegisterWndClass()
2.
我用的方法是只查
Title
中前半部分和你的要求串一致即可,忽略后面的文档
?
FindWindow()
函数需要给定窗口类名和窗口标题(
Title
),不知你是怎样做到只查前半部分的?
用
EnumWindows()
一个窗口一个窗口查,不能用
FindWindow()
这里我有另外一个问题:
找到第一事例的窗口后,如何激活它,使它成为当前窗口?
极小状态时,才能把它激活出来,否则也是没有动静,不知何故?
if (IsIconic(hwndMain))
ShowWindow(hwndMain, SW_RESTORE);
else
SetActiveWindow(hwndMain);
69.
关于
VC++2.0
中使用文件对话框的求助
在
VC++2.0
中使用了标准文件对话框以后
,
编译联接都能正常通过,而且使用
Ctrl+F5
执行
EXE
文件也完全正常
,
但是一旦用
F5
调试进入,使用该对话框的代码时
,Win95
就会异常中止
,
请问各位高手
,
为什么
?
文件对话框,改变了执行程序的当前路径,从而干扰了调试系统。如果是为了调试,可以使文件对话框定位在当前目录,并且运行时不要在其中改变目录。
70.
如何用
VC2.0
编写能
Edit
超过
64K
的类
我要用
VC2.0
编写一个
Editor,
要求能编辑超过
64K
的文本
.
我的
Edit
类从
CEdit
类派生出来
,
但编辑超过
64K
的文本就显示不出来
.
原知道在
VC1.5
中
CEdit
类只能编辑小于
64K
的文本
,
不知
VC2.0
是否也一样
?
.
自己从
CWnd
类派生,管理内存、输入、显示等(其实不累)。至于从
CEdit
中派生,我也没有头绪。
VC2.0
会有这事?我没试过,但我不相信。
VC2.0
是运行在
Win95
或
WindowsNT
上的开发工具,是
Win32
的开发工具。
Windows 95
及
NT
对应用程序在内存上没有段的限制,应用程序最多可利用高达
4G
的内存
(
包括系统占用
)
。你所说的限制大概是
VC1.5
的限制吧。盖因
VC1.5
运行于
Win16
上,每个段不能超过
64K
。
的确如此,
VC2.0
有两个例子
samples/mfc/multipad
和
samples/mfc/superpad
也是如此。不信你看看。
71.
在
VC++1.5
中如何
new
一个大数组
我想在用
VC++1.5
编程时,
new
一个
[512][512]
的大数组,却总是不行.
哪位专家可以指点一下.
选用
Larger and Huger
模式的库编译
我用过
Large
模式,好象不行呀!我用
Huge
模式,头文件编译时就出错了!
VC++ 1.5
毕竟是
16
的
, 512*512
是多少?做链表好了否则就用
VC++2.0,
全
32
位就不该有这问题了
这样的做法并不十分好
,
要分配如此大的内存最好用全局的内存分配函数
.
直接用指针操作
,
效率也会提高
.
用
MFC
类不行吗
?
如
CObArray
请用
GlobalAllocPtr
和
GlobalFreePtr
这一对函数,如下:
DWORD dwSize ;;
hpsStr =(char huge *)GlobalAllocPtr( GMEM_MOVEABLE , dwSize ) ;
...
GlobalFreePtr( hpsStr ) ;
不管多大数组,都保证没有问题。
在
VC1.5
中,如何得到子窗口在主窗口中的相对坐标?
比较笨的方法是先
ClientToScreen
转成屏幕坐标
,
然后
ScreenToClient
转成主窗口坐标
,
不知有没有更方便的方法
.
MapWindowPoints(hwndChild, hwndParent, (POINT FAR *)lprc, 2)lprc
设成子窗口内的坐标
(0,0, width, height)
72.VC1.5
如何调用进程
?
我用
VC1.52
编
Windows
程序,中间想执行一个其他
Windows
应用程序,并且让我的程序挂起等应用程序执行完后再继续,请问如何实现?
exec( )
和
spawn( )
与
Windows
不兼容,所以它们肯定不行了.
WinExec()
挂起的一个简单方法是得到新进程的主窗口句柄,然后进入死循环,直到此句柄变为无效。
不知道还有什么更漂亮一些的手法。
请问,怎么得到进程的主窗口句柄呢?
是呀,我也正想问呢.例如我执行的是
PSpice for Windows.
用
WinExec()
可以如下
:
int nWinRun = WinExec("wpspice test.cir", SW_SHOWNORMAL);
可是如何得到新进程的主窗口句柄呢?能不能截取新进程的消息呢
紧接着用
GetActiveWindow()
就可以
.
当然还是在
win3.1
下才有用
....
win95
下由于有输入的局部化问题
,
所以只能得到本线程的
Activate Window
或
Focus Window,
对于其他情况返回都是
NULL.
这问题还是不知道怎么办
,alas...
所 以 最 根 本 的 办 法 是 如 何 读 写
Windows
消 息 总 库
.
哪 位 高 手 看 得 懂
SPY
的 源 程 序
(
在
C++
或
Delphi
之 类 的
Sample
中 有
).
Use "FindWindow()". according to window title, get window handle.
then use Window Declassing method. that is write your own procedure
to process the message you want to capture. "CallWindowProc() is
executed before DefWindowProc()". (sorry can not type chinese now.)
我在
Vc 4.0
下用
_exec, _spawn,
以及
WinExec
都没问题的!
73.VC++1.5
编
Win3.1
程序能否实现全局跳转
?
setjmp
即可,和
DOS
下一样。
用
Windows API
中的
Catch()
和
Throw()
可能会更好些。不过我也不知道和
setjmp
有些什么区别。
setjmp
恐怕不行
,
它好象只能用来编写
C
程序,而不能用来编写
C++
程序
!
我的感觉是,只要是代码段,可以不受函数和应用的限制,随便乱跳的。其实是数据段,也可以跳过去的。换句话说,在
WINDOW
中,可以跳到任何地方,只要我乐意。
74.
在
DLL
用自定义窗口
我在
DLL
中用如下窗口,
class CMyWin:public CWnd
{
public:
CMyWin() ;
} ;
CMyWin::CMyWin()
{
if( !CreateEx( WS_EX_TOPMOST ,
AfxRegisterWndClass( CS_SAVEBITS ) ,
"mywin" , WS_POPUP ,
0 , 0 , 100 , 100 , NULL , NULL ) )
AfxMessageBox( "CreateEx error" ) ;
}
请问有谁知道是什么原因?谁在
DLL
中做过类似工作,望赐教。
ror
”
,
我记得
AfxRegisterWndClass
好象应该在
PreCreateWindow
中调用
,
在构造函数中用这个函数似乎有问题
,
你再试试吧
!
用
C++
作
DLL
可以吗
?
好象名字分裂回有些负作用吧
?
用
MFC C
++是可以做传统的
DLL
的。只要将回调函数定义成如下格式就行了:
#ifdef __cplusplus
extern "C" {
#endif
void __export FAR PASCAL fun() ;
#ifdef __cplusplus
}
#endif
其它与普通
MFC
程序一样。当然,在例程类的定义上也有点特别的地方
我如果在正常的执行程序中这样用
CreateEx
就没有任何问题,而在
DLL
中
就有问题。并且这问题也只发生在
WIN3.1
上,在
WIN95
上却可以正常执行。
-
75.
如何让
TOOLTIP
的字体变大
前几天有个虫虫问如何让
vc4.0
的
Tooltip
的字体变大
,
可现在文章没有了
.
不过现在我
有个方法
:
在
Windows 95 Desktop
属性中有
desktop scheme
中有
Tooltip
一项
,
可以该变
TOOLTIP
的字体和大小
.
不过这样做所有程序的
Tooltip
都变大了
.
这可能不是你的本意
.
但
Tooltip
是
Windows 95 Common Control,
由
Windows
95
内部实现
,VC4.0
的
CTooltip
类并不实现
Tips
的显示
,
所以要实现针对某个程序的
Tooltip
的特殊显示
,
有一定难度
.
我以前曾经试图实现
Tooltip
的多行显示
,
做到了当
Toolt.
显示时触发我的函数
,
消失时触发我的函数
,
但在显示时却出
GP
错误
.
现在我认为最简
单的方法是从头自己实现
Tooltip
类
.
一切随心所欲
.*