How to customize the return key in the dialog

xiaoxiao2021-03-06  63

Based on the dialog-based program, the programs exit each time you press the Enter key. The BS_DEFPUSHBUTTON attribute that removes the button and rewrites the ONOK function is useless. So how to customize the behavior of the Enter key? This problem is very easy, but it is necessary to understand that time.

This problem has been in the development of Windows, for beginners, this is an annoying problem, fortunately, people have found a variety of solutions to solve this problem. This article will tell you how to customize the key behavior.

If you want a Disable Enter key, the easiest way is to overload the ONOK function, which is a bad idea, but if you overload Onok, let it do things, then when the user uses the mouse to press back What should I do when the vehicle key wants to do? You can change the id of the Enter key, such as: id_my_ok, and write a processor that calls EndDialog, although it can be passed, but it looks a bit unprofessional.

Another method is the "default" attribute of the Disable Enter key. This is also the method you have made in this article, because the BS_DEFPUSHBUTTON attribute of the Uncheck Enter key is not enough, you can use Spy to carefully observe the control and experiments, you can find the Enter key, I will still send an exit message.

Where is the problem? You must distinguish the OK key and the Enter key, you can write a ONOK processor to call the getCurrentMessage function to get the last message, should be WM_COMMAND, then check where the WPARAM's low word (Low-Order Word) looks at where the command comes.

To solve the problem, you must figure out everything behind, you can see in Spy , when the user presses the Enter key, Windows sends a special WM_GETDEFID message to get the default command ID, Windows will use it as WM_COMMAND send. So, what you have to do is to overrun the WM_GETDEFID message, which describes the WM_GETDEFID return value in the documentation for Windows: "If there is a default button, the high level of the return value contains the DC_HASDEFID, the low word contains the control identifier Otherwise, the return value is zero. "

According to this description, it is assumed that if there is no default button, the return value should be zero. If you want disable defaults, you must return DC_HASDEFID in the high level.

Begin_MESSAGE_MAP (CMYDLG, CDIALOG)

ON_MESSAGE (DM_GETDEFID, ONGETDEFID)

...

END_MESSAGE_MAP ()

LResult CMYDLG :: ONGETDEFID (WPARAM WP, LPARAM LP)

{

Return makelong (0, DC_HASDEFID);

} Because the MFC does not correspond to the macro of the DM_GETDEFID, you must use a universal ON_Massage macro. This allows users to press the Enter key at will, but what will not happen. The above approach is to solve the problem that press the Enter key program. But another problem is produced: What should I do if I want to enter the car? Some people have asked how to map the Enter key to the Tab key, and then press the back key to press the Tab key - that is, the input focus moves to the next dialog control. This requires some work, but the simplest way is to use acceleration keys. Many programmers tried to use Onchar, I will say to them: no, no, no! Onchar is a low-level interesting thing, you should find ways to avoid it, there is WM_KeyDown, WM_KEYUP, etc. Who can deal with these things? OnChar can be used to limit characters that allow input to edit boxes, such as numbers, letters, etc. If you want to map a key to a command, the acceleration key is the best way. An acceleration key is created for VK_RETURN for VK_RETURN to map it to the command ID_MY_ENTER, and write a command processor to do what you want.

Begin_MESSAGE_MAP (CMYDLG, CDIALOG)

ON_COMMAND (ID_MY_ENTER, ONMYENTER)

......

END_MESSAGE_MAP ()

void cmydlg :: onmyenter ()

{

Nextintaborder ();

} The following figure is the dialog box for this example and

The code, NEXTITABORDER in the code is a function that actually works. It uses GetNextdlgTabItem to get the next control focus of the Tab sequence.

While (getMessage (...) {

TranslateMessage (...);

DispatchMessage (...);

} Not important here, it is important that the message does not reach the process, you must request a message. This is a kind of artificial non-charm multi-task method. This method has collaborates through every task to simulate multi-task environments. With more and more features, some people think of the idea of ​​accelerating key tables, this mesh To map buttons and command IDs. In order to achieve this, they invented a function called TranslateAccelerator. Now this message pump turns as follows:

While (getMessage (...) {

IF (TRANSLATEACCELERATOR (Haccel ...) {

// Handled, Continue looping

} else {

TranslateMessage (...);

DispatchMessage (...);

}

} Haccel is an acceleration key table handle, which is also not important here. It is important to use acceleration keys, which is to have a dedicated function to interpret the button message as a WM_COMMAND message. TRANSLATEACCELERATOR is looking for a word that matches WM_KEYDOWN, WM_CHAR, WM_KEYUP, and the character matching the key value in the table. If found, it inserts a WM_COMMAND to message queue, where the command ID in the message queue can be any entry defined by the acceleration key table. This way you just set the accelerator key table (in the resource) and remember to call the corresponding function TranslateAccelerator, don't worry if you don't worry.

Time has entered the 21st century. With the ripening of C and MFC, almost the entire message loop (but not all) is hidden in the MFC, in order to make any windows have a chance to get a little message pump behavior, MFC Provide a special virtual function PretranslateMessage, if you have enough courage to explore the message processing mechanism in CWINTHREAD, you will encounter the following code: // Simplified CWINTHREAD

While (getMessage (...) {

IF (PretranslateMessage (...) {

//undinue looping

} else {

TranslateMessage (...);

DispatchMessage (...);

}

} CWINTHREAD :: PretranslateMessage is a virtual function, in the application, its default implementation calls another virtual function with the same name, CWnd :: PretranslateMessage. So if you need anything to do in the message loop - as explained to the accelerator - you only need to overload PretranslateMessage. In fact, this is the method of cframewnd processing acceleration keys.

Bool CFrameWnd :: PretranslateMessage (MSG * PMSG)

{

......

IF (PMSG-> Message> = WM_KEYFIRST &&

PMSG-> Message <= WM_KEYLAST)

{

:: TranslateAccelerator (M_HACCELTABLE, ...);

}

} Where can I get acceleration key tables from CFRAMEWND? When you load the frame, cframeWnd :: loadFrame uses the same ID (such as idR_mainframe) as the document template, and loads him into m_hacceltable. All processing details are automatic, hidden in the MFC, you don't have to worry - only the main framework, if it is a dialog, it is another situation. Because CDIALOG is not derived from CFrameWnd, it does not inherit any content related to acceleration keys.

Don't worry, we can imitate the work of cframewnd, easy to increase the function of acceleration for the dialog. The first step is to load the accelerator button, the best place to load the accelerator key is in the OnInitDialog function of the dialog:

Bool cmydlg :: oninitdialog ()

{

CDIALOG :: OnInitdialog ();

......

// load accelerators

m_haccel = :: loadaccelerators (AfxgetResourceHandle (),

m_lpsztemplatename);

Assert (m_haccel);

Return True;

} In the acceleration key table, you can use any ID. Here I am using the ID of the dialog itself, (M_LpszTemplatename can be a string name, or an integer id using makeintResource):

// In DLGKEYS.RC in this article

IDD_MYDIALOG Accelerators Discardable

Begin

VK_RETURN, ID_MY_ENTER, VIRTKEY, NOINVERT

End Once you have loaded acceleration keys, the rest is to overload the PretranslateMessage function:

Bool CMYDLG :: PretranslateMessage (MSG * PMSG)

{

IF (WM_KeyFirst <= PMSG-> MESSAGE &&

PMSG-> Message <= WM_KEYLAST)

{

Haccl Haccel = m_haccel;

IF (Haccel &&

:: TranslateAccelerator (M_HWND, HACCEL, PMSG))

Return True;

}

Return CDIALOG :: PretranslateMessage (PMSG);

} The reason why the button class (from WM_ KeyFirst to WM_KEYLAST) is to increase the speed. If you know that you are not a button message, you don't have to waste time to call TranslateAccelerator. Then the TranslateAccelerator is a virtual function that does not have to add a message mapping entry. Just write this function.

In summary, the method of adding acceleration key functionality in the MFC is: load the accelerator key and overload the PretranslateMessage function. That is, if you decide to use the accelerator button, you don't have to worry about ONGETDEFID, but the ID of the command processor is mapped to VK_RETURN. The example of this article encapsulates a new dialog class for a speed button: CDLGWINACCELERATORS, which is a general class. I hope everyone likes it. Finally, I wish everyone a happy program.

转载请注明原文地址:https://www.9cbs.com/read-86221.html

New Post(0)