(Ebook - Eng) Introduction Wxwidgets Programming
(Ebook - Eng) Introduction Wxwidgets Programming
Abstract
The article starts with an introduction to the C++ library wxWin-
dows. The first small example wxHello, is the well known ”Hello
world” type example. Another example wxKoch will be extended to
show the implementation of a Model-View-Controller concept.
1
Contents
1 Introduction to wxWindows 3
1.1 What is wxWindows . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4 Model-View-Controller Concept 12
4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.2 wxKoch1: Introducing a model and view class . . . . . . . . . 13
2
1 Introduction to wxWindows
1.1 What is wxWindows
wxWindows is a C++ library which allows software development for sev-
eral platforms. It’s main target is the programming of the Graphical User
Interface (GUI). To get more information look at the homepage of wxWin-
dows http://www.wxwindows.org/. The examples are written for the win-
dows version using Microsoft’s Visual C++ compiler. It should also com-
pile on all other supported platforms, like Unix (GTK+ or Motif) or Ap-
ple’s Macintosh. For more information on the GTK+ based wxWindows
version (called wxGTK), which is often used with GNU/Linux, look at
http://www.freiburg.linux.de/~wxxt/.
Currently version 2.2.0 is available. For downloads look at http://www.
wxwindows.org/dl_msw2.htm, the main ftp site ftp://www.remstar.com/
pub/wxwin/ or a mirror site. We will use the setup executable ftp://ftp.
mapsy.nat.tu-bs.de/pub/mirror/wxwin/2.2.0/wxMSW-2.2.0-setup.zip.
You may also get wxWindows-2.2.0-WinHelp.zip and add the files after the
installation procedure.
There is also a quite helpful mailing list. Look at http://www.wxwindows.
org/maillst2.htm for information.
1.2 Installation
After unzipping and doing the common installation procedure using setup.exe,
the library has to be build. There are two ways:
1. using makefiles
3
2 The first programm
The first example is the famous ”hello world” application. It can be found at
http://www.wxwindows.org/hworld2.txt. A similar program is explained
at http://www.wxwindows.org/hello.htm. You might also have a look at
the minimal sample.
It’s important that after creating a new project with VC++, the project
settings are adapted to needs of wxWindows, e. g. the search path have
to include the wxWindows include and library files. One possibility is to
(mis)use an existing sample. To simplify the process a tool is developed here
called wxProjectGenerator to generate the *.ds? files, which can be opened
with VC++. Let’s generate a project called wxHello. There is a resource file
called ”wxHello.rc” with only one line
#include ”wx/msw/wx . r c ”
4
wxApp (respectively wxHelloApp)-Object. Now a window with a menu is
needed. To get this, the application has to create a kind of wxFrame-Object.
The specialized version wxHelloFrame is derived:
c l a s s wxHelloFrame : public wxFrame
{
public :
wxHelloFrame ( const wxString & t i t l e , const wxPoint& pos
, const wxSize & s i z e ) ;
void OnQuit ( wxCommandEvent& e v e n t ) ;
void OnAbout ( wxCommandEvent& e v e n t ) ;
};
/ / dynamic e v e n t s −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
frame−>Connect ( ID Quit , wxEVT COMMAND MENU SELECTED,
( wxObjectEventFunction ) & wxHelloFrame : : OnQuit ) ;
frame−>Connect ( ID About , wxEVT COMMAND MENU SELECTED,
( wxObjectEventFunction ) & wxHelloFrame : : OnAbout ) ;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
frame−>Show ( true ) ;
5
SetTopWindow ( frame ) ;
return true ;
}
As already mentioned ”wxHelloApp::OnInit” is the first method being exe-
cuted. Here the frame window with title ”Hello World” will be created at a
certain position and size. The ”Connect” method dynamically connects an
event to a method. If the event occurs, the method is executed. But some-
thing has to raise an event... This can be done with a button or through a
menu item. If the frame is created, its constructor is executed:
wxHelloFrame : : wxHelloFrame ( const wxString & t i t l e
, const wxPoint& pos , const wxSize & s i z e )
: wxFrame ( ( wxFrame ∗ )NULL, − 1 , t i t l e , pos , s i z e )
{
/ / c r e a t e menubar
wxMenuBar ∗ menuBar = new wxMenuBar ;
/ / c r e a t e menu
wxMenu ∗ menuFile = new wxMenu ;
/ / append menu e n t r i e s
menuFile−>Append ( ID About , ”&About . . . ” ) ;
menuFile−>AppendSeparator ( ) ;
menuFile−>Append ( ID Quit , ”E&x i t ” ) ;
/ / append menu t o menubar
menuBar−>Append ( menuFile , ”& F i l e ” ) ;
/ / s e t frame menubar
SetMenuBar ( menuBar ) ;
/ / c r e a t e frame s t a t u s b a r
CreateStatusBar ( ) ;
// set statusbar text
S e t S t a t u s T e x t ( ”Demo f o r wxWindows” ) ;
}
Here the menubar is created and menus are appended. A menu can have
several menu items, which are associated to an event number. If a menu
item is selected, the specified event occurs. The event method will then be
executed. The & char marks the key shortcut. Here Alt–F will open the File
menu and x will afterwards exit the application. The status bar is found at
the bottom of the frame window and the message ”Demo for wxWindows”
is written there.
void wxHelloFrame : : OnQuit ( wxCommandEvent& e v e n t )
{
C l o s e ( true ) ;
}
6
wxMessageBox ( ”wxWindows H e l l o World example . ”
, ”About H e l l o World” , wxOK| wxICON INFORMATION
, this ) ;
}
The middle one is replaced with the two other edges of another equal sided
triangle. This Koch snowflake of level 1 is shown in figure 1(b). The proce-
dure is repeated and Koch snowflakes of level n are obtained recursivly (see
2).
7
(a) level 2 (b) level 3
#i f n d e f WXKOCH H
#define WXKOCH H
8
c l a s s wxKochApp : public wxApp
{
wxKochFrame ∗ m pframe ;
v i r t u a l bool OnInit ( ) ;
public :
void Draw ( unsigned int n ) ;
void DrawEdge (wxDC& dc , unsigned int n , int x1 , int y1
, int x2 , int y2 ) ;
};
#endif
The wxKochApp stores the pointer to its frame mp f rame, which is created
in the OnInit method. ”Draw” will draw a Koch snowflake of level n and
makes use of the DrawEdge method, which calls itself recursively.
Looking at the source file, the first part is similar to wxHello:
/ / wxKoch0 . cpp
/ / Martin B e r n r e u t h e r , Jan . 2 0 0 0
/ / wxWindows 2
#include ”wxKoch0 . h”
enum
{
ID Quit =1,
ID About ,
ID InpLevel
};
SetTopWindow ( m pframe ) ;
return true ;
}
9
S e t I c o n (wxICON( KochIcon ) ) ;
/ / c r e a t e menubar
wxMenuBar ∗ menuBar = new wxMenuBar ;
/ / c r e a t e menu
wxMenu ∗ menuFile = new wxMenu ;
wxMenu ∗ menuHelp = new wxMenu ;
/ / append menu e n t r i e s
menuFile−>Append ( I D I n p L e v e l , ” Input & L e v e l . . . \ t C t r l−D” ) ;
menuFile−>AppendSeparator ( ) ;
menuFile−>Append ( ID Quit , ”E&x i t ” ) ;
menuHelp−>Append ( ID About , ”&About . . . ” ) ;
/ / append menu t o menubar
menuBar−>Append ( menuFile , ”& F i l e ” ) ;
menuBar−>Append ( menuHelp , ”&Help ” ) ;
/ / s e t frame menubar
SetMenuBar ( menuBar ) ;
/ / Connect e v e n t t o c a l l b a c k f u n c t i o n
Connect ( ID Quit , wxEVT COMMAND MENU SELECTED,
( wxObjectEventFunction ) &wxKochFrame : : OnQuit ) ;
Connect ( ID About , wxEVT COMMAND MENU SELECTED,
( wxObjectEventFunction ) &wxKochFrame : : OnAbout ) ;
Connect ( I D I n p L e v e l , wxEVT COMMAND MENU SELECTED,
( wxObjectEventFunction ) &wxKochFrame : : OnInpLevel ) ;
/ / c r e a t e frame s t a t u s b a r
CreateStatusBar ( ) ;
// set statusbar text
S e t S t a t u s T e x t ( ” G e n e r a t i n g Koch s n o w f l a k e s ” ) ;
}
10
long l e v e l = wxGetNumberFromUser ( ”” , ” L e v e l : ” , ” Input L e v e l ”
, 4 , 0 , 1 0 , this ) ;
wxString msg ;
i f ( l e v e l == −1 )
msg = ” I n v a l i d number e n t e r e d o r d i a l o g c a n c e l l e d . ” ;
else
{
msg . P r i n t f ( ” L e v e l : % l u ” , l e v e l ) ;
wxGetApp ( ) . Draw ( l e v e l ) ;
}
S e t S t a t u s T e x t ( msg ) ;
}
For the input of an positive integer wxWindows offers the dialog wxGetNum-
berFromUser, which also can be found in the Dialogs sample. If a valid input
exists, the Koch snowflake is drawn.
void wxKochApp : : Draw ( unsigned int n )
{
int width , h e i g h t ;
unsigned int d , x1 , y1 , x2 , y3 , x3 ;
/ / d e t e r m i n e s i z e o f Window
m pframe−>G e t C l i e n t S i z e (&width , & h e i g h t ) ;
d=h e i g h t ;
// c a l c u l a t e coordinates of i n i t i a l t r i a n g l e
i f ( width<h e i g h t ) d=width ;
y1 =.5∗ h e i g h t +.25∗d ;
y3 =.5∗ h e i g h t −.5∗d ;
x1 =.5∗ width −.25∗d∗ s q r t ( 3 . ) ;
x2 =.5∗ width +.25∗d∗ s q r t ( 3 . ) ;
x3 =.5∗ width ;
// I n i t i a l i z e device context
wxClientDC dc ( m pframe ) ;
dc . C l e a r ( ) ;
dc . SetPen ( wxPen ( wxColour ( 0 , 0 , 0 ) , 1 , wxSOLID ) ) ;
dc . BeginDrawing ( ) ;
/ / draw t h e e d g e s
DrawEdge ( dc , n , x1 , y1 , x2 , y1 ) ;
DrawEdge ( dc , n , x2 , y1 , x3 , y3 ) ;
DrawEdge ( dc , n , x3 , y3 , x1 , y1 ) ;
dc . EndDrawing ( ) ;
}
11
/ / c a l c u l a t e new c o o r d i n a t e s
int x3 , y3 , x4 , y4 , x5 , y5 ;
x3 =2.∗ x1 /3.+ x2 / 3 . ;
y3 =2.∗ y1 /3.+ y2 / 3 . ;
DrawEdge ( dc , n−1, x1 , y1 , x3 , y3 ) ;
x4=x1 / 3 . + 2 . ∗ x2 / 3 . ;
y4=y1 / 3 . + 2 . ∗ y2 / 3 . ;
x5 =.5∗( x1+x2 )−( y2−y1 ) ∗ s q r t ( 3 . ) / 6 . ;
y5 =.5∗( y1+y2 )+( x2−x1 ) ∗ s q r t ( 3 . ) / 6 . ;
// re c ur s iv e c a l l s
DrawEdge ( dc , n−1, x3 , y3 , x5 , y5 ) ;
DrawEdge ( dc , n−1, x5 , y5 , x4 , y4 ) ;
DrawEdge ( dc , n−1, x4 , y4 , x2 , y2 ) ;
}
else
/ / j u s t draw a l i n e
dc . DrawLine ( x1 , y1 , x2 , y2 ) ;
}
The application will draw to the frame client window. The size of the window
and the coordinates of the corners of the initial triangle are determined.
Drawing operations need a device context. Here a wxClientDC is created
and used. ”Clear” first will result in an empty area and SetPen will specify
the pen, which will be used for drawing. A black solid pen with width 1 is
created here for this purpose. DrawEdge will receive the drawing context by
reference and will do the recursion and drawing using DrawLine.
4 Model-View-Controller Concept
4.1 Overview
Following the Model-View-Controller (MVC) concept, an application consists
of three parts (see 3), which communicate through messages.
The View and the Controller part are grown together in most applica-
tions. Important is the model part, which can be modelled as own class in
C++. The properties of the model class represent the data used in the ap-
plication. This can be drawing objects in a CAD like application or text and
formatting information in a word processor. Since the MFC1 was written for
applications like MS-Word in the first place, a model is called ”Document”
there. wxWindows offers a MVC like environment, where the model also
is called ”document”. This won’t be used here. More information can be
obtained looking at the help and the doc* samples.
1
Microsoft Foundation Classes: a commercial GUI/Class library
12
An application can have multiple instances of model data or just one at
a time. If there are multiple2 allowed, usually there is an active one, which
receives the changes.
Regarding the views, the window man-
ager of the Windows operating system
doesn’t store the areas overdrawn through Model - View
other windows in the front. The applica- BMB
tion has to take care of restore the invalid BB
areas itself. There is an repaint event BB
which is release from the window man-
BBN
Controller
ager to tell the view (through the appli-
cation) to restore the area.
Figure 3: MVC concept
4.2 wxKoch1: Introducing a
model and view class
Taking wxKoch0 (see 3.2), a model and a view class should be added like
described in 4. The view class is a very specialized one and is able to draw
Koch snowflakes. It might be better to have a general view and move the
functionality to the model.
c l a s s KochView ;
c l a s s KochModel
{
private :
// l e v e l :
unsigned int m n ;
/ / t h e one and o n l y view :
KochView ∗ m pview ;
public :
KochModel ( ) ;
˜KochModel ( ) ;
void Draw ( ) ;
};
13
{
private :
/ / t h e model t h e view b e l o n g s t o :
KochModel ∗ m pmodel ;
wxPen m pen ;
unsigned int m x1 , m y1 , m x2 , m x3 , m y3 ;
public :
KochView (wxWindow ∗ p p a r e n t , KochModel ∗ pmodel ) ;
v i r t u a l ˜ KochView ( ) ;
void S e t S t a t u s T e x t ( wxString t e x t )
{ ( ( wxFrame ∗ ) GetParent ())−> S e t S t a t u s T e x t ( t e x t ) ; }
void Draw ( ) { R e f r e s h ( ) ; }
void OnPaint ( wxPaintEvent & e v e n t ) ;
};
14
return 0 ;
}
KochModel : : ˜ KochModel ( )
{
i f ( m pview )
m pview−>Des troy ( ) ;
}
i f ( m pmodel ) m pmodel−>AddView ( t h i s ) ;
KochView : : ˜ KochView ( )
{
i f ( m pmodel ) m pmodel−>RemoveView ( t h i s ) ;
}
15
KochModel::Setn just sets a new level, which is the data the model has to
store:
void KochModel : : Setn ( unsigned int n )
{
i f ( n!=m n )
{
m n=n ;
i f ( m pview )
{
wxString msg ;
msg . P r i n t f ( ” L e v e l changed t o %l u ” , m n ) ;
wxGetApp ( ) . S e t S t a t u s T e x t ( msg ) ;
m pview−>Draw ( ) ;
}
}
}
The view receives the repaint event to update the drawing area through
KochView::OnPaint. A pen is needed for the drawing procedure. The data
comes from the model.
KochView : : KochView (wxWindow ∗ p p a r e n t , KochModel ∗ pmodel ) :
wxWindow( p p a r e n t , − 1 ) , m pmodel ( pmodel )
{
wxColour c o l ( 0 , 0 , 0 ) ;
m pen = wxPen ( c o l , 1 , wxSOLID ) ;
i f ( m pmodel ) m pmodel−>SetView ( t h i s ) ;
The calculation of the first three vertices coordinates of the triangle is done
in KochView::CalcStartCoordinates depending on the size of the view. The
drawing is started with KochView::Draw and done in the recursive KochView::OnPaint:
void KochView : : C a l c S t a r t C o o r d i n a t e s ( unsigned i nt width
, unsigned i nt height
, int & x1 , int & y1
, int & x2 , int & x3 , int & y3 )
{
16
i f ( width<h e i g h t )
{
y1 =.5∗ h e i g h t +.25∗ width ;
y3 =.5∗( h e i g h t−width ) ;
x1 =(.5−.25∗ s q r t ( 3 . ) ) ∗ width ;
x2 =(.5+.25∗ s q r t ( 3 . ) ) ∗ width ;
}
else
{
y1 =.75∗ h e i g h t ;
y3 = 0 . ;
x1 =.5∗ width −.25∗ h e i g h t ∗ s q r t ( 3 . ) ;
x2 =.5∗ width +.25∗ h e i g h t ∗ s q r t ( 3 . ) ;
}
x3 =.5∗ width ;
}
DrawEdge ( dc , n , x1 , y1 , x2 , y1 ) ;
DrawEdge ( dc , n , x2 , y1 , x3 , y3 ) ;
DrawEdge ( dc , n , x3 , y3 , x1 , y1 ) ;
}
17
void KochView : : OnPaint ( wxPaintEvent & e v e n t )
{
i f ( m pmodel )
{
int width , h e i g h t ;
G e t C l i e n t S i z e (&width , & h e i g h t ) ;
int x1 , y1 , x2 , x3 , y3 ;
C a l c S t a r t C o o r d i n a t e s ( width , h e i g h t , x1 , y1 , x2 , x3 , y3 ) ;
wxPaintDC dc ( t h i s ) ;
dc . C l e a r ( ) ;
dc . SetPen ( m pen ) ;
Draw ( dc , x1 , y1 , x2 , x3 , y3 ) ;
}
}
18
5.1.2 Printing and Clipboard copy
wxWindows offers special device contexts for printing and the clipboard.
Instead of drawing to the screen, KochView::Draw draws to the printer or in
the clipboard.
5.1.3 Undo/Redo
Undo/Redo is implemented through classes for each command. The class
CmdSetLevel for example sets and restores the level with its Do and Undo
method. The command processor object manages all command objects.
// wxKoch . h
// Martin B e r n r e u t h e r , J u l y 2 0 0 0
// u s i n g wxWindows 2 . 2 . 0
// draws & p r i n t s t h e r e c u r s i v e Koch s n o w f l a k e s t r u c t u r e
#i f n d e f WXKOCH H
#define WXKOCH H
c l a s s KochView ;
c l a s s KochModel
{
private :
// l e v e l :
unsigned int m n ;
/ / t h e one and o n l y view :
KochView ∗ m pview ;
public :
KochModel ( ) ;
19
˜KochModel ( ) ;
void Draw ( ) ;
public :
KochView (wxWindow ∗ p p a r e n t , KochModel ∗ pmodel ) ;
v i r t u a l ˜ KochView ( ) ;
void S e t S t a t u s T e x t ( wxString t e x t )
{ ( ( wxFrame ∗ ) GetParent ())−> S e t S t a t u s T e x t ( t e x t ) ; }
void Draw ( ) { R e f r e s h ( ) ; }
void OnPaint ( wxPaintEvent & e v e n t ) ;
20
void Copy2Clipboard ( ) ;
};
21
v i r t u a l bool Do ( ) ;
v i r t u a l bool Undo ( ) ;
};
#endif
5.2.2 wxKoch.cpp
/ / wxKoch . cpp
/ / Martin B e r n r e u t h e r , J u l y 2 0 0 0
/ / u s i n g wxWindows 2 . 2 . 0
#include ”wxKoch . h”
enum
{
22
ID Quit =1,
ID About ,
ID InpLevel ,
ID SetPenWidth ,
ID SetPenColor ,
ID CopyClipboard ,
ID Print
};
//KochApp−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / i n i t i a l i z e ColourDialogData
m c o l d a t a . S e t C h o o s e F u l l (TRUE) ;
fo r ( int i = 0 ; i < 1 6 ; i ++)
{
wxColour c o l ( i ∗ 1 6 , i ∗ 1 6 , i ∗ 1 6 ) ;
m c o l d a t a . SetCustomColour ( i , c o l ) ;
}
// i n i t i a l i z e PrintDialogData
m prndata . E n a b l e S e l e c t i o n (FALSE ) ;
m prndata . EnablePageNumbers (FALSE ) ;
return true ;
}
//KochFrame−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
23
S e t I c o n (wxICON( KochIcon ) ) ;
/ / c r e a t e menubar
wxMenuBar ∗ menuBar = new wxMenuBar ;
/ / c r e a t e menu
wxMenu ∗ menuFile = new wxMenu ;
wxMenu ∗ menuEdit = new wxMenu ;
wxMenu ∗ menuHelp = new wxMenu ;
/ / append menu e n t r i e s
menuFile−>Append ( I D I n p L e v e l , ” Input & L e v e l . . . \ t C t r l−D” ) ;
menuFile−>Append ( ID SetPenWidth , ” S e t Pen &Width . . . ” ) ;
menuFile−>Append ( ID SetPenColor , ” S e t Pen &C o l o r . . . ” ) ;
menuFile−>Append ( I D P r i n t , ”&P r i n t . . . \ t C t r l−P” ) ;
menuFile−>AppendSeparator ( ) ;
menuFile−>Append ( ID Quit , ”E&x i t \ t A l t−F4” ) ;
menuEdit−>Append (wxID UNDO , ”&Undo” ) ;
menuEdit−>Append (wxID REDO , ”&Redo” ) ;
menuEdit−>Append ( ID CopyClipboard , ”&Copy t o C l i p b o a r d ” ) ;
menuHelp−>Append ( ID About , ”&About . . . ” ) ;
/ / append menu t o menubar
menuBar−>Append ( menuFile , ”& F i l e ” ) ;
menuBar−>Append ( menuEdit , ”&Edit ” ) ;
menuBar−>Append ( menuHelp , ”&Help ” ) ;
/ / add Undo/Redo e n t r i e s t o menuEdit & I n i t i a l i z e
m cmdprocessor . SetEditMenu ( menuEdit ) ;
m cmdprocessor . I n i t i a l i z e ( ) ;
/ / s e t frame menubar
SetMenuBar ( menuBar ) ;
/ / c r e a t e frame s t a t u s b a r
24
CreateStatusBar ( ) ;
// set statusbar text
S e t S t a t u s T e x t ( ” G e n e r a t i n g Koch s n o w f l a k e s ” ) ;
}
25
void KochFrame : : OnSetPenColor ( wxCommandEvent& e v e n t )
{
wxColourDialog c o l d i a l o g ( t h i s , wxGetApp ( ) . GetpColdata ( ) ) ;
wxString msg ;
i f ( c o l d i a l o g . ShowModal () == wxID OK)
{
msg=”Pen C o l o r s e t ” ;
m cmdprocessor . Submit (new CmdSetPenColor ( c o l d i a l o g . GetColourData ( ) ) ) ;
wxGetApp ( ) . GetpModel()−>Draw ( ) ;
}
else
msg=” C o l o r D i a l o g c a n c e l e d ” ;
S e t S t a t u s T e x t ( msg ) ;
}
// KochModel−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
KochModel : : KochModel ( )
{
m pview=NULL;
m n=4;
/∗ m pview=∗/
new KochView ( wxGetApp ( ) . GetpFrame ( ) , t h i s ) ;
}
KochModel : : ˜ KochModel ( )
{
26
i f ( m pview )
// d e l e t e m pview ;
m pview−>Des troy ( ) ;
// m pview−>C l o s e ( ) ;
}
27
wxColor KochModel : : GetPenColor ( )
{
i f ( m pview )
return m pview−>GetPenColor ( ) ;
else
return wxNullColour ;
}
void KochModel : : P r i n t ( )
{
i f ( m pview ) m pview−>P r i n t ( ) ;
}
// KochView−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i f ( m pmodel ) m pmodel−>AddView ( t h i s ) ;
KochView : : ˜ KochView ( )
{
i f ( m pmodel ) m pmodel−>RemoveView ( t h i s ) ;
}
28
{
return m pen . GetWidth ( ) ;
}
DrawEdge ( dc , n , x1 , y1 , x2 , y1 ) ;
DrawEdge ( dc , n , x2 , y1 , x3 , y3 ) ;
DrawEdge ( dc , n , x3 , y3 , x1 , y1 ) ;
}
29
void KochView : : DrawEdge (wxDC& dc , unsigned i nt n
, int x1 , int y1 , int x2 , int y2 )
{
i f ( n>0)
{
int x3 , y3 , x4 , y4 , x5 , y5 ;
x3 =2.∗ x1 /3.+ x2 / 3 . ;
y3 =2.∗ y1 /3.+ y2 / 3 . ;
DrawEdge ( dc , n−1, x1 , y1 , x3 , y3 ) ;
x4=x1 / 3 . + 2 . ∗ x2 / 3 . ;
y4=y1 / 3 . + 2 . ∗ y2 / 3 . ;
x5 =.5∗( x1+x2 )−( y2−y1 ) ∗ s q r t ( 3 . ) / 6 . ;
y5 =.5∗( y1+y2 )+( x2−x1 ) ∗ s q r t ( 3 . ) / 6 . ;
DrawEdge ( dc , n−1, x3 , y3 , x5 , y5 ) ;
DrawEdge ( dc , n−1, x5 , y5 , x4 , y4 ) ;
DrawEdge ( dc , n−1, x4 , y4 , x2 , y2 ) ;
}
else
dc . DrawLine ( x1 , y1 , x2 , y2 ) ;
}
wxPaintDC dc ( t h i s ) ;
dc . C l e a r ( ) ;
dc . SetPen ( m pen ) ;
Draw ( dc , x1 , y1 , x2 , x3 , y3 ) ;
}
}
void KochView : : P r i n t ( )
{
wxWindow ∗ p pa r e n t=wxGetApp ( ) . GetpFrame ( ) ;
wxPrintDialogData ∗ pprndata=wxGetApp ( ) . GetpPrndata ( ) ;
w x P r i n t D i a l o g p r n d i a l o g ( p p a r e n t , pprndata ) ;
i f ( p r n d i a l o g . ShowModal ( ) ! = wxID OK)
{
wxGetApp ( ) . S e t S t a t u s T e x t ( ” P r i n t e r D i a l o g c a n c e l l e d ” ) ;
return ;
}
∗ pprndata = p r n d i a l o g . G e tP r i n t D i a lo g D a t a ( ) ;
wxDC ∗ pdc = p r n d i a l o g . GetPrintDC ( ) ;
30
i f ( ! pdc−>Ok ( ) )
{
wxGetApp ( ) . S e t S t a t u s T e x t (
” Error c r e a t i n g device context ” ) ;
return ;
}
int width , h e i g h t ;
pdc−>G e t S i z e (&width , & h e i g h t ) ;
int x1 , y1 , x2 , x3 , y3 ;
C a l c S t a r t C o o r d i n a t e s ( width , h e i g h t , x1 , y1 , x2 , x3 , y3 ) ;
pdc−>SetPen ( m pen ) ;
m font . S e t P o i n t S i z e ( int ( h e i g h t / 1 0 0 ) ) ;
pdc−>SetFont ( m font ) ;
pdc−>SetTextForeground ( wxColour ( 0 , 0 , 0 ) ) ;
pdc−>StartDoc ( ”wxKoch p r i n t o u t ” ) ;
pdc−>S t a r t P a g e ( ) ;
ypos+=t h e i g h t +5;
msg . P r i n t f ( ”Depth %l u ” , wxGetApp ( ) . GetpModel()−>Getn ( ) ) ;
// pdc−>GetTextExtent ( msg,& t w i d t h ,& t h e i g h t ) ;
pdc−>DrawText ( msg , xpos , ypos ) ;
pdc−>GetFont ( ) . S e t P o i n t S i z e ( int ( h e i g h t / 2 0 0 ) ) ;
msg=”by M. B e r n r e u t h e r ” ;
pdc−>GetTextExtent ( msg,& t w i d t h ,& t h e i g h t ) ;
xpos =.99∗ width−t w i d t h ;
ypos =.99∗ h e i g h t−t h e i g h t ;
pdc−>DrawText ( msg , xpos , ypos ) ;
Draw ( ∗ pdc , x1 , y1 , x2 , x3 , y3 ) ;
pdc−>EndPage ( ) ;
pdc−>EndDoc ( ) ;
}
31
int x1 , y1 , x2 , x3 , y3 ;
C a l c S t a r t C o o r d i n a t e s ( 1 0 0 0 , 1 0 0 0 , x1 , y1 , x2 , x3 , y3 ) ;
wxEnhMetaFileDC dc ;
i f ( ! dc . Ok ( ) )
{
wxGetApp ( ) . S e t S t a t u s T e x t ( ” wxMetafileDC not Ok” ) ;
return ;
}
dc . SetPen ( m pen ) ;
Draw ( dc , x1 , y1 , x2 , x3 , y3 ) ;
wxEnhMetaFile ∗ pmf = dc . C l o s e ( ) ;
i f ( ! pmf )
{
wxGetApp ( ) . S e t S t a t u s T e x t ( ” Could not c r e a t e w x M e t a f i l e ” ) ;
return ;
}
i f ( pmf−>Ok ( ) )
{
i f ( wxTheClipboard−>Open ( ) )
{
i f ( wxTheClipboard−>SetData (new wxEnhMetaFileDataObject ( ∗ pmf ) ) )
wxGetApp ( ) . S e t S t a t u s T e x t ( ” C l i p b o a r d data s e t ” ) ;
else
wxGetApp ( ) . S e t S t a t u s T e x t ( ” E r r o r s e t t i n g C l i p b o a r d data ” ) ;
wxTheClipboard−>C l o s e ( ) ;
}
else
wxGetApp ( ) . S e t S t a t u s T e x t (
” Error opening Clipboard ” ) ;
}
else
wxGetApp ( ) . S e t S t a t u s T e x t ( ” w x M e t a f i l e not Ok” ) ;
delete pmf ;
}
//CmdSetDepth−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
bool CmdSetLevel : : Do ( )
{
m o l d l e v e l=wxGetApp ( ) . GetpModel()−>Getn ( ) ;
wxGetApp ( ) . GetpModel()−> Setn ( m l e v e l ) ;
m commandName . P r i n t f ( ” S e t Depth=%l u ” , m l e v e l ) ;
return TRUE;
}
32
bool CmdSetLevel : : Undo ( )
{
wxGetApp ( ) . GetpModel()−> Setn ( m o l d l e v e l ) ;
return TRUE;
}
bool CmdSetPenWidth : : Do ( )
{
m oldpenwidth=wxGetApp ( ) . GetpModel()−>GetPenWidth ( ) ;
wxGetApp ( ) . GetpModel()−>SetPenWidth ( m penwidth ) ;
m commandName . P r i n t f ( ” S e t Pen Width=%l u ” , m penwidth ) ;
return TRUE;
}
bool CmdSetPenColor : : Do ( )
{
wxColourData ∗ p c o l d a t a=wxGetApp ( ) . GetpColdata ( ) ;
m o l d c o l d a t a=∗p c o l d a t a ;
∗ pcoldata = m coldata ;
wxGetApp ( ) . GetpModel()−> SetPenColor ( p c o l d a t a−>GetColour ( ) ) ;
return TRUE;
}
33
gtk+. A Windows port exists (http://www.gimp.org/~tml/gimp/
win32/), but is under development. Gtk– http://gtkmm.sourceforge.
net/ is a C++ interface for gtk+.
FLTK The Fast Light Tool Kit Home Page can be found at http://www.
fltk.org/.
34