您的位置:首页 > 其它

以前学习vc的笔记

2008-05-10 23:25 357 查看
1 如何让一个VC的对话框程序响应键盘消息?

我不知道在这样的基于对话框的程序中,如何使用SetFocus使得对话框窗口获得输入焦点,从而能够响应键盘消息.

基于对话框的程序,如果窗体上有控件,由于如果窗体处于活动状态,那么将必有一个控件获得焦点,不能通过在ClassWizard中添加WM_KEYDOWN来响应键盘输入。

一个简单的办法就是重载CWnd::PreTranslateMessage,即

BOOL CDlgDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(pMsg->message == WM_KEYDOWN)
{
MessageBox("ssd");
}

return CDialog::PreTranslateMessage(pMsg);
}

2 对话框中如何响应键盘消息?

我们首先想到的是响应WM_KEYDOWN消息,但实际运行却发现没有任何效果。
原因是对话框里的控件需要首先对按键作出响应,比如多行编辑框必须首先
处理回车,不至于回车使对话框关闭。
我们要想在第一时间对对话框的按键做出响应,需要重载PreTranslateMessage,
以下的代码实现了在对话框中显示虚拟键值(virtual-key code)
BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
///或者直接调用OnKeyDown
CString strwParam;
strwParam.Format("%d ",pMsg->wParam);
CDC* pDC = GetDC();
pDC->TextOut(10,10,strwParam);
ReleaseDC(pDC);
}
return CDialog::PreTranslateMessage(pMsg);
}

此方法也适用于FORMVIEW或其它控件中对键盘按键的响应,以下的代码来自MSDN,
实现了当按下上下左右方向键时调用OnKeyDown,我们可以在OnKeyDown中作相应处理。

BOOL CSampleControl::PreTranslateMessage(LPMSG lpmsg)
{
BOOL bHandleNow = FALSE;
switch (lpmsg->message)
{
case WM_KEYDOWN:
switch (lpmsg->wParam)
{
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
bHandleNow = TRUE;
break;
}
if (bHandleNow)
OnKeyDown(lpmsg->wParam, LOWORD(lpmsg ->lParam), HIWORD(lpmsg->lParam));
break;
}
return bHandleNow;
}

3 对话框窗口只要有子控件就接不到KEY_DOWN,该怎么写代码响应键盘呢?我想要响应F10,F11键。
只要对话框上有任何子控件,就不能响应键盘消息了(键盘消息被派发到了获取焦点的控件上)
方法是在PreTranslateMessage中拦截

4 PreTranslateMessage 是做什么用的啊????
用来预处理消息的。发给窗口的消息经过预处理以后再发给窗口,这里你就可以过滤或者处理你感兴趣的消息,比如回车等。如果你处理好了不需要窗口继续处理了,就返回TRUE或者1 。

就是说在你的窗体收到消息前对消息进行处理,举个很简单的例子,在对话框里回车的时候就会直接OnOK,如果你要屏蔽掉回车键就在这个函数里判断,如果是WM_KEYDOWN并且按键为VK_ENTER就不进行任何处理,这样的话,回车键的消息就不会发给对话框了
5 MFC中PretranslateMessage的实现

在MFC里面,PretranslateMessage是一个很重要的虚函数。这个函数的作用这里就不谈了,很多地方都有涉及,这里只谈一下其实现的机制。
谈到PretranslateMessage的实现,便不得不谈到MFC消息循环的实现。MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但是实际的消息循环代码位于CWinThread中,CWinApp只是从CWinThread继承过来。其简化后的代码大概如下:

BOOL CWinThread::PumpMessage()
...{
_AFX_THREAD_STATE *pState = AfxGetThreadState();

::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))

if (!AfxPreTranslateMessage(&(pState->m_msgCur)))
...{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}
可以看到,PumpMessage在实际的TranslateMessage和DispatchMessage发生之前会调用AfxPreTranslateMessage,AfxPreTranslateMessage又会调用CWnd::WalkPreTranslateTree(虽然也会调用其他函数,但是这个最为关键),其代码如下:

BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
...{
ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
ASSERT(pMsg != NULL);

// walk from the target window up to the hWndStop window checking
// if any window wants to translate this message

for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
...{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
...{
// target window is a C++ window
if (pWnd->PreTranslateMessage(pMsg))
return TRUE; // trapped by target window (eg: accelerators)
}

// got to hWndStop window without interest
if (hWnd == hWndStop)
break;
}
return FALSE; // no special processing
}

可以看到,代码还是很直接的。从接受到消息的窗口层层往上遍历,并调用PretranslateMessage看是否返回TRUE,是则结束,否则继续。
这里有一个地方非常关键:CWnd *pWnd = CWnd::FromHandlePermanent(hWnd) 这一句代码从当前AfxModuleThreadState拿到Permanent句柄表,从而找到hWnd对应的CWnd对象。关于PreTranslateMessage有一个常见的问题就是与此有关:如果编写了一个MFC DLL并从另外的一个MFC主工程之中调用这个MFC DLL中的Modeless Dialog的话,Modeless Dialog的PreTranslateMessage不会被调。因为MFC DLL和这个MFC工程拥有不同的AfxModuleThreadState,因此在MFC DLL中创建的modeless CDialog对象不在MFC工程的句柄表中(CWnd::FromhandlePermanent返回NULL),因此虽然MFC主工程中的CWinApp的Pretranslatemessage会被调(注意此时Dialog的消息循环在MFC主工程里面),但是不会调用MFC DLL中创建的那个modeless CDialog的PreTranslateMessage函数。因此需要特殊处理。一般有两种方法:
一种是直接在MFC主工程中的CWinApp::PreTranslatemessage里面调用MFC DLL的CWinApp::PreTranslateMessage(可以专门在MFC DLL中export一个专门的函数来做这件事情)。另外的方法是使用钩子,在钩子消息处理函数之中,判断目标窗口是否是当前具有焦点的窗口,如果是,则直接调用目标窗口的PreTranslateMessage函数(前提是你有要保存这个对象的指针)。

6. 可以通过如下获得控件的HWND
CWnd* pWnd;
pWnd = GetDlgItem(IDC_...);
HWND hWnd;
hWnd = pWnd->GetSafeHandle();

下面的回调函数要调用该ITEM里的数据
SetTimer(this->GetSafeHwnd(), MY_TIMER, 1000,(TIMERPROC)MyTimerProc);

7. 通过HWND来处理控件数据

static void CALLBACK MyTimerProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_TIMER message
UINT_PTR idEvent, // timer identifier
DWORD dwTime // current system time
)
{
CWnd* pWnd;
pWnd = CWnd::FromHandle(hwnd);

Page1 *pPage = (Page1 *)pWnd; //Page1为类名称
CString strTmp = pPage->m_NameList.GetItemText(0,0);

}

8 我想请问一下,GetDlgItem 的第二个函数void CWnd::GetDlgItem( int nID, HWND* phWnd ) const;有什么用处呀?

两个函数分别按如下方法使用,效果等价
1.
CWnd* pWnd;
pWnd = GetDlgItem(IDC_...);
HWND hWnd;
hWnd = pWnd->GetSafeHandle();

2.
HWND hWnd;
GetDlgItem(IDC_..., &hWnd);
CWnd* pWnd;
pWnd = FromHandle(hWnd);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: