From: A.M. K. <aku...@us...> - 2001-03-28 18:57:48
|
Update of /cvsroot/py-howto/pyhowto In directory usw-pr-cvs1:/tmp/cvs-serv23717 Added Files: wxpython.tex Log Message: First draft of wxPython HOWTO from Lucas Bruand --- NEW FILE --- % ================================================================================== % % HOWTO : wxPython, a cross-platform GUI Library % $ Id $ % ================================================================================== \documentclass{howto} \usepackage{epsfig} \input epsf \title{wxPython, a cross-platform GUI Library } \release{0.03} \author{The wxPython community} \authoraddress{\email{luc...@ec...} } \begin{document} \maketitle \ifhtml \chapter*{Front Matter\label{front}} \fi % ================================================================================== \begin{abstract} \noindent In this document, we present a cross-platform GUI ( Graphical User Interface) called wxPython. We shall be using wxPython 2.2.5 . We shall also introduce a few advanced topics that make the strength of wxPython. This document is available in several formats, including PostScript, PDF, HTML and plain ASCII, from the Python HOWTO page at \url{http://py-howto.sourceforge.net/}. \end{abstract} % ================================================================================== \tableofcontents % ================================================================================== \section{What is wxPython ? } WxPython ranks amongst the toolkits that enable writing cross-platform GUI-applications like \module{pyQT}, \module{pyGTK}, or \module{Tkinter}. But under windows, and unlike \module{Tkinter} or \module{pyGTK}, a \module{wxPython} Application has a look and feel very similar to what you would get with an application using microsoft native GUI, MFC \footnote{Microsoft Foundation Classes}. This is because wxPython is a fine layer over the native GUI classes. Besides this, wxPython is very simple to learn and takes advantage of the possibilities Python is offering. By instance, events handling is particularly nice under wxPython. In fact, wxPython is simply (?) Python Bindings to a C++ Library called wxWindows; dating back from 1992 \footnote{It's almost as old as Tkinter - which dates back from 1990}, wxWindows is now a very stable, efficient, object-oriented library running (smoothly) on Windows, Unix ( GTK/Motif/Lesstif) and soon Macintosh. % ================================================================================== \section{Prerequisites} We assume the reader has sufficient knowledge of Python and is familiar with classes and objects in Python\footnote{ If you are not already a Pythonista,you might want to have a look at \url{http://www.crosswinds.net/~agauld } }. No other knowledge is required. % ================================================================================== \section{Installation} \subsection{Windows} Installation under windows is especially simple: Run the installer you can get from \url{http://www.wxpython.org/download.php} and follow the instructions. \subsection{Linux - Redhat} You can find RPMs for Redhat (they are working just fine with Mandrake though), at the address \url{http://www.wxpython.org/download.php}. \subsection{Linux - Building from the source} TO DO % TO BE CONTINUED. % ================================================================================== \section{A first application - Hello, world} As is traditional, we are first going to write a Small "Hello, world" application. Here is the code: % Old code: % from wxPython.wx import * % class HelloApp(wxApp): % def OnInit(self): % frame = wxFrame(None,-1,"Hello, world") % frame.Show(true) % self.SetTopWindow(frame) % return true % app = HelloApp() % app.MainLoop() % New code: \begin{verbatim} from wxPython.wx import wxPySimpleApp, wxFrame app = wxPySimpleApp() frame = wxFrame(None, -1, "Hello World") frame.Show(1) app.MainLoop() \end{verbatim} \begin{figure} \epsfig{file=helloworld.eps} \caption{Hello, World application} \end{figure} % After importing \module{wxPython} GUI, we derive our new application from wxPython's original application abstract class. This lets use rewrite the \method{OnInit} method. % This is where the real work is: % We instantiate a new \keyword{Frame}\footnote{A frame in wxPython is a window with its titlebar, reduction and close buttons, etc... it can be a normal application window, a MDI parent frame, etc...} with the constructor \class{wxFrame}. We make this \keyword{Frame} appear by "showing" it. Eventually, we tell the application that this frame is going to be its Topwindow ( so that the application terminates when you close the frame). % Explaination: After importing \module{wxPython} GUI, we instantiate a new \class{wxPySimpleApp} and a new \class{wxFrame}. A frame in wxPython is a window with its titlebar, reduction and close buttons, etc... \footnote{it can be a normal application window, a MDI parent frame, etc...} We make this \keyword{Frame} appear by "showing" it. Eventually, we start the application's \method{MainLoop} whose role % ================================================================================== \section{Pushing it a bit further - Marvels of wxPython} In this section, we shall build a little editor. This is mostly to convince you of the inner capabilities and of the simplicity of use of wxPython. If you are already convinced you might as well want to read first \emph{Advanced Topics}. \subsection{Adding the edit component} The first step is to add a new edit component. The code herein appears, by courtesy of Mr Michael Roberts\footnote{ See Also his excellent article in Useful resources }. \begin{verbatim} from wxPython.wx import * class MainWindow(wxFrame): """ We simply derive a new class of Frame. """ def __init__(self,parent,id,title): wxFrame.__init__(self,parent,-4, title, size = ( 200,100), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.control = wxTextCtrl(self, 1, style=wxTE_MULTILINE) self.Show(true) app = wxPySimpleApp() frame = MainWindow(None, -1, "Sample editor") frame.Show(1) app.MainLoop() \end{verbatim} %class EditApp(wxApp): % def OnInit(self): % frame = MainWindow(None,-1,"A sample edit ctrl") % frame.Show(true) % self.SetTopWindow(frame) % return true %app = EditApp() %app.MainLoop() As you can see, it is not very difficult: All we have to do is to derive \class{wxFrame} and then overload its \method{__init__} method. In this method, we declare a new \class{wxTextCtrl}, which is a simple text edit control. Here, You might probably want to have a look at the demoes that are bundled with the install package, since they deal with all sort of subjects and show very well how easy and rich wxPython is. \subsection{ Adding a menu} Every application should have a menu bar and a status bar. Let's add that to ours: \begin{verbatim} from wxPython.wx import * ID_ABOUT=101 ID_EXIT=110 class MainWindow(wxFrame): def __init__(self,parent,id,title): wxFrame.__init__(self,parent,-4, title, size = ( 200,100), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.control = wxTextCtrl(self, 1, style=wxTE_MULTILINE) self.CreateStatusBar() # A Statusbar in the bottom of the window # Setting up the menu. filemenu= wxMenu() filemenu.Append(ID_ABOUT, "&About"," Information about this program") filemenu.AppendSeparator() filemenu.Append(ID_EXIT,"E&xit"," Terminate the program") # Creating the menubar. menuBar = wxMenuBar() menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. self.Show(true) app = wxPySimpleApp() frame = MainWindow(None, -1, "Sample editor") frame.Show(1) app.MainLoop() \end{verbatim} The only little problem is that our application does little more that showing our new menu: As it is, our menu is a deadborn deprived of any reaction. Let's implement reactions into our program: \subsection{ Practical event handling} Reacting to events in wxPython is called \keyword{event handling}. Flexible event handling is one of the biggest strengths of wxPython. We are going to present practical basic event handling and we'll discuss later in \emph{advanced topics}, the why and how. An event is a small message sent by wxPython to your application to signify that "something" has happened \footnote{the mouse has been moved, a key has been pressed, the user has popped up the menu, everything you might possibly think of...}. Most often, in wxPython, all you have to do, is to "connect" an event with a particular method. This is done by calling the pseudo methods \method{EVT_*}. By instance: \begin{verbatim} EVT_MENU(self, ID_ABOUT, self.OnAbout ) \end{verbatim} In other words, from now on, any menu selection event with ID, ID_ABOUT that is sent to window \code{self}, will be passed to the method \method{self.OnAbout}. The latter method has the general declaration: \begin{verbatim} def OnAbout(self, event): ... \end{verbatim} where event is an instance of a subclass of wxEvent. Let's now have a look at what it is like in our application: \begin{verbatim} from wxPython.wx import * ID_ABOUT=101 ID_EXIT=110 class MainWindow(wxFrame): def __init__(self,parent,id,title): wxFrame.__init__(self,parent,-4, title, size = ( 200,100), style=wxDEFAULT_FRAME_STYLE| wxNO_FULL_REPAINT_ON_RESIZE) self.control = wxTextCtrl(self, 1, style=wxTE_MULTILINE) self.CreateStatusBar() # A Statusbar in the bottom of the window # Setting up the menu. filemenu= wxMenu() filemenu.Append(ID_ABOUT, "&About"," Information about this program") filemenu.AppendSeparator() filemenu.Append(ID_EXIT,"E&xit"," Terminate the program") # Creating the menubar. menuBar = wxMenuBar() menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the # method self.OnAbout EVT_MENU(self, ID_EXIT, self.OnExit) # attach the menu-event ID_EXIT to the # method self.OnExit self.Show(true) def OnAbout(self,e): d= wxMessageDialog( self, " A sample editor \n" " in wxPython","About Sample Editor", wxOK) # Create a message dialog box d.ShowModal() # Shows it d.Destroy() # finally destroy it when finished. def OnExit(self,e): self.Close(true) # Close the frame. app = wxPySimpleApp() frame = MainWindow(None, -1, "Sample editor") frame.Show(1) app.MainLoop() \end{verbatim} % ================================================================================== \subsection{More magic} Of course an editor is useless if it is not able to save or open documents. That's where Common dialogs come in. Those dialogs are those offered by the underlying platform so that your application will exactly look like a native application. Here is the implementation of the OnOpen method in \class{MainWindow} : \begin{verbatim} def OnOpen(self,e): """ Open a file""" dlg = wxFileDialog(self, "Choose a file", self.dirname, "", "*.*", wxOPEN) if dlg.ShowModal() == wxID_OK: self.filename=dlg.GetFilename() self.dirname=dlg.GetDirectory() f=open(self.dirname+'\\'+self.filename,'r') self.control.SetValue(f.read()) f.close() dlg.Destroy() \end{verbatim} This method works just in three steps: \begin{itemize} \item First, we create the dialog by calling the appropriate Constructor. \item Then, we call the \method{ShowModal} method, that does all the real work and returns a value corresponding to what the user has pressed ( OK button or Cancel) \item If necessary, we retrieve the filename and the directory of the selected file and we load it into the editor. Finally, we destroy the dialog. \end{itemize} Normally, you should now be able to add the corresponding entry into the menu and connect it to the \method{OnOpen} method. Find the complete source in appendix A. \subsection{Possible extensions} Of course, this program is far from being a decent editor. But adding other features should not be more difficult than what has already been done. You might take inspiration in the demoes that are bundled with wxPython: \begin{itemize} \item Drag and Drog. \item MDI \item Tabview/multifiles \item Find/Replace dialog \item Print dialog \item Macro-commands in python ( using the \function{eval} function) \item etc ... \end{itemize} % ================================================================================== \section{Advanced topics} \subsection{Events} Events are really one of the \emph{key feature} of wxPython. % TO BE CONTINUED \subsection{Scintilla} % TO BE CONTINUED \subsection{Boa-constructor} Boa-constructor is a RAD IDE for wxPython. % TO BE CONTINUED \subsection{multithreading} % Why in what way ? % TO BE CONTINUED % ================================================================================== \section{Useful resources} \begin{definitions} \term{\url{http://wxPython.org/} } To start with, a very obvious website but you can also have a look in the demo shipped in with the wxPython package. It's full of very useful examples approaching nearly all the subjects you can think of. How to run the demo: \begin{itemize} \item{under windows} Simply select the program Run The Demo in the submenu wxPython of the start menu. \item{under linux} find the demo directory in the source distribution and run "python demo.py" \end{itemize} \term{\url{http://wxwindows.org/} } You can also try to find directly information on the wxWindows website - Although wxPython's documentation contains all wxWindows', so it's a bit useless to go there, if you have had a look at wxPython's in the first place. \term{\url{http://wxpython.org/maillist.php } } The wxPython mailing lists. \term{\url{http://boa-constructor.sourceforge.net/} } Boa-constructor is a RAD GUI building IDE for wxPython. \term{\url{http://www-106.ibm.com/developerworks/library/l-wxpy/index.html} } An excellent article for newbies \term{\url{http://www.oreillynet.com/pub/a/Python/excerpts/chpt20/wxpython.html} } Last but not least: The book "Python Programming on Win32 using WxPython" of Mark Hammond and Andy Robinson has an entire (excellent) chapter on wxPython . \term{\url{http://www.scintilla.org/} } Scintilla is a complete editing component for which wxPython offers bindings (a control named \class{wxStyledTextCtrl2} ). \term{\url{http://www.python.org/} } The reference website relative to the python community. \term{\url{http://www.crosswinds.net/\~ agauld} } A python tutorial. \end{definitions} % ================================================================================== \section{As a conclusion- slithering our way to the future of GUI-apps} % ================================================================================== \section{contributors} \begin{itemize} \item The wxPython community \item Lucas Bruand \item Rob CakeBread \item Charlie Derr \item Robin Dunn \item Michael Roberts \end{itemize} % ================================================================================== \section{Acknowledgements} % ================================================================================== \appendix \section{Small editor complete source} \begin{verbatim} from wxPython.wx import * ID_ABOUT=101 ID_OPEN=102 ID_SAVE=103 ID_SAVEAS=104 ID_EXIT=110 class MainWindow(wxFrame): def __init__(self,parent,id,filename='noname.txt'): self.filename=filename self.dirname="." wxFrame.__init__(self,parent,-4, "Editor %s" % self.filename, size = ( 200,100), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.control = wxTextCtrl(self, 1, style=wxTE_MULTILINE) self.CreateStatusBar() # A Statusbar in the bottom of the window # Setting up the menu. filemenu= wxMenu() filemenu.Append(ID_ABOUT, "&About"," Information about this program") filemenu.Append(ID_OPEN,"&Open"," Open a new file ") filemenu.Append(ID_SAVE,"&Save"," Save the current file") filemenu.Append(ID_SAVEAS,"Save &As"," Save the file under a different name") filemenu.AppendSeparator() filemenu.Append(ID_EXIT,"E&xit"," Terminate the program") # Creating the menubar. menuBar = wxMenuBar() menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the method self.OnAbout EVT_MENU(self, ID_EXIT, self.OnExit) # attach the menu-event ID_EXIT to the method self.OnExit EVT_MENU(self, ID_OPEN, self.OnOpen) EVT_MENU(self, ID_SAVE, self.OnSave) EVT_MENU(self, ID_SAVEAS, self.OnSaveAs) self.Show(true) \end{verbatim} \begin{verbatim} def OnAbout(self,e): d= wxMessageDialog( self, " A sample editor \n" " in wxPython","About Sample Editor", wxOK) # Create a message dialog box d.ShowModal() # Shows it d.Destroy() # finally destroy it when finished. def OnExit(self,e): self.Close(true) # Close the frame. def OnSave(self,e): """ Save the current file """ f=open(self.dirname+'\\'+self.filename,"w") f.write(self.control.GetValue()) f.close() def OnOpen(self,e): """ Open a file""" dlg = wxFileDialog(self, "Choose a file", self.dirname, "", "*.*", wxOPEN) if dlg.ShowModal() == wxID_OK: self.filename=dlg.GetFilename() self.dirname=dlg.GetDirectory() f=open(self.dirname+'\\'+self.filename,'r') self.control.SetValue(f.read()) f.close() dlg.Destroy() def OnSaveAs(self,e): """ Save as """ dlg = wxFileDialog(self, "Choose a file", self.dirname, self.filename, "*.*", wxSAVE) if dlg.ShowModal() == wxID_OK: self.filename=dlg.GetFilename() self.dirname=dlg.GetDirectory() self.OnSave(e) dlg.Destroy() \end{verbatim} \begin{verbatim} app = wxPySimpleApp() frame = MainWindow(None, -1) frame.Show(1) app.MainLoop() app.MainLoop() \end{verbatim} % ================================================================================== \end{document} |