This article compares MFC with wxWidgets in all aspects, especially its class hierarchy and some key macros, and provides an entry guide for MFC programmers to port wxWidgets. The layout is completed.
Dish
You may still be maintaining the old windows application built with Microsoft Foundation Classes (MFC), but now some customers require the Linux version. What should you do? You may have a skilled MFC developer in your team, but how can you accelerate Linux development? Don't worry; this article is for you. With the help of wxwindows (a portable GUI toolbox for C ++ and Python), I will use the Multiple Document Interface (MDI )) the text editor is used as an example to demonstrate how to port windows-only MFC applications to Linux. A small application like this helps us to focus on the specific details of the porting framework to avoid getting lost in the code. You can obtain the source code of the complete MFC Application and wxwindows application in the references section after this article.
Document/view Overview
I will demonstrate the application using a well-known document/view architecture because it can process documents like most applications. Even if your application does not use the document/view architecture, I recommend that you read it. As long as you are switching to this framework, you may want to add this feature.
In my wxwindows, I have pointed out some similarities between MFC and wxwindows. String typeCString,wxStringIt is very similar to the Event System. But there are more than these similarities. Wxwindows toolkit also provides class MFC support for the document/view architecture.
I will start from the comparison of core classes. The following table lists the classes involved in the document/view architecture of the two frameworks.
Table 1. Comparison of documents/Views
| Class |
MFC class |
Wxwindows |
| Document) |
Cdocument |
Wxdocument |
| View) |
Cview |
Wxview |
| Edit View) |
Ceditview |
N/ |
| Template Class) |
Cmultidoctemplate |
Wxdoctemplate |
| MDI parent Frame) |
Cmdiframewnd |
Wxdow.iparentframe |
| MDI child frame) |
Cmdichildwnd |
Wxdow.ichildframe |
| Document Manager) |
N/ |
Wxdocmanager |
In addition to editing the View class, each MFC class has its corresponding wxwindows class. (The part of MFC In the last item is empty because MFC does not have an independent document manager class. By application classCWinAppInternal processing documentation .) The following UML diagram demonstrates the relationships between these classes:
Figure 1. MFC class
Figure 2. wxwindows
Applications
Each Framework provides a class that represents the application itself. The MFC Application class declares a constructor, a method for initialization, a method for event processing, and a message ing table. You need the message ing table declaration and event processing method, because the "about" dialog box of the application will be processed by this class.
Application class: MFC
class CPortMeApp : public CWinApp { public: CPortMeApp(); virtual BOOL InitInstance(); afx_msg void OnAppAbout(); DECLARE_MESSAGE_MAP() }; |
Note: When I first created an MFC application, I used the Application Wizard included in Microsoft Visual Studio to create it, but in my code snippets, I will not give comments that are generated by the wizard and sometimes confusing (//{{AFX_MSGAnd similar things ). For the complete source code, see the zip compression documentation.
The corresponding wxwindows class looks slightly different. It also declares a constructor and a method for initialization, but does not need anything to process messages. As you will see later, the "about" dialog box is processed in the main framework class.
Application class: wxwindows
class PortedApp : public wxApp { public: PortedApp(); bool OnInit(); int OnExit(); protected: wxDocManager* m_docManager; }; |
As described below, this class requireswxDocManagerAttribute to process in the initialization methodOnInit()Template. Cleaning Method when the application exitsOnExit()Will delete thiswxDocManagerObject.
All applications require their entry points (also knownmain()OrWinMain()). The two frameworks are slightly different in implementing this. In MFC, create static objects of the application class as follows:
In wxwindowsIMPLEMENT_APP()MACRO:
If you are interested in what the macro is doing, check the header file.wx/app.hAnd find the header file in the downloadable source code. Basically, it inserts an appropriate entry point function for the platform in use. After you create an application class object, you need to initialize it. For MFC, Microsoft recommends that you do not use the constructor of the Application object to initialize the object. Instead, you should useInitInstance()Method. To perform any cleanup, implementExitInstance()Method.
Although there are many things to do during application initialization, here I will focus only on the Code related to the document/view. To establish a document/view framework,InitInstance()You must createCMultiDocTemplate, As shown below:
Create document/view code: MFC
CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_PORTMETYPE, RUNTIME_CLASS(CPortMeDoc), RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CPortMeView)); |
Wxwindows application providesOnInit()Method to perform any initialization, and provideOnExit()Used for cleanup. To create a document/view framework in a wxwindows application,OnInit()The method must be created like thiswxDocTemplate:
Create document/view code: wxwindows
m_docManager = new wxDocManager(); wxDocTemplate* pDocTemplate; pDocTemplate = new wxDocTemplate(m_docManager, "Pom", "*.pom", "", "pom", "Pom Doc", "Text View", CLASSINFO(PortedDoc),CLASSINFO(PortedView)); |
What MFC and wxwindows do is basically the same. The framework needs to know which document is related to which view and which document the combination processes. Types include descriptive names of documents and the file extensions of such documents. Both frameworks Use templates to handle this issue (note that this has nothing to do with the standard C ++ template ).
MFCCMultiDocTemplateYou can also save information about the child frameworks associated with the same document and add the template to the application objects that manage the template. WxwindowswxDocTemplateAn additional management templatewxDocManagerObject. Remember,wxDocManagerIs an attribute of the wxwindows application class.
After the document/view framework is initialized, the main framework of the application is created. In the MFC applicationInitInstance()Method, create a main framework as follows:
Create the main framework: MFC
CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); |
CallpMainFrame->LoadFrame(IDR_MAINFRAME)Load all information about the main framework from the resource file.
In wxwindows, you can create menus, dialogs, and controls from resource files, or create them in code. I prefer to create them in code, but if you want to separate code from resources, you should take a look at wxwindows Resource System (see wxwindows document topic Overview ).
Create the main framework: wxwindows
m_mainFrame = new MainFrame(m_docManager, (wxFrame*) NULL, "DocView Demo", wxPoint(0, 0), wxSize(500, 400), wxDEFAULT_FRAME_STYLE); // Set up menu bar... m_mainFrame->SetMenuBar(menu_bar); m_mainFrame->Centre(wxBOTH); m_mainFrame->Show(TRUE); SetTopWindow(m_mainFrame); |
Let me show you the documentation and view classes for each framework before you can view what happened after application Initialization is complete.
Document
The document stores the file-based data processed by the application. It loads the data from the file and saves the data back to the file when necessary. The declaration of this MFC class is similar to this:
File class declaration: MFC
class CPortMeDoc : public CDocument { protected: CPortMeDoc(); DECLARE_DYNCREATE(CPortMeDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); virtual ~CPortMeDoc(); DECLARE_MESSAGE_MAP()}; |
Note: This class has a protected constructor. Never directly create any objects of the class. On the contrary, the framework uses serialization to create a document. Therefore, you must useDECLARE_DYNCREATE()Macro. Wxwindows statements are similar to the following:
Document class declaration: wxwindows
class PortedDoc : public wxDocument { public: virtual bool OnSaveDocument(const wxString& filename); virtual bool OnOpenDocument(const wxString& filename); virtual bool IsModified() const; virtual void Modify(bool mod); private: DECLARE_DYNAMIC_CLASS(PortedDoc)}; |
DECLARE_DYNAMIC_CLASS()Macros are required because wxwindows dynamically creates objects of this class like MFC.
View
If the MFC application processes text documentsCEditViewIt is a good idea to derive a View class. This class provides basic editing functions and text controls in its client window. Here I follow my own suggestions. The declaration of the MFC View class is similar to this:
View class declaration: MFC
class CPortMeView : public CEditView { protected: CPortMeView(); DECLARE_DYNCREATE(CPortMeView) public: CPortMeDoc* GetDocument(); virtual void OnDraw(CDC* pDC); virtual BOOL PreCreateWindow(CREATESTRUCT& cs); virtual ~CPortMeView(); DECLARE_MESSAGE_MAP()}; |
In wxwindows, (not yet) there is no dedicated editing view. However, it is easy to create your own editing view. You only need to havewxTextCtrlDerived text control. View class processes controls and frameworks as class attributes. Therefore, wxwindows statements are similar to the following:
View class declaration: wxwindows
class PortedView : public wxView { public: MyTextCtrl* textsw; PortedView(); bool OnCreate(wxDocument* doc, long flags); void OnDraw(wxDC* dc); bool OnClose(bool deleteWindow = TRUE); private: wxMDIChildFrame* CreateChildFrame(wxDocument* doc, wxView* view); wxFrame* frame; DECLARE_DYNAMIC_CLASS(PortedView) }; |
In addition to common event handlers for window creation, window re-painting, and window closure, this class also provides a method to create a framework and populate its menu bar.
Although it is not a good idea to have public attributes, I am still doing this here for the sake of simplicity. This should be avoided in your application (I will remove it in a later version ).
Main framework
Now that you have a document and View class for processing and displaying data, and an application class for processing the document/view framework, you need a main framework class to interact with users. Similarly, the two frameworks provide similar functions, but the actual implementation is slightly different. The main framework class of MFC saves a status bar and a toolbar as attributes. The main framework class of MFC also provides some methods to process window creation and declare a message ing table. Note: This class is fromCMDIFrameWndDerived from, because the application has an MDI interface.
Main framework class: MFC
class CMainFrame : public CMDIFrameWnd { public: CMainFrame(); virtual ~CMainFrame(); virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() private: DECLARE_DYNAMIC(CMainFrame) }; |
The wxwindows main framework class saves menus as attributes, and also has the method of creating its toolbar, as well as declaring an event table and a method of handling the application's about dialog box. This application has an MDI interface, so this class is fromwxDocMDIParentFrameDerived from.
Main framework: wxwindows
class MainFrame : public wxDocMDIParentFrame { public: wxMenu* editMenu; MainFrame(wxDocManager* manager, wxFrame* frame, const wxString& title, const wxPoint& pos, const wxSize& size, long type); void OnAbout(wxCommandEvent& event); void RecreateToolbar(); private: DECLARE_CLASS(MainFrame); DECLARE_EVENT_TABLE(); }; |
Working Principle
The transplantation is complete. Let me review what needs to be done to achieve this. MFC Application class (derived fromCWinApp) Transplanted to the derived fromwxAppApplication class, including the initialization code. The MFC Document class (derived fromCDocument) Transplanted to the derived fromwxDocument. Use the MFC View class (derived fromCView) Transplanted to the derived fromwxView. In addition to these classes related to documents/views, the main framework class (derived fromCMDIFrameWnd) Transplanted to the derived fromwxDocMDIParentFrame.
In its current version, this application has been able to do a lot of work. It can process multiple text files. You can open, edit, and save these files, and keep the recent history of opened files. If you have to write these functions from scratch, more lines of code are needed-more lines of code mean more lines to be tested and maintained. In both frameworks, dedicated Command identifiers are used to process commonly used commands related to documents/views. Common file commands are new, open, and save. Common editing commands are cut, copy, and paste. Other frequently-used Commands include print commands (this command has not been implemented in this application) and help commands. The following table lists the command identifiers contained in the document/view architecture of the two frameworks.
Table 2. Standard command identifiers
| MFC |
Wxwindows |
| Id_file_open |
Wxid_open |
| Id_file_close |
Wxid_close |
| Id_file_new |
Wxid_new |
| Id_file_save |
Wxid_save |
| Id_file_save_as |
Wxid_saveas |
| Id_edit_cut |
Wxid_cut |
| Id_edit_copy |
Wxid_copy |
| Id_edit_paste |
Wxid_paste |
| Id_app_exit |
Wxid_exit |
| Id_edit_undo |
Wxid_undo |
| Id_edit_redo |
Wxid_redo |
| Id_help_index |
Wxid_help |
| Id_file_print |
Wxid_print |
| Id_file_print_setup |
Wxid_print_setup |
| Id_file_print_preview |
Wxid_preview |
Window Manager
If you are really interested in Linux development, you may have done some research and found that there are different Window managers in Linux. You may think this is strange when you were an MFC developer. During windows development, you don't have to worry about different Window managers, because there is only one window manager.
When you start wxwindows development, you may want to know whether your application will run on two mainstream Windows Managers, K desktop environments (K desktop environment (KDE) and gnome. I have used the wxwindows toolbox on Microsoft Windows NT 4.0, Sun Solaris 2.6 using the Common Desktop Environment (CDE), and Linux 2.2 using KDE. Wxwindows is only a high-level GUI toolbox built on other low-level, so you can choose how to build a Linux application. You can use motif version (or a better version, free lesstif) or wxwindows GTK + version. GTK + is the basic window component toolbox used by gnome, but it also runs very well in KDE. We recommend that you use the GTK + version because it is usually updated. Many developers develop it and some users use it. Therefore, if you want more help, you can turn to the email list or newsgroup to ask questions about GTK +.
The following figure shows the screen capture before, after, and after migration, which gives you a general understanding of the transplanted application.
Figure 3. Original MFC Application
Figure 4. wxwindows applications on Windows
Figure 5. wxwindows applications on Linux/KDE
Real stories
Wxwindows toolbox is not just another nerd. It is mature and stable, and people use it in practical applications to solve practical problems.
Julian smart, founder of wxwindows, is currently working on Red Hat. He has transplanted ECOs Configuration tool to wxwindows. The ECOs Configuration tool is a graphical tool used to configure the ECOS embedded operating system. People have ported the initial MFC Application to wxwindows, especially on Linux (see references ). SciTech software personnel have also used wxwindows to re-develop the front-end GUI for SciTech display doctor products. IBM has obtained a license for a dedicated version of SciTech display doctor, IBM now delivers it as the main display driver for all ibm OS/2 Warp-based operating systems, including warp client, workspace on demand, and warp server for e-business. SciTech software has made a positive contribution to the wxwindows community by submitting the extension packages wxapplet, wxuniversal, and wxmgl. With wxmgl, wxwindows applications can even run on DOS and other embedded operating systems, such as QNX, RT-target, and smx. SciTech software provides full support for wxuniversal and wxmgl projects (see references ).
Conclusion
This article demonstrates how to use the wxwindows toolkit to port Windows applications from the MFC documentation/view framework to Linux. Wxwindows toolkit has some similarities with the MFC framework to help MFC developers accelerate Linux development. With this basic knowledge, you should be able to port the best applications to Linux. But do not forget that wxwindows is not only applicable to Linux. Maybe it's time to consider running one version of your application on another Unix or even Macintosh.
References
- For more information, see the original article on the developerworks global site.
- Download the full source code of the original and transplanted applications demonstrated in this article from the Markus homepage.
- For an overview of wxwindows, read the Markus article to describe wxwindows (Developerworks, January 1, February 2001 ).
- The wxwindows homepage is the main place for wxwindows community members. It provides information and support for wxwindows, including downloads, email lists, sample applications, and wxwindows-related tools.
- Wxpython combines the Python script language with the wxwindows GUI library. For more information about wxpython, see wxpython for newbies (Developerworks, January 1, March 2001 ).
- Coding with kparts discusses the kparts architecture (Developerworks, January 1, February 2002 ).
- For more information about K desktop environments, visit the KDE homepage.
- For more information about gnome, see the gnome homepage.
- You can find more information about the Red Hat ECOs Configuration tool on the Red Hat site.
- You can get more information about SciTech display doctor on the Scitech software site.
- You can find more information about the OS/2 device driver package (which uses SciTech display doctor) on the OS/2 Warp page.
- InDeveloperworksYou can find more Linux articles in the Linux area.
About the author
|
|
|
Markus neifer initially used the logo language for programming, and later he used several basic languages. While studying Geoinformatics, he learned some C, but soon switched to C ++ and Java because these two languages have the object-oriented nature. He once worked in R & D and published articles on object-oriented development of technology software. Currently, he is a software engineer in the geographic information system field. You can contact Markus through a markus.neifer@gmx.net. |