Using wxWidgets Resource Files

team bbl


You can load specifications of dialogs, frames, menu bars, toolbars, and so on from XML files with extension xrc instead of creating these elements explicitly in C++ code. This enables better separation of code and user interface, such as enabling an application's dialog design to be changed at runtime. XRC files can be exported by a range of UI design tools, including wxDesigner, DialogBlocks, XRCed, and wxGlade.

Loading Resources

To use XRC files in your application, you need to include wx/xrc/xmlres.h in your application code.

If you will be converting your XRC files to binary XRS files, as we will describe shortly, install the zip file system handler by placing an AddHandler call in your OnInit function:

 #include "wx/filesys.h" #include "wx/fs_zip.h" wxFileSystem::AddHandler(new wxZipFSHandler); 

Initialize the XRC system by adding this to your OnInit:

 wxXmlResource::Get()->InitAllHandlers(); 

Load the XRC file with code like this:

 wxXmlResource::Get()->Load(wxT("resources.xrc")); 

This makes wxWidgets aware of the resources in the file; to create a real UI element, we need another call. For example, the following fragment creates a dialog whose resource name is dialog1:

 MyDialog dlg; wxXmlResource::Get()->LoadDialog(& dlg, parent, wxT("dialog1")); dlg.ShowModal(); 

The following code shows how to load menu bars, menus, toolbars, bitmaps, icons, and panels.

 MyFrame::MyFrame(const wxString& title): wxFrame(NULL, -1, title) {     SetMenuBar(wxXmlResource::Get()->LoadMenuBar(wxT("mainmenu")));     SetToolBar(wxXmlResource::Get()->LoadToolBar(this,                                                   wxT("toolbar")));     wxMenu* menu = wxXmlResource::Get()->LoadMenu(wxT("popupmenu"));     wxIcon icon = wxXmlResource::Get()->LoadIcon(wxT("appicon"));     SetIcon(icon);     wxBitmap bitmap = wxXmlResource::Get()->LoadBitmap(wxT("bmp1"));     // Finish creating panelA after making an instance of it     MyPanel* panelA = new MyPanel;     panelA = wxXmlResource::Get()->LoadPanel(panelA, this,                                                        wxT("panelA"));     // A second method: get XRC to both create and load panelB     wxPanel* panelB = wxXmlResource::Get()->LoadPanel(this,                                                        wxT("panelB")); } 

wxWidgets maintains a single wxXmlResource object that you can use, but alternatively, you can create a wxXmlResource object, load resources, and then destroy it. You can also use wxXmlResource::Set to set the current global resource object, destroying the old one.

To define event tables for windows loaded from a resource file, you can't use integer identifiers because resources have string names. Instead, use the XRCID macro, which takes a resource name and returns an integer identifier associated with the name. XRCID is an alias for the function wxXmlResource:: GetXRCID. Here's an example of XRCID usage:

 BEGIN_EVENT_TABLE(MyFrame, wxFrame)     EVT_MENU(XRCID("menu_quit"),  MyFrame::OnQuit)     EVT_MENU(XRCID("menu_about"), MyFrame::OnAbout) END_EVENT_TABLE() 

Using Binary and Embedded Resource Files

It can be convenient to combine a number of resource files into one binary file (extension xrs). To compile XRC files into a zip file that the resource system can load, use the utility wxrc located in the utils/wxrc directory in your wxWidgets distribution:

 wxrc resource1.xrc resource2.xrc -o resource.xrs 

Use wxXmlResource::Load to load a binary resource file in just the same way as with a plain XML file.

Tip

Instead of creating a separate zip file for your XRC files, you can include them in a single zip file that includes other files your applications needs, such as HTML files, images, and so on. wxXmlResource::Load accepts virtual file system specifications, as described in Chapter 14, "Files and Streams," so you can write

 wxXmlResource::Get()->Load(wxT("resources.bin#zip:dialogs.xrc")); 


You can also compile your XRC files into C++ code that may be embedded in your application, thereby eliminating a separate resource file. Here's the wxrc command to do this:

 wxrc resource1.xrc resource2.xrc c -o resource.cpp 

Compile this C++ file as normal and link it with your application. The file includes a function InitXmlResource, which you have to call, for example:

 extern void InitXmlResource(); // defined in generated file wxXmlResource::Get()->InitAllHandlers(); InitXmlResource(); 

Table 9-2 lists the command-line options and arguments that wxrc accepts.

Table 9-2. wxrc Commands

Short Command

Long Command

Description

-h

help

Shows a help message.

-v

verbose

Shows verbose logging information.

-c

cpp-code

Writes C++ source rather than an XRS file.

-p

python-code

Writes Python source rather than an XRS file.

-e

extra-cpp-code

If used together with -c, generates a C++ header file containing class definitions for the windows defined by the XRC file.

-u

uncompressed

Do not compress XML files (C++ only).

-g

gettext

Outputs underscore-wrapped strings that poEdit or gettext can scan. Outputs to stdout, or a file if -o is used.

-n

function <name>

Specifies a C++ initialization function name (use with -c).

-o <filename>

output <filename>

Specifies the output file, such as resource.xrs or resource.cpp.

-l <filename>

list-of-handlers <filename>

Outputs a list of resource handlers that are needed for the specified resources.


Translating Resources

If the wxXmlResource object has been created with the wxXRC_USE_LOCALE flag (the default behavior), all displayable strings will be subject to translation, as detailed in Chapter 16, "Writing International Applications." However, poEdit cannot scan XRC files for strings to translate as it can for C++ code, so you can create a file of such strings using wxrc with the -g option. For example:

 wxrc -g resources.xrc -o resource_strings.cpp 

Then you can run poEdit to scan the strings in this and other files.

The XRC Format

There isn't space to describe the XRC format in detail, but here is an example showing a simple dialog with sizers:

 <?xml version="1.0"?> <resource version="2.3.0.1"> <object  name="simpledlg">     <title>A simple dialog</title>     <object >       <orient>wxVERTICAL</orient>       <object >         <object >           <size>200,200d</size>           <style>wxTE_MULTILINE|wxSUNKEN_BORDER</style>           <value>Hello, this is an ordinary multiline\n textctrl....</value>         </object>         <option>1</option>         <flag>wxEXPAND|wxALL</flag>         <border>10</border>       </object>       <object >         <object >           <object >             <object  name="wxID_OK">               <label>Ok</label>               <default>1</default>             </object>           </object>           <object >             <object  name="wxID_CANCEL">               <label>Cancel</label>             </object>             <border>10</border>             <flag>wxLEFT</flag>           </object>         </object>         <flag>wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_RIGHT</flag>         <border>10</border>       </object>     </object>   </object> </resource> 

A detailed specification of the XRC format can be found in the technical note docs/tech/tn0014.txt in your wxWidgets distribution. If you use an editor to create your user interfaces, you won't need to know about XRC's format.

You may be wondering how a text XRC file can be used to specify binary bitmaps and icons. These resources may be specified as URLs, and wxWidgets' virtual file system will extract them from sources such as a zip file. For example:

 <object  name="wxID_OK">   <bitmap>resources.bin#zip:okimage.png</bitmap> </object> 

See Chapter 10, "Programming with Images," and Chapter 14, "Files and Streams," for more information on using virtual file systems to load resources such as images.

Writing Resource Handlers

The XRC system uses a resource handler to recognize the XML specification of each type of resource. If you write your own custom control, you may want to write a resource handler so that applications can use the custom control with XRC.

As an illustration, the declaration for wxButton's handler looks like this:

 #include "wx/xrc/xmlres.h" class wxButtonXmlHandler : public wxXmlResourceHandler { DECLARE_DYNAMIC_CLASS(wxButtonXmlHandler) public:     wxButtonXmlHandler();     virtual wxObject *DoCreateResource();     virtual bool CanHandle(wxXmlNode *node); }; 

The handler implementation is quite simple. In the handler's constructor, the XRC_ADD_STYLE macro is used to make the handler aware of specific button styles, and AddWindowStyles is called to add common window styles. In DoCreateResource, the button object is created in two steps, using XRC_MAKE_INSTANCE and then Create, extracting parameters such as the label, position, and size. Finally, CanHandle tests whether this handler can handle the node in question. It's permissible for a single handler class to handle more than one kind of resource.

 IMPLEMENT_DYNAMIC_CLASS(wxButtonXmlHandler, wxXmlResourceHandler) wxButtonXmlHandler::wxButtonXmlHandler() : wxXmlResourceHandler() {     XRC_ADD_STYLE(wxBU_LEFT);     XRC_ADD_STYLE(wxBU_RIGHT);     XRC_ADD_STYLE(wxBU_TOP);     XRC_ADD_STYLE(wxBU_BOTTOM);     XRC_ADD_STYLE(wxBU_EXACTFIT);     AddWindowStyles(); } wxObject *wxButtonXmlHandler::DoCreateResource() {    XRC_MAKE_INSTANCE(button, wxButton)    button->Create(m_parentAsWindow,                     GetID(),                     GetText(wxT("label")),                     GetPosition(), GetSize(),                     GetStyle(),                     wxDefaultValidator,                     GetName());     if (GetBool(wxT("default"), 0))         button->SetDefault();     SetupWindow(button);     return button; } bool wxButtonXmlHandler::CanHandle(wxXmlNode *node) {     return IsOfClass(node, wxT("wxButton")); } 

To use a handler, an application needs to include the header and register the handler, as follows:

 #include "wx/xrc/xh_bttn.h" wxXmlResource::AddHandler(new wxBitmapXmlHandler); 

Foreign Controls

An XRC file can specify a foreign, or "unknown" control, by specifying in the object definition. This can stand in for a control that is actually created in the C++ code, after the parent is loaded from XRC. When XRC loads the unknown object, a placeholder window is created. Then the application calls AttachUnknownControl to superimpose the real window onto the placeholder window, with the correct position and size. For example:

 wxDialog dlg; // Load the dialog wxXmlResource::Get()->LoadDialog(&dlg, this, wxT("mydialog")); // Make an instance of our new custom class. MyCtrl* myCtrl = new MyCtrl(&dlg, wxID_ANY); // Attach it to the dialog wxXmlResource::Get()->AttachUnknownControl(wxT("custctrl"), myCtrl); // Show the dialog dlg.ShowModal(); 

The custom control definition can look like this:

 <object  name="custctrl">   <size>100,100</size> </object> 

Using this technique, you can lay out interfaces in tools that don't know about your custom controls, and you also avoid the need to write a resource handler.

    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net