Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1478

[VB6] TaskDialogIndirect: Complete class implementation of Vista+ Task Dialogs

$
0
0
cTaskDialog


cTaskDialog is the sequel to my previous TaskDialogIndirect project, mTaskDialog. This version adds support for all TaskDialogIndirect features, including the progress bar, timer feedback, updating the text and icons while the dialog is open, and events for all the notifications. It's also much easier to use.

What is TaskDialog?

TaskDialog, introduced in Windows Vista, is a massive upgrade to the MessageBox. While not as simple, it offers a huge array of features... custom icons, custom button text, command link style buttons, expanded info button, a footer, a checkbox for 'i read this' or 'don't show this again' type messages, radio buttons, hyperlinks, and more.

This project can be used to create a simple messagebox like the older ones, to an extremely complex dialog with all the features mentioned, even all at once!

Before using cTaskDialog

The TaskDialog was introduced with version 6.0 of the common controls, with Windows Vista. That means a manifest is required for your compiled application, and for VB6.exe in order to use it from the IDE. In addition, your project must start from Sub Main() and initialize the common controls before any forms are loaded. The sample project includes Sub Main(), and see LaVolpe's Manifest Creator to create the manifests.

Setting Up cTaskDialog

Once you've got a project using the modern common controls, cTaskDialog is similar in use to a lot of other class modules, like the other common controls.

To initialize the class, put the following at the start of a form and in the Form_Load code:
Code:

Private WithEvents TaskDialog1 As cTaskDialog

Private Sub Form_Load()
Set TaskDialog1 = New cTaskDialog
End Sub

Now, you're all ready to begin using it. Let's start with a simple messagebox like we've seen before.



Creating this box is very straightforward. Unlike the previous incarnation, you don't have to worry about anything you're not using.

Code:

Private Sub Command2_Click()

With TaskDialog1
    .MainInstruction = "This is a simple dialog."
    .CommonButtons = TDCBF_YES_BUTTON Or TDCBF_NO_BUTTON
    .IconMain = TD_INFORMATION_ICON
    .Title = "cTaskDialog Project"
   
    .ShowDialog

    If .ResultMain = TD_YES Then
        Label1.Caption = "Yes Yes Yes!"
    ElseIf .ResultMain = TD_NO Then
        Label1.Caption = "Nope. No. Non. Nein."
    Else
        Label1.Caption = "Cancelled."
    End If
End With
End Sub

That's all it takes for a basic messagebox. The .Init() call resets the dialog. If you want to re-use all the previous settings and just change a couple things, it can be skipped.

Now that basic usage is covered, let's get down to what you really came for: advanced features!

Here's a few basic changes that make a much more fancy looking dialog:

Code:

    .Init
    .MainInstruction = "You're about to do something stupid."
    .Content = "Are you absolutely sure you want to continue with this really bad idea?"
    .CommonButtons = TDCBF_YES_BUTTON Or TDCBF_NO_BUTTON
    .IconMain = TD_SHIELD_WARNING_ICON 'TD_INFORMATION_ICON
    .Title = "cTaskDialog Project"
   
    .ShowDialog

This produces the following:




The TaskDialog supports several special shield icons that create the colored bar uptop. If you use a regular icon, or a custom icon, it will look like the dialog on the right.

All the other text fields are added the same way, so I'm just going to skip over those. One thing to note, with expanded information set, the little expando button appears automatically when you set those fields and requires no additional code to operate; where it appears is set by a flag, which is described later. Also note that the major text fields can be changed while the dialog is open, just set it again the same way.

One of the big features is the ability to customize the text on the buttons. Due to limitations in VB, I've implemented them by using a .AddButton function. You can assign the button the same id as one of the regular buttons, or give it a unique id. Custom buttons can be removed with .ClearCustomButtons so a full Init() call isn't needed.

Code:

With TaskDialog1
    .Init
    .MainInstruction = "You're about to do something stupid."
    .Content = "Are you absolutely sure you want to continue with this really bad idea?"
    .IconMain = TD_INFORMATION_ICON
    .Title = "cTaskDialog Project"
    .AddCustomButton 101, "YeeHaw!"
    .AddCustomButton 102, "NEVER!!!"
    .AddCustomButton 103, "I dunno?"
   
    .ShowDialog

    Label1.Caption = "ID of button clicked: " & .ResultMain
End With




Note that we have removed the .CommonButtons. If you specify buttons there as well, they will appear in addition to your custom buttons.

Radio buttons are added the exact same way as common buttons; and the ID of the radio button selected is found in the .ResultRad property.

Code:

    .AddRadioButton 110, "Let's do item 1"
    .AddRadioButton 111, "Or maybe 2"
    .AddRadioButton 112, "super secret option"
   
    .ShowDialog

    Label1.Caption = "ID of button clicked: " & .ResultMain
    Label2.Caption = "ID of radio button selected: " & .ResultRad



One of the other biggies are Hyperlinks. These require a few additional steps. First, you need to include TDF_ENABLE_HYPERLINKS in the .Flags property. Then, you add in the hyperlink as normal html, but the url needs to be in quotes, so you'll need chr$(34). Then you'll need to use one of the events for the class. The most common thing to do is just execute the link, so that's what's shown here, but you could also get the URL back from the pointer and do something else with it. You must use ShellExecuteW, not ShellExecuteA (which is normally what just plain ShellExecute points to). The declare is included in the sample project.

Code:

With TaskDialog1
    .Init
    .MainInstruction = "Let's see some hyperlinking!"
    .Content = "Where else to link to but <a href=" & Chr(34) & "http://www.microsoft.com" & Chr(34) & ">Microsoft.com</a>"
    .IconMain = TD_INFORMATION_ICON
    .Title = "cTaskDialog Project"
    .CommonButtons = TDCBF_CLOSE_BUTTON
    .Flags = TDF_ENABLE_HYPERLINKS
   
    .ShowDialog

    Label1.Caption = "ID of button clicked: " & .ResultMain
    Label2.Caption = "ID of radio button selected: " & .ResultRad
   
End With

Private Sub TaskDialog1_HyperlinkClick(ByVal lPtr As Long)

Call ShellExecuteW(0, 0, lPtr, 0, 0, SW_SHOWNORMAL)

End Sub



Let's talk about custom icons. You can have a custom icon for both the main icon and the footer icon, but you need to supply the function with an hIcon pointer. There's a number of different ways to accomplish this. The sample project uses a method I adapted from Leandro Ascierto's cMenuImage. It gets around VB's limitations on icons by adding them to the resource file as a custom resource, and not an icon. This way, you can include any size and any color depth and any number of them inside the .ico. Then, the ResIcontoHICON function will give you the hIcon you need for cTaskDialog. But remember, any other function returning an hIcon will work. Icons can also be updated while the dialog is open by another .IconMain= or .IconFooter= statement. You can use a standard icon for main and custom for footer, and vice versa, or both. When you're going to use a custom icon, you must include TDF_USE_HICON_MAIN/TDF_USE_HICON_FOOTER in the flags.
The icon size can't really be changed much; the main icon will be distorted but not larger if you give it a larger size, although you can make it a smaller size. The footer icon won't change at all.

Code:

With TaskDialog1
    .Init
    .MainInstruction = "What time is it?"
    .Content = "Is is party time yet???"
    .Footer = "Don't you love TaskDialogIndirect?"
    .Flags = TDF_USE_HICON_MAIN Or TDF_USE_HICON_FOOTER
    .IconMain = ResIconTohIcon("ICO_CLOCK", 32, 32)
    .IconFooter = ResIconTohIcon("ICO_HEART", 16, 16)
    .Title = "cTaskDialog Project"
    .CommonButtons = TDCBF_CLOSE_BUTTON
   
    .ShowDialog

    Label1.Caption = "ID of button clicked: " & .ResultMain

   
End With



The last basic feature is the verification checkbox. Here's an example with that, and all the other text fields. Note also what happens in this example when no buttons are specified anywhere: the OK button appears by default.

Code:

With TaskDialog1
    .Init
    .MainInstruction = "Let's see all the basic fields."
    .Content = "We can really fit in a lot of organized information now."
    .Title = "cTaskDialog Project"
    .Footer = "Have some footer text."
    .CollapsedControlText = "Click here for some more info."
    .ExpandedControlText = "Click again to hide that extra info."
    .ExpandedInfo = "Here's a whole bunch more information you probably don't need."
    .VerifyText = "Never ever show me this dialog again!"
   
    .IconMain = TD_INFORMATION_ICON
    .IconFooter = TD_ERROR_ICON
   
    .ShowDialog
   
    Label1.Caption = "ID of button clicked: " & .ResultMain
End With



One of the major stylistic differences are the CommandLink buttons. When using the Command Link style, the first line is considered the main text, and lines are made into sub-text. Note that the line is broken with vbLf only; not vbCrLf. vbCrLf results in the text not being smaller on Win7 x64, I haven't tested other systems but it should be the same.
With the custom button sample from above, these changes are made:

Code:

    .Flags = TDF_USE_COMMAND_LINKS
    .AddCustomButton 101, "YeeHaw!" & vbLf & "Put some additional information about the command here."



and that is what the dialog now looks like.

That covers all the basic functionality.

Advanced Features

The TaskDialog supports having a progress bar, both regular and marquee. To enable it, include the TDF_SHOW_PROGRESS_BAR or the TDF_SHOW_MARQUEE_PROGRESS_BAR flag (you can switch back and forth between them while the dialog is open if you want). Getting it to show up is the easy part, linking it to actual events in your program is where it gets a little tricky. There's some events that are provided that will help out...

TaskDialog_DialogCreated is triggered when the dialog is displayed, then all the buttons, the radio buttons, the expando button, the checkbox, and hyperlinks all have events when the user clicks them. In addition to that, TaskDialog_Timer is sent approximately every 200ms and includes a variable telling you how many ms has elapsed since the dialog appeared, or since it was reset with the .ResetTimer() call. The example shows a basic counter, but you can go further and enable/disable buttons and use hyperlinks to control things too.

Code:


Private bRunProgress As Boolean
Private lSecs As Long


With TaskDialog1
    .Init
    .MainInstruction = "You're about to do something stupid."
    .Content = "Are you absolutely sure you want to continue with this really bad idea? I'll give you a minute to think about it."
    .IconMain = TD_INFORMATION_ICON
    .Title = "cTaskDialog Project"
    .Footer = "Really, think about it."
    .Flags = TDF_USE_COMMAND_LINKS Or TDF_SHOW_PROGRESS_BAR Or TDF_CALLBACK_TIMER
    .AddCustomButton 101, "YeeHaw!" & vbLf & "Put some additional information about the command here."
    .AddCustomButton 102, "NEVER!!!"
    .AddCustomButton 103, "I dunno?"
    .VerifyText = "Hold up!"
    bRunProgress = True
   
    .ShowDialog

    Label1.Caption = "ID of button clicked: " & .ResultMain
End With


Private Sub TaskDialog1_DialogCreated(ByVal hWnd As Long)
Timer1.Interval = 1000
Timer1.Enabled = True
TaskDialog1.ProgressSetRange 0, 60

End Sub


Private Sub TaskDialog1_Timer(ByVal TimerValue As Long)
If lSecs > 60 Then
    Timer1.Enabled = False
    bRunProgress = False
Else
    TaskDialog1.ProgressSetValue lSecs
    TaskDialog1.Footer = "You've been thinking for " & lSecs & " seconds now..."
End If

End Sub

Private Sub TaskDialog1_VerificationClicked(ByVal Value As Long)
If Value = 1 Then
    Timer1.Enabled = False
    bRunProgress = False
Else
    bRunProgress = True
    Timer1.Enabled = True
End If
End Sub

Private Sub Timer1_Timer()
lSecs = lSecs + 1
End Sub




That's the basic feature set. The class allows an infinite number of customizations to take place from here.
Attached Files

Viewing all articles
Browse latest Browse all 1478

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>