本文共 18046 字,大约阅读时间需要 60 分钟。
(1) DLL中的模板成员函数?
在一个DLL中,我在自己创建的类中使用了模板成员函数来代替预处理宏.但出现以下错误:error C2664: 'double Data::extract(double &)' : cannot convert parameter 1
from 'class CArray' to 'double &' 为什么在匹配模板定义时它要寻找一个DOUBLE参数?我觉得你可能是在表达成员函数(内联)时出现了问题,请参照下面的示例:
class AFX_EXT_CLASS Data : public CObject //This is not a template
{ public: Data(); Data(BYTE * buffer,int size); template Data(const CArray& array); template CArray& extract(CArray& array) { CArchive ar(&buffer, CArchive::store); ar >> array; }; double extract(double&); (...) private: CMemFile buffer; }
(2) CFormView中的上下文帮助?
我想在基于CFormView类的SDI应用程序中加入真正的上下文帮助,但没有成功.你应该重载CMyFormView类的OnHelpHitTest函数:
LRESULT CMyFormView::OnHelpHitTest(WPARAM, LPARAM lParam)
{ LRESULT lResult = (LRESULT)0x00;CWnd* pWndChild = ChildWindowFromPoint(CPoint(lParam),
CWP_ALL|CWP_SKIPINVISIBLE);if (pWndChild && ::IsWindow(pWndChild->m_hWnd))
{ lResult = ::GetWindowLong(pWndChild->m_hWnd, GWL_ID);if (lResult)
lResult += HID_BASE_COMMAND; }if (lResult == (LRESULT)0x00)
lResult = ::GetWindowLong(m_hWnd, GWL_ID) + HID_BASE_RESOURCE;return lResult;
} 然后你就可以使用平时用的帮助文件了,但你要保证有正确的前缀,请参照 TN028:Context-Sensitive Help Support. 例如: ID_SOME_MENU_ITEM_OR_COMMAND_BUTTON IDR_SOME_WINDOW_OR_DIALOG IDP_PROMPT IDW_CONTROL_THAT_IS_NOT_A_COMAND_BUTTON 你要确认你所使用的控件的ID包含在文件resource.hm中.(3) CArchive类的WriteObject函数问题?
谁知道在使用CArchive类的WriteObject函数时,如何避免将类名写入文件吗?WriteObject函数不仅写入了类名,而且还写入PID(请查看TN02),如果你只想写进一个文本文件,并且你也 想用串行化,你可以使用文件指针(用GetFile)来存储字符串.或者,你可以使用CFILE类来处理这个问题,如果是文本文件,你也可以用 CStdioFile类.
(4) RegisterWindowMessage中的BroadcastSystemMessage如何处理?
我想用BroadcastSystemMessage来在两个进程之间通讯,我从一个进程发送了一个用RegisterWindowMessage注册过的消息,但在目的进程中却没有收到该消息.
我认为你应该在两个进程的最高级窗口中都注册该消息.请看下例:
static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame )
ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand ) END_MESSAGE_MAP()LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam )
{ your code... } 然后发送进行应该包含: While the sending process would contain:static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
void Someclass :: someMethod( void )
{ ::PostMessage( (HWND)HWND_BROADCAST, sBroadcastCommand, 0, yourMessageId ); }
(5) 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); } }
(6) 如何向ATL-COM对象传送一个数组?
我想创建一个函数来向ATL-COM对象传送数组.如下代码的方法用于ACTIVEX中,可能对ATL-COM也有启发吧.
CoInitialize(NULL);
CLSID m_clsid; USES_CONVERSION; ::CLSIDFromString(T2OLE("ROUNDANALOG.RoundAnlgAARCtrl.1"), &m_clsid); IDispatch FAR* pObj = (IDispatch FAR*)NULL; CString str = "UpdateControl"; BSTR bstr = str.AllocSysString(); HRESULT hr = CoCreateInstance(m_clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pObj);SafeArrayAccessData(psa, (void**)&bstrArray);
bstrArray[0] = str.AllocSysString(); bstrArray[1] = str.AllocSysString(); SafeArrayUnaccessData(psa);VARIANTARG* pvars = new VARIANTARG[1];
VariantInit(&pvars[0]); pvars[0].vt = VT_ARRAY|VT_BYREF|VT_BSTR; pvars[0].pparray = &psa; DISPID dispid;hr = pObj->GetIDsOfNames(IID_NULL, &bstr, 1,LOCALE_USER_DEFAULT, &dispid);
DISPPARAMS disp = {pvars, &dispid, 1,1};
hr = pObj->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,DISPATCH_PROPERTYPUT,&disp,NULL, NULL, NULL); delete[] pvars; pObj->Release(); CoUninitialize();在你的控制中建立如下并变量参考:
void CRoundAnlgAARCtrl::SaveFunc(const VARIANT FAR& var)
{ // TOD Add your dispatch handler code here ASSERT(var.vt == VT_ARRAY | VT_BYREF | VT_BSTR); SAFEARRAY* psa = *var.pparray; }
(7) 如何选择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;
}
(8) 如何改变默认的光标形状?
我试着将光标改变为其它的形状和颜色,但却没有变化.在对话框/窗口/你需要的地方加上对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.(9) 如何用键盘滚动分割的视口?
我的问题是当我用鼠标滚动分割窗口时,视口滚动都很正常,但用键盘时,却什么也没有发生.在你的视图继承类中加入如下两个函数,假定该类为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; } (10) 如何在线程中处理状态条?在我的应用程序CWnd的继承中有指针指向状态条,用pStatusBar->SetPaneText(0,status,TRUE)在状态条上显示一些文本都很正常.但在第二个线程中调用该函数却不行,出现hwnd警告.
当你传送一个CWnd的指针到另外一个线程时,m_hWnd将为空.我的办法是用PostThreadMessage传送消息到状态条的父类,让它对状态条进行处理.
(11) 如何阻止WINDOWS关闭?
我有一个应用程序会不停地工作.当该程序正常运行时,该如何避免用户关掉系统?是不是该用WM_QUERYENDSESSION.是的,在你的主框架窗口类中使用.
// in the class header
afx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason );// in the Message Map
ON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession )// in the class body
BOOL CMainFrame::OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason ) { if( lEndReason =3D=3D ENDSESSION_LOGOFF ) { // user is logging off else // Windows is going downreturn( bCanExit );
}
(12) 如何使一个按钮Disable?
我使用下面代码来Disable一个为ID_BUTTON的按钮,为什么会没有变化. GetDlgItem(IDC_BUTTON)->EnableWindow(FALSE);CWnd类中的EnableWindow函数用来Enable或Disable一个窗口类的对象,因为CButton类继承于类CWnd,所以你可以使用来操作一个按钮.Enable一个基于窗口类的对象可以用以下代码:
pWnd->EnableWindow(TRUE);
Disable一个对象可用pWnd->EnableWindow(FALSE);
其中pWnd为一个指向窗口对象的指针VC++中消息WM_ENABLE告诉窗口它正在Disable或Enable,但它并不能使一个窗口Enable或Disable.
(13) 怎样从MFC扩展动态链结库(DLL)中显示一个对话框?
我在过去的几天中试着在DLL中定义的函数中显示一个对话框,可是已经在DLL中定义好的对话框资源,在常规DLL调用时,我可以正常的显示出来,为什么在扩展DLL中同样的资源我却不能显示.当你在DLL中使用资源时,有些小细节需要注意,首先,在DLL运行时,必须保存DLL的实例,可以通过AfxInitExtensionModule
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{ if (dwReason == DLL_PROCESS_ATTACH) { // Extension DLL one-time initialization if (!AfxInitExtensionModule(extensionDLL, hInstance)) return false; }return(true);
} 然后,每次使用DLL资源时,你必须改变资源的句柄,使其指向DLL,并保存exe的资源,以便以后正确恢复void get_DLL_resource(void)
{ /* this function changes the resource handle to that of the DLL */ //这个函数改变资源句柄使其指向DLL if (resource_counter == 0) { save_hInstance = AfxGetResourceHandle(); AfxSetResourceHandle(extensionDLL.hModule); }resource_counter++;
} 接着你需要其它函数来恢复资源句柄void reset_DLL_resource(void)
{ /* this function restores the resource handle set by 'get_DLL_resource()' */if (resource_counter > 0)
resource_counter--;if (resource_counter == 0)
AfxSetResourceHandle(save_hInstance); } 接 下来一点非常重要,只要有可能就必须恢复资源句柄,否则,你将会遇到许多问题.原因是可执行文件必须重画工具条等等,比如说,如果用户移动DLL的对话 框,如果资源句柄仍然为DLL的资源,程序就崩溃了,我发现最好恢复句柄的时机在对话框的OnInitDialog()中,这时对话框的模板等已经读出了.
(14) 想隐藏用户界面怎么办?
我编了一个小巧而有趣的工具,当用户使用时我不想让它显示出任何用户界面。听听各位有办法可将视关闭。你可以注册一个新的窗口类型,它拥有除了WS_VISBLE属性外的任何属性,类似CFrameWnd,在PreCreateWindow方法中实现。另外,你能在OnCreate方法中通过设置m_nCmdShow为SW_HIDE来实现,具体方法如下:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;// hide our app
AfxGetApp()->m_nCmdShow = SW_HIDE;return 0;
}
(15) 如何实现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.否则会出错。
(16) 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); }
(17) 如何激活变灰的弹出菜单?
在设计菜单时设定为GRAYED的菜单项,如何在运行时激活它?请看下面的示例代码:
void CMyView::OnRButtonDown(UINT nFlags, CPoint point)
{ CScrollView::OnRButtonDown(nFlags, point);CMenu *menu, *popup;
menu = new CMenu();// load menu from resource file
menu->LoadMenu( IDR_POPUPMENU ); popup = menu->GetSubMenu(0); // item 0 is DUMMYUINT nEnable;
nEnable = MF_BYCOMMAND|MF_GRAYED;if( your test )
{ nEnable = MF_BYCOMMAND|MF_ENABLED; }popup->EnableMenuItem( ID_YOUR_ID, nEnable );
//display menu
ClientToScreen(&point); popup->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ); delete menu; }
(18)线程消息?
如何正确地在线程之间传送消息?下面的代码将会帮你的忙:
void CThread::OnUserOpen( WPARAM wParm, LPARAM lParm )
{ UNUSED( wParm ) ; UNUSED( lParm ) ; AfxMessageBox("User Open", MB_OK|MB_ICONEXCLAMATION); }当然,也别忘了以下声明:
class CThread : public CWinThread
{ DECLARE_DYNCREATE(CThread) protected: CThread(); // protected constructor used by dynamic creation afx_msg void OnUserOpen( WPARAM wParm, LPARAM lParm );
(19) TreeCtrl控制的显示速度太慢?
我从CTreeCtrl继承了一个TREE控制类,重载主要是为了改写每个节点的文本.我在 OnPaint函数中写了一些代码,但这严重地影响了TREE控制的滚动速度.OnPaint函数
1) 可见节点,对于GetFirstVisibleItem和GetNextVisibleItem来讲,是: a.根节点;b.父节点已展开的节点;因此,"可见"意味着"没有被未展开的父节点隐藏".当节点滚动到客户外时,它对上述两个函数来讲仍是可见的.2) 当TREE的内容改变时,它默认只将变为可见的节点重绘.另外其它已经是可见的节点没有必要重绘,TREE只是滚动DC的位图而已.
上面的意思是不要绘制你不需要看的节点,那会导致速度降低.建议,测试节点矩形是否在客户区,使得只有需要绘制的节点才会被绘制. void CIndentTree::OnPaint() { CPaintDC dc(this); // device context for paintingHTREEITEM hItem = NULL;
DRAWITEMSTRUCT dis;
CRect rc;// redraw only visible items with indentation
for( hItem = GetFirstVisibleItem(); hItem; hItem = GetNextVisibleItem( hItem ) ) { if( !GetItemRect( hItem, rc, FALSE ) ) continue;if( rc.top <= dc.m_ps.rcPaint.bottom &&
rc.bottom > dc.m_ps.rcPaint.top &&=20 rc.left <= dc.m_ps.rcPaint.right && rc.right > dc.m_ps.rcPaint.left ) { dis.hwndItem = (HWND)hItem; dis.rcItem = rc; OnDrawItem(0, &dis, &dc); } } } OnDrawItem函数 (i).删掉如下代码:IMAGEINFO* pinfo = new IMAGEINFO;
... delete pinfo; 没有必要使用动态的IMAGEINFO变量,你可以将其定义为堆栈变量. (ii) GetItemState和GetItemText都是使用的GetItem,因此,你只需调用一次, 就可以从节点获得你要的所有信息.
(20) 关于工具条?
我需要在程序中做一个FLAT工具条,于是我加入一个变量m_wndToolBar. 在程序主体窗口的OnCreate()函数中修改工具条状态(0,TBSTYLE_FLAT). 在NT中运行正常,为什么在95中工具条变得透明?在COMCTL32.DLL中的旧版本中有些小bug,绘画时会带来一些问题, 你可以使用一些定制代码,在 站点上有下载,如果你使用的是6.0版本,你也可以使用下列代码(摘自我的mainfrm.cpp文件)
m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP |
CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); 用CreateEx替换ModifyStyle在同一尺寸的工具条中有些不同((CreateEx 建立的略小些),试一下,如果你仍然有这个问题,检查一下COMCTL32.DLL的版本使用标准按钮替换FLAT.
(21) 关于线程消息?
真奇怪,OnUserOpen()函数和OnUserOpen(WPARAM, LPARAM)函数竟然不是一个函数,编译器在查到OnUserOpen(WPARAM, LPARAM)时,不会调用OnUserOpen 莫非有人在消息映象做了什么手脚?其实,这是MFC严密的表现,处理时,通过函数指针来调用,而该指针是由发生的事件所决定的.如果句柄不正确定义的话,调用当然是非法的
(22) 关于控件的焦点?
有谁能给我一个有效的方法:当一个控件失去焦点时,怎样管理才能使对话框的焦点进入到正确的控件.我有一个可运行的程序来实现,不一定很全面,但能工作.
const int WM_VALIDATE_PARAMS WM_APP + 101;
void CMyDlg::OnKillfocusName()
{ PostMessage(WM_VALIDATE_PARAMS, ED_NAME, 0L); }void CMyDlg::OnKillfocusAddress()
{ PostMessage(WM_VALIDATE_PARAMS, ED_ADDRESS, 0L); }bool CMyDlg::OnValidateParams(WPARAM rcId, LPARAM)
{ switch( rcId ) { case ED_NAME: if( !validateName() ) m_edName.SetFocus(); break;case ED_ADDRESS:
if( !validateAddress() ) m_edAddress.SetFocus(); break;default:
break; }return true;
} 上面的代码可以在用户使用TAB键或鼠标操纵时,使用焦点跳至下一个控制.当你想DISABLE一个控件或重设焦点时,会有些问题,特别是在Killfocus事件中。
(23) 如何捕获键盘按键?
在CTabCtrl的子对话框怎样才能捕获ALT+0组合键可以在PreTranslateMessage中截取键盘消息。
(24)怎样实现3D效果?
在对话框中怎样实现Edit和Listboxes控件的3D效果?(环境95/NT VC5.0)1). 使用带WS_EX_CLIENTEDGE标志的::CreateWindowEx来替换::CreateWindow 或者用CWnd::CreateEx替换CWnd::Create.
2).在建立控件之后,调用ModifyStyleEx(0, WS_EX_CLIENTEDGE).(25) 怎样建立客户CSocket?
我有一个客户socket想在socket中建立一个局域联接.我使用下列顺序:CSocket* m_pSocket;
m_pSocket = new CSMSSocket(this); m_pSocket->Create(); m_pSocket->Bind(m_intHostPort, m_strHostIPAddress); m_pSocket->Connect(lpszAddress, nPort); 但每次Windows Socket都定向到别的端口,怎样才能定向到同一个端口(环境:95/NT VC5.0).1).如果你想用Client Socket,你就不能在connect()之前调用bind(),因为局域端口地址由TCP/IP设置,我们不可能知道下一次将使用那一个端口,我想我们不必这做.
2). 看一下Create()的帮助,里面告诉我们必须给Create()指定一个端口值, 缺省的情况为0,也就是由Window为我们选择一个端口,通过Create()将会自动捆绑. 3).我不认为你应该完成所有的工作,但想总是用一个相同的端口来连接远程机器是一个不正确的想法. 问题出在端口数/地址结合必须唯一,如果你想 在Create()中指一个固定的端口数,你只能与远程机器建一个单个连接.在你所写的代码中是允许局域端口数可变化,可以打开多个连接来取得相同的地 址.在侦听(listening)Socket中有许多理由使用一个固定端口,但在连接(connecting Socket中我想没有太多的必要.
(26) Disable一个非模态对话框的客户区?
我在OCX(对象连接和嵌入客户控制程序)有一个非模态对话框.它有一个菜单以及工具条.现在我想Disable 客户区(只是客户区,例如:设置特殊变量时显示一个等待光标,区域里的所有控制都不可以处理)但在客户区的所有控制要看上去没有变化(也就是不可以 Disable)可以这样试一下,建立一个子窗口,覆盖对话框的全部的用户区域,用WS_EX_TRANSPAPENT 透明类型,然后调用函数EnableWindow(FALSE),使用SetClassLong或者别的方法,在子窗口调用"忙"光标,这时光标就正确 了,但对话框中的菜单还能正常使用.(说白了就是建立一个透明的子窗口盖住所有的用户区域,然后Disable该透明窗口,在这个窗口中设置光标为" 忙") 这个方法我没有试过,但在一些老的Windows的书介绍过这种方法.
(27) 关于使用SetClassLong和SetCapture问题
我用SetClassLong设置对话框光标时遇到了一些问题,当我使用SetCapture捕获鼠标时,光标形状并没有变化时,以下为原代码:
void CMouseMoveSimDlg::OnLButtonDown(UINT nFlags, CPoint point)
{ myDragging = TRUE;myhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,
(long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_SELECTCURSOR )));SetCapture(m_hWnd);
CDialog::OnLButtonDown(nFlags, point); } 如果移去SetCapture这一行,光标就会正确的设置,但它就不能正确的捕获鼠标消息.那儿出问题了(环境NT4.0 VC6.0)?1).如果我没有记错的话,SetClassLong只影响调用它以后的建立的窗口.可以使用 SetWindowLong来改变已存在的窗口的属性.(为什么要用SetClassLong来改变光标形状, 为什么不在消息WM_SETCURSOR中替换.)
2).我也不清楚问题出在那儿,但下面的方法可以克服SetCapture带来的问题,它是从我的程序里面提出来的: void CScribbleView::OnLButtonDown(UINT nFlags, CPoint point) { ........ SetCapture(); // Capture the mouse until button upmyhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,
(long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));
SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));
........ }void CScribbleView::OnLButtonUp(UINT nFlags, CPoint point)
{ if( GetCapture() != this ) return; ........ ReleaseCapture(); SetClassLong( m_hWnd, GCL_HCURSOR, (long)myhPrevCursor); return; }
(28) 动画控件?
我在对话框中使用一个动画控件,通常我都是用CAnimated的open成员函数,并加上avi的文件名来使用动画控件,怎样在资源文件加入一个avi文件,作为资源使用?1).简单,将avi文件引入资源,按你的喜欢来决定是属于那一种类型的,通过ID来代替文件的名字,这样你就可以使用了.
2).在资源窗口中单击右键,在弹出的菜单中选择"Import".这时会打开文件选择框,选择所要的文件,这时系统将会询问自定义资源类型,输入avi.一个AVIS的资源组将会创立,你所选的avi文件将会出现在该组中并拥有一个ID. 3).手动在资源文件中加入一个AVI资源说明,比如: //在这手工编辑资源文件 IDR_ANIMATION AVI res/animate.avi
(29) 错误声明的消息?
我给一个视发送一条消息 pView->SendMessage (MY_MESSAGE, wparam, lparam); 消息声明被认为是不正确的 afx_msg void OnMyMessage(); 高手一看就知道这是一条命令错误的声明对象,正确的声明应该为: afx_msg LERSULT OnMyMessage (WPAPRAM wparam, LPARAM lparam);因为我不使用参数,程序工作也很好,所以我不知道为什么会有这种错误,该过程处理完之后也没有任何错误的信息出现.但现在release版本中有一个奇怪的现象(debug版本中没有)程序会非正常终止,通常这现象发生在SendMessage()返回之后。为什么?
1.相信问题是出在错误的堆栈上,"thiscall"调用后就应该清除堆栈,调用者调用时将两个参数压入堆栈,但参数却 没有被清除.如果你真的不需要WPARAM,LPARAM,也不需要返回值的话,你可以使用ON_MESSAGE_VOID 消息声明.在afxpriv.h中定义,是非文档的,意思就是它不会有什么提示或可能中断程序, 另外,需要注意一下线程消息,注意线程消息是可变的,它们将返回void,没有LRESULT,同样的声明.
2.如果你不使用WParam和LParam,为什么不在视中定义一个用户函数来处理自己想做的?
(30) 怎样模拟鼠标动作?
这是困扰我多时的一个问题,怎样才能实现模拟鼠标的动作,就是说要使一个程序实现鼠标的单击,双击,拖放等功能.我认为必须要实现相应的消息传递,但每次都不成功. 比 如说,我想关闭记事本窗口,可以传送WM_lBUTTONDOWN和WM_LBUTTONUP(X,Y值为记事本的右上角关闭按钮的位置)给记事本窗口, 但窗口并没有关闭.当然,我也知道关闭一个窗口可以通过传送WM_QUIT或WM_CLOSE来实现,但鼠标的消息为什么会丢失? 请教各位大师,怎样模式模拟实现鼠标的动作,或者给我一些怎样发送消息来关闭窗口的建议(不是WM_CLOSE或WM_QUIT)1).试一下window hooks,你可以使用SetWindowsHookEx和JournalPlayback来处理鼠标事件.
2).你可以使用文档中的SendInput(),它能实现模拟键盘或鼠标事件.如果你使用NT,那也可以用老的函数像mouse_event(),keyb_event等,在Win98中,SendInput()一样可以使用. 3).抱歉不能给你一个满意的回答,你可以在网站 中找到一篇关于模拟输入的文章. 4).在NT中可以使用mouse_event()传递事件,文档上说这种方法已经过时了,那么你可以用 SendInput()替换,但找不到关于此函数的使用说明,所以我依然使用mouse_event,没有任何问题.
(31) 改变对话框标题字体?
怎样改变对话框标题文件的字体,改变资源中对话框属性中的字体,将改变所有的控件的字体, 却没有改变标题,但我只想改变标题字体,不改基余控件的属性.是不是我错过一些明显的选项. 通过查找一些MFC代码,我发现有一个CDialog模块,里面调用了一引起字体方法,但该对话框不是公用的,我相信它不会给我任何帮助.1).就我所知,对话框的标题字体和其它的窗口标题一样,它可以通过系统--显示器--属性--外观来设置,如果自己想这样做,我想你应该取得WM_NCPAINT句柄自己来画出非用户区域(包括标题在内),我从未做这样做过,可能是个错误的方向.
2).如果你是在CView继承的,那你可以在构造函数中看见如下代码: if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) ) return false; GetEditCtrl().SetFont( &my_CFont ,true ) 接下来如果你想改变在对话框中的一个CEdit控件字体时,可以使用以下代码:if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) )
return false; ( GetDlgItem (ID_ANY_CEDIT) ) ->SetFont( &my_CFont );转载地址:http://gghab.baihongyu.com/