Journal Articles
Browse in : |
All
> Journals
> CVu
> 153
(14)
All > Topics > Programming (877) Any of these categories - All of these categories |
Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.
Title: Generating Lists for C++ in Python
Author: Administrator
Date: 03 June 2003 13:15:57 +01:00 or Tue, 03 June 2003 13:15:57 +01:00
Summary:
In this, the second article in my Practical Uses for Python in C++ Series, I explore and provide examples of using Python [python] to generate lists for C++.
Body:
In this, the
second article in my Practical Uses for Python in C++ Series, I
explore and provide examples of using Python [python] to generate lists for C++. The particular
example I am going to use is the loading of country names into a
Combo Box (see figure 1). Most of my GUI development experience has
been with the Microsoft Visual C++ (MSVC) Graphical User Interface
(GUI) libraries. For this article I decided I would try out a new
cross-platform GUI framework library, with the idea that it may
help the article appeal to more people. I initially looked at Qt
[qt] but found various problems with it. I then
tried WxWindows [wxwindows] and found it
much easier to work with, after the initial set-up and
compilation.
At the time of writing the latest stable release of WxWindows is 2.4.0 and can be downloaded from the WxWindows Download [download] page. There are versions available for Windows, Unix (including Linux), MacOS and OS/2. Full installation and build instructions come with each package and are beyond the scope of this article. I would also recommend the wizard [wizard] for MSVC and Windows users.
Before writing the necessary Python script we need a test application with a Combo Box. This is quite easy with WxWindows and only requires two new classes - an application class and a dialog class. The dialog class holds the combo box and is defined as follows:
// PythonListsDialog.h (include guards omitted) #include "wx/dialog.h" #include "wx/combobox.h" #include "wx/textctrl.h" class PythonListsDialog : public wxDialog { public: PythonListsDialog(wxWindow *parent); private: virtual void InitDialog(); void OnComboTextChanged(wxCommandEvent &event); private: wxComboBox *m_pCombo; wxTextCtrl *m_pText; private: DECLARE_EVENT_TABLE() };
PythonListsDialog is implemented in the following way:
// PythonListsDialog.cpp #include "PythonListsDialog.h" #include "wx/icon.h" #include "wx/msgdlg.h" #include <memory> const wxWindowID comboId = 1000; const wxWindowID textId = 1001; BEGIN_EVENT_TABLE(PythonListsDialog, wxDialog) EVT_TEXT(comboId, PythonListsDialog::OnComboTextChanged) END_EVENT_TABLE() PythonListsDialog::PythonListsDialog(wxWindow *parent) : wxDialog(parent, -1, _T("Python Lists"), wxDefaultPosition, wxSize(200,100), wxDEFAULT_DIALOG_STYLE), m_pCombo(0), m_pText(0) {} void PythonListsDialog::InitDialog() { try { wxString comboContents[] = {""}; m_pCombo = new wxComboBox(this, comboId, "", wxPoint(10,40), wxDefaultSize, 0, comboContents, wxCB_DROPDOWN | wxCB_READONLY); // Extra check for implementations // where new does not throw. if (m_pCombo == 0) { throw std::bad_alloc("Failed to create combo box: new failed."); } m_pText = new wxTextCtrl(this, textId, "", wxPoint(10,10), wxDefaultSize, wxTE_READONLY); // Extra check for implementations // where new does not throw. if (m_pText == 0) { throw std::bad_alloc("Failed to create text box: new failed."); } } catch(const std::bad_alloc& e) { wxMessageBox(e.what(), wxString("Dialog Error"),wxOK,this); } } void PythonListsDialog::OnComboTextChanged( wxCommandEvent &event) { m_pText->SetValue(event.GetString()); }
The second class is the application class and is defined as follows:
// PythonListsApp.h (include guards omitted) #include "wx/wxprec.h" class PythonListsApp : public wxApp { private: virtual bool OnInit(); }; DECLARE_APP(PythonListsApp)
The application class implements its single override in the following way:
// PythonListsApp.cpp #include "PythonListsApp.h" #include "PythonListsDialog.h" IMPLEMENT_APP(PythonListsApp) bool PythonListsApp::OnInit() { // This will be deleted by the framework. PythonListsDialog* pDialog = new PythonListsDialog(0); pDialog->ShowModal(); return false; }
Now that we have an application with a Combo Box we need to fill it with country names. The wxComboBox method for adding strings to the combo box is Append(). Therefore the code to add countries would look something like this:
m_pCombo->Append("Afghanistan"); m_pCombo->Append("Albania"); m_pCombo->Append("Algeria"); .... m_pCombo->Append("Zimbabwe");
This would take some time to format and enter into the code by hand and if the list ever changed significantly (unlikely for countries, of course) it would need doing again. This is where Python comes in handy. If you have a list of countries in a text file, Python can be used to generate a function which will load all the countries into the combo box.
Start with a header file that declares the function which will load the countries:
// LoadCountries.h #ifndef LOADCOUNTRIES_H #define LOADCOUNTRIES_H #include "wx/combobox.h" void LoadCountries(wxComboBox* pComboBox); #endif // LOADCOUNTRIES_H
Then create a template for the cpp file. Call it something like 'LoadCountries_template.cpp':
// LoadCountries.cpp #include "LoadCountries.h" void LoadCountries(wxComboBox* pComboBox) { if (pComboBox != 0) { // Countries Here } }
The template file will be used to generate C++ along with the text file containing the list of countries. The comment:
// Countries Here
is used to tell the Python script where to write the countries in the generated C++ file.
Now it's time to write a Python script. Assuming that the list of countries is in a flat text file called 'countries.txt' and the C++ template is in a file called 'LoadCountries_template.cpp', the first thing we want the script to do is take the two input files and an output file as command line arguments:
# CountriesList.py import sys import string print "\nCountriesList.py\n" # Check Command Line Parameters if len(sys.argv) < 4: print "CountriesList.py requires three filenames \ as command line parameters: " "Countries, Template, OutputFile" else: print "Countries Filename:\t" + sys.argv[1] print "Template Filename:\t" + sys.argv[2] print "Output Filename:\t" + sys.argv[3] + "\n"
Then open, read in and store the list of countries and the template:
#Open and store Countries CountriesFile = open(sys.argv[1],"r") CountriesStore = CountriesFile.readlines() CountriesFile.close #Open and store Template TemplateFile = open(sys.argv[2],"r") TemplateStore = TemplateFile.readlines() TemplateFile.close
This list of countries I have is all in upper case and each country is followed by its abbreviation. For example:
AFGHANISTAN AF ALBANIA AL ALGERIA DZ AMERICAN SAMOA AS
Therefore as the Python script writes the C++ it not only needs to be able to spot the "// Countries Here" comment, it must also case the countries and remove the abbreviation. Also, each country must be wrapped in quotes (") as well as the Append method.
The "// Countries Here" comment must be detected during the writing of the output file. This can be done as follows:
#Write Output File OutputFile = open(sys.argv[3],"w") for templateline in TemplateStore: if templateline == "// Countries Here\n": # write countries here print "Countries Comment Found.\n" else: OutputFile.write(templateline) OutputFile.close() print sys.argv[3] + " written Ok."
Finally the countries must be formatted and written to the output file. Python makes this easy:
# loop through countries for line in CountriesStore: # Remove country abbreviation line = line [:line.rfind(" ")] # Case country line = string.capwords(line) # Write combo box loading country code to # output file OutputFile.write('\t\tpComboBox->Append("' + \ line + '");\n')
The complete Python script looks like this:
# CountriesList.py import sys import string print "\nCountriesList.py\n" # Check Command Line Parameters if len(sys.argv) < 4: print "CountriesList.py requires three filenames \ as command line parameters: " "Countries, Template, OutputFile" else: print "Countries Filename:\t" + sys.argv[1] print "Template Filename:\t" + sys.argv[2] print "Output Filename:\t" + sys.argv[3] + "\n" #Open and store Countries CountriesFile = open(sys.argv[1],"r") CountriesStore = CountriesFile.readlines() CountriesFile.close #Open and store Template TemplateFile = open(sys.argv[2],"r") TemplateStore = TemplateFile.readlines() TemplateFile.close #Write Output File OutputFile = open(sys.argv[3],"w") for templateline in TemplateStore: if templateline == "// Countries Here\n": # loop through countries for line in CountriesStore: # Remove country abbreviation line = line [:line.rfind(" ")] # Case country line = string.capwords(line) # Write combo box loading country code # to output file OutputFile.write('\t\tpComboBox->Append("' + \ line + '");\n') else: OutputFile.write(templateline) OutputFile.close() print sys.argv[3] + " written Ok."
To generate the LoadCountries.cpp file type the following at the command line, using the appropriate file paths:
python countriesList.py countries.txt
LoadCountries_template.cpp LoadCountries.cpp
Then add LoadCountries.cpp and LoadCountries.h to theWxWindows project. Add "#include "LoadCountries.h"" and "LoadCountries(m_pCombo);" to PythonListsDialog.h and rebuild:
// PythonListsDialog.h #include "PythonListsDialog.h" #include "wx\icon.h" #include "wx\msgdlg.h" #include "LoadCountries.h" #include <memory> ... void PythonListsDialog::InitDialog() { try { wxString comboContents[] = {""}; m_pCombo = new wxComboBox(this, comboId, "", wxPoint(10,40), wxDefaultSize, 0, comboContents, wxCB_DROPDOWN | wxCB_READONLY); LoadCountries(m_pCombo); ...
Running the executable created by rebuilding the WxWindows project will display a small dialog box with a Combo Box of countries. Selecting a country from the Combo Box displays its edit box above it (see figure). The full CountriesList.pyscript and a Microsoft Visual C++ 6.0 test application [source] are available for download from my website.
[python] Python: http://www.python.org/
[wxwindows] WxWindows: http://www.wxwindows.org
[download] WxWindows Download page: http://www.wxwindows.org/downld2.htm
[wizard] WxWindows wizard: http://www.wxwindows.org/dl_optn.htm
[source] Full CountriesList.py script and a Microsoft Visual C++ 6.0 test application: http://www.paulgrenyer.co.uk/download/python_lists.zip
Notes:
More fields may be available via dynamicdata ..