Author: Kenny Kerr
Translation: dflying Chen
Original article: http://weblogs.asp.net/kennykerr/archive/2006/07/18/Windows-Vista-for-Developers-_1320_-Part-2-_1320_-Task-Dialogs-in-Depth.aspx
For more information, see Windows Vista for developers.
Just as the aero wizard is more friendly than the traditional wizard, the task dialog box (Task DIALOG) that replaces the original message window can also bring a better user experience. Compared with message windows, the task dialog box provides many new functions and greatly enhances the customization capability. Of course, with the enhancement of these functions, the complexity also increases. In part 2 of the Windows Vista for developers series, I will use native C ++ to demonstrate how to effectively use the task dialog box API to create various dialogs. If you are not patient, go directly to the end of this article and find the download link. This link contains a complete API for the c ++ encapsulated task dialog box.Source code.
Comctl32.dllA library namedCtaskdialogThe C ++ class of implements all the functions provided by the task dialog box. You can callComctl32.dllInTaskdialogAndTaskdialogindirectFunction to use the task dialog box.TaskdialogIt is actually a simple version.TaskdialogindirectIt simplifiesTaskdialogindirectBut it is slightly easier to use. ActuallyTaskdialogAndTaskdialogindirectIt is not that simple, so this article will briefly introduceTaskdialogindirectThen, it is encapsulated with C ++ to make it easier to use.
The following sectionCodeThe following is a simple task dialog box:
Taskdialogconfig Config = {Sizeof(Taskdialogconfig )};
IntSelectedbuttonid = 0;
IntSelectedradiobuttonid = 0;
Bool verificationchecked = false;
Hresult result =: taskdialogindirect (& config,
& Selectedbuttonid,
& Selectedradiobuttonid,
& Verificationchecked );
TaskdialogconfigThe structure contains the fields and tags required for the Create task dialog box, and a callback function is provided to respond to the events triggered by the task dialog box:
StructTaskdialogconfig
{
Uint cbsize;
Hwnd hwndparent;
Hinstance;
Taskdialog_flags dwflags;
Taskdialog_common_button_flags dwcommonbuttons;
Pcwstr pszwindowtitle;
Union
{
Hicon hmainicon;
Pcwstr pszmainicon;
};
Pcwstr pszmaininstruction;
Pcwstr pszcontent;
Uint cbuttons;
ConstTaskdialog_button * pbuttons;
IntNdefaultbutton;
Uint cradiobuttons;
ConstTaskdialog_button * pradiobuttons;
IntNdefaultradiobutton;
Pcwstr pszverificationtext;
Pcwstr pszexpandedinformation;
Pcwstr pszexpandedcontroltext;
Pcwstr pszcollapsedcontroltext;
Union
{
Hicon hfootericon;
Pcwstr pszfootericon;
};
Pcwstr pszfooter;
Pftaskdialogcallback pfcallback;
Long_ptr lpcallbackdata;
Uint cxwidth;
};
As you can imagine, it is not easy to create such a structure. It is inevitable that such errors will occur. Although we can ignore many of these fields, the following fields are required to achieve the expected results:
- CbsizeThe field specifies the size of the structure during the compilation period. In C, this technique is often used to differentiate the version of the struct. The operating system can use this field to know the version of the structure, so that the data fields in the structure can be assumed and used based on the version information.
- HwndparentThe field stores the handle of the parent window. In this way, the dialog box is displayed in a modal mode and its position relative to the parent window can be set.
- HinstanceFields are very useful for C ++ developers. They allow us to specify their strings and ICON resources in resource files by using identifiers instead of being manually loaded or created in code.
- DwflagsFields are saved with Different tags to control the behaviors and styles of the dialog box. This article will be detailed in the following sections.
Text captions)
TaskdialogconfigThe structure contains the following fields to set the text descriptions in the task dialog box respectively.
Pszwindowtitle
Pszmaininstruction
Pszcontent
Pszverificationtext
Pszexpandedinformation
Pszexpandedcontroltext
Pszcollapsedcontroltext
Pszfooter
You can use string pointers orMakeintresourceThe string identifier created by Macro. In addition, you can set text descriptions for custom buttons, which will be detailed in the next section.
It demonstrates the location of different text descriptions:
Before creating the dialog box, we can usePszwindowtitleSet "window title" in the figure ". After the dialog box is created, you must useSetwindowtextFunction.
Before creating the dialog box, we can usePszmaininstructionSet "main instruction ". After the dialog box is created, you must useTdm_set_element_textThe message updates the text. SetWparamIsTde_main_instructionAnd setLparamA string pointer orMakeintresourceThe string identifier created by Macro. "Content", "Verification text", "expanded information", and "footer" text can also be set in a similar way, as long as it is passedWparamDifferent values are used to differentiate the controls to be operated. "Expanded control text" and "collapsed control text" can only be used before the dialog box is createdPszexpandedcontroltextAndPszcollapsedcontroltextField settings. Windows Vista with version 5456 has a bug in expanding/folding extension information-if the control loses the input focus, the text is reset to the text in the folding state.
Setting these text descriptions is not easy. It depends on where the text is obtained and what you want to set. Later in this article, we will use C ++ to simplify it.
Button
The task dialog box supports the combination of common buttons and custom buttons. Currently, common buttons include the following:
- Tdcbf_ OK _button (idok)
- Tdcbf_yes_button (idyes)
- Tdcbf_no_button (IDNO)
- Tdcbf_cancel_button (idcancel)
- Tdcbf_retry_button (idretry)
- Tdcbf_close_button (idclose)
We can combine these tags in any way and set themDwcommonbuttonsField. The constant in the brackets is the identifier of the button to identify which button the user clicks.
Download the source code at the end of this ArticleCommon buttons sampleDemonstrate these common buttons:
We cannot directly change the order of these common buttons and their text descriptions. To fully control these buttons, you must provideTaskdialog_buttonStructure array. The following code specifies two custom buttons:
Taskdialogconfig Config = {Sizeof(Taskdialogconfig )};
Taskdialog_button buttons [] =
{
{101, l"First button"},
{102, l"Second button"}
};
Config. pbuttons = buttons;
Config. cbuttons = _ countof (buttons );
We can also useMakeintresourceMacro specifies the string resource that the button will use. In addition to buttons, the task dialog box also provides a series of single tasks. You can use oneTaskdialog_buttonSpecify the array of the structure:
Taskdialog_button radiobuttons [] =
{
{201, l"First radio button"},
{202, l"Second radio button"}
};
Config. pradiobuttons = radiobuttons;
Config. cradiobuttons = _ countof (radiobuttons );
The running result of this Code is as follows:
We can also useTdf_use_command_linksThe user-defined buttons are displayed as command links. If you do not want the icon next to the link, useTdf_use_command_links_no_icon.
As you can see, these identifiers can only affect custom buttons. The normal button is still displayed as a regular style.
We can also sendTdm_set_button_elevation_required_stateMessage to this window, so that the "Notorious" User Account Control icon can be displayed next to the link (why is it notorious? -- Translator's question ).
This message applies to any custom button, whether in the form of command link or conventional button. By the way, for normal buttons such as OK and cancel, this message is also applicable, although this makes the user look unfriendly.
Icon
We can also display a "Main" icon and a "footer" icon in the task dialog box. The main icon is displayed next to the main text in the dialog box.Tdf_can_be_minimizedIn the title bar of the window. The footer icon is displayed next to the footer text.
Setting icons is tricky. Before the dialog box is createdMakeintresourceThe Resource Identifier of the icon created by macro is setPszmainiconField. If you use this method, do not setTdf_use_hicon_mainMark. You can also set the icon handleHmainiconField. If this method is used, make sure thatTdf_use_hicon_mainMark.
The footer icon is similar.PszfootericonField is used to specify the icon resource identifier before the create dialog box. You can also set the icon handleHfootericonField (similarly, make sure thatTdf_use_hicon_footerMark ).
After the dialog box is created, we can sendTdm_update_iconTo update these icons. To update the master iconWparamSetTdie_icon_mainTo update the footer iconWparamSetTdie_icon_footer.LparamTo be set as the icon Resource Identifier or icon handle, it depends onTdf_use_hicon_mainAndTdf_use_hicon_footerTag settings.
As you can see, the text description is not that easy to handle. Later, our c ++ solution will also simplify this operation.
Progress bar
A commendable feature provided by the new task dialog box is to support progress bars and setTdf_show_progress_barTo display the progress bar. You can useTdf_show_marquee_progress_barMark. After the dialog box is created, you can also sendTdm_set_progress_bar_marqueeThe message switches between the standard progress bar and the progress bar style. SetWparamSetTrueYou can switch to the drive lamp progress bar and set itFalseSwitch to the general progress bar.LparamThe animation Delay Time in milliseconds.
SendTdm_set_progress_bar_rangeYou can specify the range of the progress bar for a message.LparamThe lower byte part specifies the lower limit of the range, and the higher byte part represents the upper limit.Tdm_set_progress_bar_posThe message is used to specify the position of the progress bar in the specified range.WparamSet the Location Value.
SendTdm_set_progress_bar_stateYou can change the progress bar status,WparamOptionalPbst_normal,Pbst_pausedOrPbst_error.
In the download code of this articleProgress sampleAndProgress effects sampleDemonstrate all progress bar functions.
Notifications)
The task dialog box notifies external users.ProgramIts current status can be used to add behaviors or respond to events in the dialog box. These notifications can be specifiedPfcallbackThe callback function of the field is obtained. The callback function is prototype as follows:
Hresult _ stdcall callback (hwnd handle,
Uint notification,
Wparam,
Lparam,
Long_ptr data );
This prototype seems misleading because none of the messages are returned.Hresult. Some messages return values, but only boolean values (TrueOrFalse. The handle parameter provides a handle for the task dialog box window.Tdn_destroyedBefore the notification arrives, we can control the dialog box as we like. The data parameter specifiesLpcallbackdataThe pointer of the value in the field. It is often used to pass the pointer of a C ++ window object to a static callback function. Let's take a look at these notifications.
Tdn_dialog_constructedIs the first arrival notification. In addition to providing the handle of the task dialog box, this notification also indicates that the dialog box is created and will be displayed soon. In this case, you can send any message used to modify the style before the dialog box is displayed. ThenTdn_createdNotifications, but we usually don't need to care about this unless you have to do some window-specific initialization work. Some initialization work in these two notifications is legal, although it is not provided in page navigationTdn_createdNotification (but will still be providedTdn_dialog_constructedNotification ). The navigation will be discussed later.
As the name suggests,Tdn_button_clickedThe notification indicates that you have clicked a button, including the common button and Custom button. If you click the X button in the upper-right corner of the dialog box or press the ESC key on the keyboard, the notification will also be sent, but you need to setTdf_allow_dialog_cancellationMark.WparamIndicates the identifier of the clicked button. In the previous sections of this article, we have discussed the buttons and their corresponding tokens. If you want to close this dialog box, you should returnFalse. If you do not want to disable the function, returnTrue.
Tdn_radio_button_clickedThe notification indicates that a single-choice button is selected.WparamIndicates the identifier of the selected radio button. The Return Value of the notification is useless.
Tdn_helpThe notification indicates that you have pressed the F1 (HELP) key on the keyboard. We 'd better provide some help here.
Tdn_verification_clickedThe notification indicates that the status of the check box has changed. If not selectedWparamIsFalse, If selectedTrue.
Tdn_expando_button_clickedThe notification indicates that the user has clicked the area used to collapse/expand the "expanded information" content. If it is in the collapsed StateWparamIsFalse, If it is in the expanded state, it isTrue.
Tdn_hyperlink_clickedThe notification indicates that you have clicked a hyperlink in the task dialog box. Hyperlinks are supported only in "content", "expanded information", and "footer" sections, and must be setTdf_enable_hyperlinksMark. Hyperlinks are marked by HTML anchors (A) Definition, for example:
<A href ="Uri"> Text </a>
Note that only double quotation marks are supported, so the characters may need to be escaped. Long strings can also use links. The href attribute of the link can beLparamAccess, and then we can handle it as needed, such as opening a webpage. The task dialog box does not provide any default behavior for the link. The mainwindow class in the download code demonstrates how to use hyperlinks.
Tdn_timerThe notification provides a timer, which can be used to implement many different functions, such as updating the content of the dialog box and closing the dialog box after a period of time. IfTdf_callback_timerTag, then a message is sent every about 200 milliseconds.Tdn_timerNotification. DownloadTimer sampleDemonstrate the timer function:
Message)
The task dialog box can respond to a series of messages. We can use this mechanism to control and implement some required behaviors.
Tdm_click_buttonAndTdm_click_radio_buttonThe message is used to simulate a user clicking a button or a single button.WparamSpecifies the identifier of the button or radio button,LparamIt is useless here.
Tdm_click_verificationThe message is used to simulate a user clicking the confirm check box.WparamIndicates whether the check box is selected,LparamIndicates whether the check box needs to obtain the input focus.
Tdm_enable_buttonAndTdm_enable_radio_buttonThe message is used to enable or disable a button or radio button.WparamSpecifies the identifier of the button or radio button,LparamIndicates whether the button or single-choice button is enabled.
One of the notifications I did not mention in the previous section isTdn_navigatedBecause there are no relevant documents. This notification correspondsTdm_navigate_pageMessages are closely related, so I think it may be better to put them here.Tdm_navigate_pageThere are also no relevant documentation instructions. After a period of single-step debugging (of course, the operating system symbol is used here), I finally understand its usefulness. These messages allow us to switch from one task dialog box or navigate to another, just like a forward wizard. The "New" task dialog box will get the ownership of the "old" task dialog box, that is, you do not need to create a new task dialog box. I am tracking in the anti-CompilerComctl32.dllCode,Tdm_navigate_pageThe message processing program is not usedWparamBut expectLparamProvideTaskdialogconfigStructure to describe the dialog box to be navigated. ThenTdn_navigatedThe notification is associated with the callback function of the new task dialog box. DownloadError sampleThis function is demonstrated.
Use C ++ to make everything simple
The task dialog box is naturally powerful, but it is not so easy for developers to use. Despite exposing only two functions, the C language API of the task dialog box is still complex. To solve this problem, I specially wrote thisTaskdialogC ++ class simplifies the process of operating the task dialog box in C ++.TaskdialogThe class inherits fromCwindowClass, which encapsulates most of the task dialog box functions, will be a lot of preparationTaskdialogconfigThe complex work is abstracted. You can also send messages and respond to notifications. All programs in the downloaded code use thisTaskdialogSo you have no sample code.
The following is the source code of a sample task dialog box, which can be found in the download code:
ClassTimerdialog:PublicKerr: taskdialog
{
Public:
Timerdialog ():
M_reset (False)
{
Setwindowtitle (L"Timer sample");
Setmaininstruction (L"Time elapsed: 0 seconds");
Addbutton (L"Reset", Button_reset );
M_config.dwflags | = tdf_allow_dialog_cancellation |
Tdf_callback_timer;
}
Private:
Enum
{
Button_reset = 101
};
Virtual VoidOntimer (DWORD milliseconds,
Bool& Reset)
{
Cstring text;
Text. Format (L"Time elapsed: %. 2f seconds",
Static_cast <Double> (Milliseconds)/1000 );
Setmaininstruction (text. getstring ());
Reset = m_reset;
M_reset =False;
}
Virtual VoidOnbuttonclicked (IntButtonid,
Bool& Closedialog)
{
Switch(Buttonid)
{
CaseButton_reset:
{
M_reset =True;
Break;
}
CaseIdcancel:
{
Closedialog =True;
Break;
}
Default:
{
Assert (False);
}
}
}
BoolM_reset;
};
As you can see,TaskdialogClass provides a simple and object-oriented operation task dialog box. You no longer need to directly generate the lengthy and complex struct or manually define the button array. All of these details areTaskdialogClass.TaskdialogClass provides methods for setting/modifying the text description and icons in the task dialog box, addition of buttons and sending methods for various messages, and a series of virtual methods for responding to notifications.
Using the task dialog box defined above is a simple task:
Timerdialog dialog;
Dialog. domodal ();
InDomodalAfter the method is returned, we can useGetselectedbuttonid,GetselectedradiobuttonidAndVerificiationcheckedMethod to obtain the button selected by the user.
If you want to knowTaskdialogClass hides the complexity.SetwindowtitleCode of the method:
VoidKerr: taskdialog: setwindowtitle (ATL: _ u_stringorid text)
{
If(0 = m_hwnd)
{
M_config.pszwindowtitle = text. m_lpstr;
}
Else If(Is_intresource (text. m_lpstr ))
{
CstringString;
// Since we know that text is actually a resource ID we can ignore the pointer truncation warning.
# PragmaWarning (push)
# PragmaWarning (Disable: 4311)
Verify (String. Loadstring (m_config.hinstance,
Reinterpret_cast <uint> (text. m_lpstr )));
# PragmaWarning (POP)
Verify (setwindowtext (String));
}
Else
{
Verify (setwindowtext (text. m_lpstr ));
}
}
Here I use_ U_stringoridClass to set the string pointer or resource identifier. If you have not created the Task dialog box, simply updateTaskdialogconfigStructure. Otherwise, callSetwindowtextFunction to update the title of the window. In this way, developers callSetwindowtitleThere is no problem with the method, no need to worry about the source of the text, or whether the dialog box has been created.
Sample program
The instance program mentioned in this article can be downloaded here. It demonstrates all the features mentioned in this article: http://www.kennyandkarin.com/kenny/vista/taskdialogsamplecpp.zip.
Hmm ...... It seems that this articleArticleThe length is much longer than I expected (it is also more than I expected, so tired-the Translator's note ). The task dialog box API of Windows Vista provides so many functions that I cannot compress. I suddenly realized that this is the only complete task dialog box reference document. We hope to benefit as many readers as possible.
Originally, I wanted to demonstrate the task dialog box function in managed code, but Daniel moth has made a good version with C. He also talked about webcast, which demonstrated several ways to create a Task dialog box, including the task dialog designer I mentioned in the msdn magazine article. One thing to mention is that this Webcast has an error:Kerr. VistaIs a COM component. In fact, this is a simple. Net Assembly written in C ++/CLI.