|
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 ResourcesTo 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 FilesIt 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.
Translating ResourcesIf 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 FormatThere 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 HandlersThe 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 ControlsAn 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. |
|