Cross-Platform GUI Programming with wxWidgets

Although you should make your application as intuitive as possible so that the user rarely has to resort to the manual, it's important to supply online help for all but the simplest application. You could supply it as a PDF file or even an HTML file to be viewed by the user's favorite browser, but it will make a much better impression if you use a special-purpose help system and link to appropriate topics from all your dialogs and from your main window.

wxWidgets has the concept of help controller, a class that your application uses to load help files and show topics. Several help controller classes are supported:

  • wxWinHelpController, for controlling RTF-based WinHelp files on Windows (extension hlp). This format is deprecated, and new applications should use wxCHMHelpController.

  • wxCHMHelpController, for controlling MS HTML Help files on Windows (extension chm).

  • wxWinceHelpController, for controlling Windows CE Help files (extension htm).

  • wxHtmlHelpController, for controlling wxWidgets HTML Help files on all platforms (extension htb).

wxHtmlHelpController is different from the others in that instead of merely being a wrapper for an external help viewer, it is part of an entire help system implementation, and the help window resides in the same process as the application. If you want to use the wxWidgets HTML Help viewer as a separate process, compile HelpView in utils/src/helpview in your wxWidgets distribution. The files remhelp.h and remhelp.cpp implement a remote help controller (wxRemoteHtmlHelpController) that you can link with your application to control the HelpView instance.

Note that at the time of writing, there is no special help controller class for Mac OS X help files. You can use wxWidgets HTML Help files on this platform.

Figure 20-1 and Figure 20-2 show the same topic displayed in MS HTML Help and wxWidgets HTML Help viewers under Windows. The two provide similar functionality: HTML content on the right, and on the left, a hierarchy of topics, an index of topic names, and a keyword search facility. In addition, wxWidgets HTML Help can load multiple help files.

Figure 20-1. MS HTML Help

Figure 20-2. wxWidgets HTML Help

Using a Help Controller

Normally you will create a help controller object that will last the lifetime of the application instance, probably as a pointer member of your application class (create the object in OnInit and delete it in OnExit). Make it a pointer so that you can delete it fully in OnExit because some help controller implementations rely on a dynamic library loading class that is not available when the application object is being deleted. Then call Initialize with the name of the help file. You can omit the file extension, and wxWidgets will supply the relevant one for the current platform. For example:

#include "wx/help.h" #include "wx/fs_zip.h" bool MyApp::OnInit() { ... // Required for wxWidgets HTML help wxFileSystem::AddHandler(new wxZipFSHandler); m_helpController = new wxHelpController; m_helpController->Initialize(helpFilePath); ... return true; } int MyApp::OnExit() { delete m_helpController; ... return 0; }

Note that here we leave it to wxWidgets to choose the appropriate help class: wxHelpController is an alias for wxCHMHelpController on Windows and wxHtmlHelpController on other platforms. You can use wxHtmlHelpController for all platforms if you want, but it's better to use a native help viewer when possible.

When the help controller has been successfully initialized, you can show the help to the user with functions illustrated in the following:

// Show the contents m_helpController->DisplayContents(); // Display the topic whose title is "Introduction" m_helpController->DisplaySection(wxT("Introduction")); // Display the given HTML topic within the help file m_helpController->DisplaySection(wxT("wx.html")); // Display the given topic by ID (WinHelp, MS HTML Help only) m_helpController->DisplaySection(500); // Search for a keyword m_helpController->KeywordSearch(wxT("Getting started"));

Typically, you'll want to call DisplayContents from the event handler for a menu item Help Contents in the application's Help menu. You might have other important topics listed on the Help menu, and you can display them via DisplaySection. If you want to use the topic title with DisplaySection, all the topic titles in the help file must be unique.

You also might want to add a Help button to all non-trivial custom dialogs in your application to show an explanation of the current dialog and its controls. However, there is a catch here: showing help from a modal dialog does not work on all platforms. Where the help viewer is an external application (for example, when using wxCHMHelpController on Windows), you can display help from a modal dialog. But when the help controller shows a modeless window that is part of the same program, as with wxHtmlHelpController, you have to be careful because in general, you cannot display a modeless window (such as a frame) from within a modal dialog. By definition, a modal dialog won't enable you to switch to another arbitrary window except for another modal dialog. If you use wxGTK, there is a workaround that allows this to work for wxHtmlHelpController, but on Mac OS X, you need to either use an external help viewer (such as HelpView as mentioned earlier) or show the help in a modal dialog. The latter method is described in the next section.

Extended wxWidgets HTML Help

The wxWidgets HTML Help system is great, but it does have a couple of limitations. Firstly, it can only display help in its own frame, so it can't be used for embedded help, such as in a tab on your main window. Secondly, as a result of the previous limitation, it doesn't address the problem of displaying a modeless help window from a modal dialog.

To overcome these limitations, there is a variant of wxWidgets HTML Help that implements the help viewer as a window that can be shown as a child of any window. You can copy it from examples/chap20/htmlctrlex on the CD-ROM or download it from ftp://biolpc22.york.ac.uk/pub/contrib/helpctrlex.

If you compile it with your application, you can embed wxHtmlHelp WindowEx in your application and control it with wxHtmlHelpControllerEx before using the usual controller functions for displaying help. Here's an example of embedding:

#include "helpwinex.h" #include "helpctrlex.h" bool MyApp::OnInit() { ... m_embeddedHelpController = new wxHtmlHelpControllerEx; m_embeddedHelpWindow = new wxHtmlHelpWindowEx; m_embeddedHelpWindow->SetController(m_embeddedHelpController); m_embeddedHelpController->SetHelpWindow(m_embeddedHelpWindow); m_embeddedHelpController->UseConfig(config, wxT("EmbeddedHelp")); m_embeddedHelpWindow->Create(parentWindow, wxID_ANY, wxDefaultPosition, wxSize(200, 100), wxTAB_TRAVERSAL|wxNO_BORDER, wxHF_DEFAULT_STYLE); m_embeddedHelpController->AddBook(wxT("book1.htb")); m_embeddedHelpController->AddBook(wxT("book2.htb")); return true; } int MyApp::OnExit(void) { if (m_embeddedHelpController) { m_embeddedHelpController->SetHelpWindow(NULL); delete m_embeddedHelpController; } ... return 0; }

To solve the modal dialog problem, you can use the wxModalHelp class to show a topic in a modal dialog. When the user has finished browsing the help, clicking on the Close button takes control back to the previous dialog. The following code is all that's needed to show a topic:

wxModalHelp help(parentWindow, helpFile, topic);

It would be inconvenient to make a distinction between modal help and normal help throughout your application, so here's a function that you can use to make life easier:

// Shows help using normal help controller or // modal help controller if modalParent is non-NULL void MyApp::ShowHelp(const wxString& topic, wxWindow* modalParent) { #if USE_MODAL_HELP if (modalParent) { wxString helpFile(wxGetApp().GetFullAppPath(wxT("myapp"))); wxModalHelp help(modalParent, helpFile, topic); } else #endif { if (topic.IsEmpty()) m_helpController->DisplayContents(); else m_helpController->DisplaySection(topic); } }

The symbol USE_MODAL_HELP should be defined for those platforms that use wxHtmlHelpController. When you want to show help from a modal dialog, pass a pointer to the dialog to ShowHelp, and if necessary, it will be shown in its own modal dialog. When help isn't shown from a modal dialog, just pass NULL as the second argument of ShowHelp.

Authoring Help

Most help files nowadays are based on HTML. To make it even easier to author help on multiple platforms, wxWidgets HTML Help uses the same project, contents, and keyword files as the input to a MS HTML Help file. This way, you only have to deal with one set of files for all platforms. These are the files you'll need to create your help file:

  • A set of HTML files, one per topic.

  • A contents file (extension hhc) with an XML description of the topic hierarchy.

  • An optional keyword file (extension hhk) that maps words and phrases to HTML topics.

  • A project file (extension hhp) that describes all the other files in the project and specifies project options.

You then compile the project file into an MS HTML Help file (extension chm) or a wxWidgets HTML Help file (extension htb). For the former, use Microsoft's HTML Help Workshop, which can be invoked either from the command line or as a GUI application. For the latter, simply use your favorite zip utility to make a zip archive, renaming it with an htb extension.

Although you could write your help file by hand, it's much more convenient to use a tool. You can use a tool intended for MS HTML Help file creation, but be aware that it may output HTML that wxWidgets HTML Help cannot recognize. Anthemion Software's HelpBlocks is the only tool that specifically targets both MS HTML Help and wxWidgets HTML Help and assists you with writing HTML and organizing keywords.

To get a feel for a good help file structure, look at the help in other applications. You might consider including the following topics: Contents, Welcome, Contacts, Installation, Registration, Release notes, Tutorial, Using menu commands, Using toolbar commands, Using dialogs (with descriptions of all dialogs as subtopics), Using keyboard shortcuts, Command-line options, and Troubleshooting.

Remember that topics you show from the application should be designed to be standalone. Other topics, such as a tutorial, read better in a more linear fashion.

Other Ways to Provide Help

You might think of other ways to offer the user online help, perhaps using the HTML classes that wxWidgets provides. For example, Anthemion Software's Writer's Café has a modal welcome dialog with a small number of suggested options, implemented using a wxHtmlWindow. These include showing a Quick Tour consisting of a number of HTML screens to quickly give the user an idea of what the product can do (see Figure 20-3). The advantage of doing it this way is immediacy. Novice users are guided along a fairly narrow path initially, and they do not have to find their way around a full help system with ample opportunities for getting lost and confused.

Figure 20-3. Quick Tour dialog in Writer's Café

Another popular method for providing online help is the opening tip. This is great for educating the user about the product's functionality in palatable chunks. As mentioned in Chapter 8, "Using Standard Dialogs," wxWidgets has a function wxShowTip that takes a parent window, a wxTipProvider pointer to tell wxWidgets where to find the tips, and a boolean for the initial value of a Show Tips at Startup check box. For example:

#include "wx/tipdlg.h" ... m_tipProvider = wxCreateFileTipProvider(tipFilename, currentTip); wxShowTip(parent, m_tipProvider, showAtStart);

Context-Sensitive Help and Tooltips

If possible, an application should provide context-sensitive help and the option of tooltips for controls. A tooltip is a little descriptive window that pops up over a control as the mouse pointer hovers over it. Context-sensitive help is similar, but the descriptive window is invoked by the user clicking on a button or menu item to initiate the help and then clicking on the window of interest. These topics are discussed in more detail in Chapter 9, "Creating Custom Dialogs," in the context of help for dialogs, but you can equally set context-sensitive help for arbitrary windows. For example, applications often have a What's This? item on the Help menu and toolbar, which enables the user to click on a window or control in the main window for further details. You don't have to restrict yourself to the way help is displayed by default: you can derive your own class from wxHelpProvider and implement ShowHelp yourself.

Some help controllers are able to display the context-sensitive help in a more "native" way than the default behavior. If you are using wxCHMHelpController, let wxWidgets use this help controller's context-sensitive help implementation, in the following way:

#include "wx/cshelp.h" m_helpController = new wxCHMHelpController; wxHelpProvider::Set( new wxHelpControllerHelpProvider(m_helpController));

The wxHelpControllerHelpProvider instance will use the help controller's DisplayTextPopup function to display context-sensitive help.

Note that context-sensitive help is not in the Mac OS X style guide, and so should be omitted on this platform.

Menu Help

When you append items to a menu, you have the option of specifying a help string. If the menu is part of a menu bar, and the menu bar's frame has a status bar, an item's help string will be displayed in the status bar when the mouse is over that item. You can set the status pane in which the help will be displayed using wxFrame::SetStatusBarPane (a value of -1 will disable it). The behavior is implemented in wxFrame using a default wxMenuEvent handler for EVT_MENU_HIGHLIGHT_ALL, so you can reimplement it to do something different, such as showing the help in a different window.

    Категории