SECCIONES
AÑADIR ARTÍCULO
CLUB TÉCNICO
CURSOS
WEB AMIGAS
| Fecha de publicación: 2008.04.09 | |
| Grado de Dificultad: 3 | |
wxWidgets allows developing one code base that will natively compile and run on a variety of platforms, including Windows, Windows CE, Linux, Unix, Mac OS X, OS/2, HP-UX and others, by wrapping the native APIs on each platform in one common API. The resulting applications are native for each platform, with native look and feel. While wxWidgets is written in C++, there are bindings for Python, Perl, Ruby, .NET, Haskell and others. In this article, Kevin will discuss some of the basic wxWidgets features and concepts. A small sample program is shown in 5 parts, with the complete program included on this issue’s CD. The code is not explicitly discussed line-by-line, but the functionality in the sample program is covered in the article. While the dominant personal computing platform today is Microsoft Windows, Linux and Mac OS X are also viable and well-supported. It is relatively easy to develop software for Windows thanks to standardized Microsoft APIs and tools, and doing so lets you target around 90% of computer users. When we originally developed BitWise IM ( http://www.bitwiseim.com), an instant messaging system, we developed only a Windows client. We were surprised by the demand for both Linux and OS X versions, but the resources were not available to develop and maintain three different code trees. What became clearer as time went on is that the potential for success with new software is much greater on Linux and OS X because the market isn't nearly as crowded. After some searching, our resource worries disappeared when we discovered wxWidgets ( http://www.wxwidgets.org ). wxWidgets allows developing one code base that will natively compile and run on a variety of platforms, including Windows, Windows CE, Linux, Unix, Mac OS X, OS/2, HP-UX and others, by wrapping the native APIs on each platform in one common API. The resulting applications are native for each platform, with native look and feel. While wxWidgets is written in C++, there are bindings for Python, Perl, Ruby, .NET, Haskell and others. In this article, I'll discuss some of the basic wxWidgets features and concepts. A small sample program is shown in 5 parts, with the complete program included on this issue's CD. The code is not explicitly discussed line-by-line, but the functionality in the sample program is covered in the article. The Application and Application SettingsThe wxApp class represents an application, implements the event loop and stores application-wide settings. Typically, you would override OnInit to perform custom initializations, read any startup settings, and create your main window. OnInit has a Boolean return value, allowing you to return false and immediately terminate the application if an error occurs while starting up. Each operating system stores users' preferences differently: Windows uses the registry, Linux uses dot files, and OS X uses a Preferences folder in each user home folder. wxWidgets automatically uses the correct location on each operating system using wxConfig. wxConfig is a typedef to one of the specific configuration classes, wxRegConfig or wxFileConfig, which both have the same API. One common challenge when writing an application is preventing multiple instances. wxSingleInstanceChecker allows you to check for another running instance of the application. The wxSingleInstanceChecker object must be active during the lifetime of the application, so it is usually deleted in the application OnExit handler, which also gives you a chance to define your application's return value. A wxWidgets application will continue to run until all windows have been closed. One notable exception is that a system tray icon also counts as a window, allowing you to create an application that can be minimized to the system tray (on Windows or Linux). Listing 1 shows the application initialization and shutdown code for the sample program. Windows, Frames, Panels and DialogsAll controls and windows in wxWidgets derive from wxWindow. This is similar to the CWnd class in MFC. Common methods such as SetSize, SetFont, Show, Hide, GetParent, etc. are in wxWindow. GUI controls all derive from the wxControl class, a small class that processes user I/O. wxControl also derives from wxWindow. To create a window, use the wxFrame or wxDialog classes. The wxFrame class is a robust class allowing menus, toolbars, and status bars. The wxPanel class is used in conjunction with a wxFrame to provide a surface on which to place controls that matches the expected background color for the system. The wxDialog class is more functionally limited, designed primarily for quick user input, or to display a message. wxWidgets includes some standard dialogs for common tasks such as entering a password, asking the user to make a selection from a list of choices, choosing a color, choosing a font, etc. Where possible, these dialogs are native. Where native dialogs are not available, generic wxWidgets-created dialogs are used. Therefore, a given dialog will always exist, even if a generic substitute has to be used. MenuswxWidgets handles different UI paradigms among the different platforms wherever possible. For example, unlike on Windows or Linux, OS X has only one menu bar, which is always at the top of the screen and changes as you switch applications; the menu bar for a given application usually does not change. Your window menus will automatically be placed on this native menu bar. If you create an application with different menus on different windows, the menu bar on OS X will change as you switch windows. Frequent changing of the menu bar is unexpected behavior on OS X, so you should consider your menu layouts during the design phase of your application. wxWidgets automatically handles several special menu cases on OS X. Every application on OS X has its own application menu, providing access to data sharing capabilities as well as common application-wide items such as About, Preferences and Quit. By using the built-in identifiers wxID_ABOUT, wxID_PREFERENCES and wxID_EXIT, wxWidgets will automatically move these items from the � ir placed locations to the OS X application menu. Figure 1 shows the application menu of the sample program.
Figure 1. Application Menu on OS X Listing 2 shows the code for creating the sample program's main frame, including the menu bar and a simple status bar. Sizers and Window LayoutsI originally came from an MFC background where window layouts used absolute positioning and sizing. This works well when targeting Windows, where controls are always the same size and shape, but not very well when controls have varying sizes between platforms. By using sizers, window layouts can adjust at runtime to platform-specific control sizes. Adjusting the size is necessary for supporting not only varying default fonts and sizes, but also for supporting interfaces that may be translated into other languages. All controls and sizers have four main attributes: a minimum size (in pixels), a border, an alignment, and a stretch factor. Some controls are able to define their own minimum height and width, such as a checkbox, whereas other controls have no real minimum size, such as a text field or a listbox, which require one or both minimum sizes to be explicitly set. A sizer minimum size is always determined by the minimum size of its children. A border defines how much empty space appears around the specified sides of the control or sizer. Alignment controls how the item will align itself if there is empty space around it, including the option to expand (grow) to fill the empty space. The stretch factor is the most complex of the options, determining how a sizer distributes surplus space among its children. The default value of 0 indicates that the child will not expand past its minimum size. A non-zero value indicates a proportion of all stretch factors of that item's siblings. If the stretch factor of item X is one and the sum of all the siblings' stretch factors is four, item X will receive one-fourth of the extra space. See Figure 2 for a simple example of stretch factors using three buttons.
Figure 2. Stretch Factor Example Using sizers means that you typically would not define the size of the window, nor assign specific sizes to all of the controls. For example, a button can size itself based on the platform's default button height and the length of the button's label. A single-line text control can determine its own minimum height, but would need a minimum width specified. Certain controls, such as text controls or list controls, have no specific minimum sizes, and would need minimum sizes defined. When a window is created, it queries its outermost sizer for its size. That outermost sizer, in turn, would query its children for their sizes (which could be programmer-defined minimum sizes, the controls' minimum sizes based on their content, or stretched sizes based on the stretch factors). The children could be specific controls, empty space, or other sizers, in which case the size query continues recursively. Once each sizer knows the size of its children, it can report back to its parent and the window size and layout can be finalized. This size determined by the outermost sizer represents the minimum size for the window. When a window is resized, the queries are remade, and the window layout can automatically adjust. Widgets/ControlsAs previously mentioned, almost all of the controls that you see in wxWidgets are native controls with wxWidgets wrapping the native API. What this means for you is that your application genuinely feels like it was created for that platform. No other GUI library offers the same level of native appearance. If a native control is not available, generic versions or platform-specific approximations are available. The native controls extend even to platform-specific functionality. For example, GTK+ 2 themes have a set of "stock buttons" such as OK, Cancel, Close, Save, etc that usually include both a graphic and text. wxWidgets automatically uses the stock buttons when you specify a stock ID and the stock label. This technique is shown in the sample program, on the Close button. Designing Windows with Sizers and WidgetsUnderstandably, most wxWidgets developers find it tedious to develop window layouts by hand, instead relying on a GUI tool. The two most widely-used tools are wxDesigner (http://www.roebling.de), written by Robert Roebling, and DialogBlocks (http://www.anthemion.co.uk/dialogblocks/), written by Julian Smart. Both are core wxWidgets developers, and both tools have a variety of round-trip features available, including being able to add event handlers into your application code. Which tool is better is usually a matter of personal preference. The main window for the sample program as previewed by wxDesigner is shown in Figure 3, showing the initial values and sizes for each control. The corresponding hierarchy of sizers and controls is shown in Figure 4. The resulting code automatically generated by wxDesigner is the SDJMainFrame function is in Listing 3. It should be obvious looking at the code why doing layouts by hand can be time-consuming.
Figure 3. Window Preview in wxDesigner
Figure 4. Control Layout in wxDesigner Events and Event HandlingwxWidgets provides event handling using event tables. Every event handler that you write will have one parameter taking an event object derived from wxEvent. Some events derive from wxNotifyEvent, which adds methods for allowing or vetoing an event, such as denying a label edit on a tree or preventing a window from closing. Listing 4 shows the event macros for the sample program. The most common type of event is a wxCommandEvent, which is used to notify the application of actions on buttons, checkboxes, choices, comboboxes, listboxes, menus, sliders, radio buttons, and toolbars. A wxCommandEvent object provides accessors such as GetInt, GetSelection, GetString, IsChecked and IsSelection to allow processing the event without needing to access the originating control. For example, if the user enables a checkbox, IsChecked would return true in the corresponding event. Listing 5 shows the event handling code for the sample program; notice how the same event handler is used for the Quit menu item as well as the Close button, which is possible because buttons and menu selections both use a command event. When an event occurs, wxWidgets searches for an event handler, starting with the most-derived class (for example, MyTreeCtrl would be the most-derived class from the chain: MyTreeCtrl inherits from wxTreeCtrl inherits from wxControl inherits from wxWindow ). If that class does not handle the event, each base class is tried until an event handler is found. If no event handler is found, the event is ignored. Once an event handler is found, it is invoked. If the object's parent should also process the event, use the Skip method to let the event continue propagating up. More complex controls, such as list controls, notebooks, spinners, splitters and trees have their own event classes so that more complex data can be passed to the event handler. For example, when processing a tree event, you would want to know which item the event is for, what the item's label is, or where the item is in the tree. The idea is that an event handler should have all the information needed to process the event from the event object. Introduction to InternationalizationIn order to keep the sample application short, it does not contain any internationalization. However, wxWidgets provides many facilities for adapting to different locales and languages:
Running the Sample Program & Exploring wxWidgets FurtherIf you want to try the sample program yourself, you will need to download and compile the wxWidgets library for your platform. You can build the sample program by copying the files minimal.cpp and minimal.h (on this issue's CD) into the minimal sample folder and then building the minimal sample. Many wxWidgets users use the samples' makefiles / projects as a starting point for their own makefiles / projects. The resulting windows created on Windows XP, Linux (GTK+ 2) and OS X are shown in Figures 5, 6 and 7, respectively. Unless you were privy to knowing that wxWidgets was used to create the windows, you could never tell based on how great they look.
Figure 5. Sample Program on Windows XP
Figure 6. Sample Program on Linux
Figure 7. Sample Program on Mac OS X If you want to learn more about a specific wxWidgets feature, wxWidgets includes a plethora of samples in the sample directory of the installation. The documentation for wxWidgets also includes dozens of "Topic Overviews" that provide discussion and code examples for more advanced features, such as internationalization, container classes, streams, device contexts, document/view, event handling and multithreading. If you want to dive into wxWidgets, the book Cross-Platoform GUI Programming with wxWidgets provides everything you need to get up and running quickly. SummaryThe wxWidgets library is a powerful tool for building native look and feel applications. While this article and the sample program barely scratch the surface of all that wxWidgets has to offer, it is representative of the clean and easy to use API. Whether you are interested in targeting multiple platforms or only one for your next project, give wxWidgets a try. I'sure you'll agree that wxWidgets is not only easy to use but also stable, robust and powerful. As the website says, it "makes cross-platform programming childs play. Well, almost." Special thanks to Julian Smart and Alton Sanders for editing and reviewing this article. Listing 1. Application Initialization and Shutdown
Listing 2. Window Creation
Listing 3. Window Layout
Listing 4. Event Table
Listing 5. Event Handling GNU General Public License |
|
| Autor: Kevin Hock | Nota: |
| Volver | |

