source: trunk/doc/html/tutorial2-05.html@ 203

Last change on this file since 203 was 190, checked in by rudi, 14 years ago

reference documentation added

File size: 29.3 KB
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/doc/tutorial2.doc:349 -->
3<html>
4<head>
5<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
6<title>Presenting the GUI</title>
7<style type="text/css"><!--
8fn { margin-left: 1cm; text-indent: -1cm; }
9a:link { color: #004faf; text-decoration: none }
10a:visited { color: #672967; text-decoration: none }
11body { background: #ffffff; color: black; }
12--></style>
13</head>
14<body>
15
16<table border="0" cellpadding="0" cellspacing="0" width="100%">
17<tr bgcolor="#E5E5E5">
18<td valign=center>
19 <a href="index.html">
20<font color="#004faf">Home</font></a>
21 | <a href="classes.html">
22<font color="#004faf">All&nbsp;Classes</font></a>
23 | <a href="mainclasses.html">
24<font color="#004faf">Main&nbsp;Classes</font></a>
25 | <a href="annotated.html">
26<font color="#004faf">Annotated</font></a>
27 | <a href="groups.html">
28<font color="#004faf">Grouped&nbsp;Classes</font></a>
29 | <a href="functions.html">
30<font color="#004faf">Functions</font></a>
31</td>
32<td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><h1 align=center>Presenting the GUI</h1>
33
34
35<p>
36<p> <center><img src="chart-main2.png" alt="The chart application"></center>
37<p> The <tt>chart</tt> application provides access to options via menus and
38toolbar buttons arranged around a central widget, a CanvasView, in a
39conventional document-centric style.
40<p> (Extracts from <tt>chartform.h</tt>.)
41<p>
42
43<pre> class ChartForm: public <a href="qmainwindow.html">QMainWindow</a>
44 {
45 <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
46 public:
47 enum { MAX_ELEMENTS = 100 };
48 enum { MAX_RECENTFILES = 9 }; // Must not exceed 9
49 enum ChartType { PIE, VERTICAL_BAR, HORIZONTAL_BAR };
50 enum AddValuesType { NO, YES, AS_PERCENTAGE };
51
52 ChartForm( const <a href="qstring.html">QString</a>&amp; filename );
53 ~ChartForm();
54
55 int chartType() { return m_chartType; }
56 void setChanged( bool changed = TRUE ) { m_changed = changed; }
57 void drawElements();
58
59 <a href="qpopupmenu.html">QPopupMenu</a> *optionsMenu; // Why public? See canvasview.cpp
60
61 protected:
62 virtual void closeEvent( <a href="qcloseevent.html">QCloseEvent</a> * );
63
64 private slots:
65 void fileNew();
66 void fileOpen();
67 void fileOpenRecent( int index );
68 void fileSave();
69 void fileSaveAs();
70 void fileSaveAsPixmap();
71 void filePrint();
72 void fileQuit();
73 void optionsSetData();
74 void updateChartType( <a href="qaction.html">QAction</a> *action );
75 void optionsSetFont();
76 void optionsSetOptions();
77 void helpHelp();
78 void helpAbout();
79 void helpAboutQt();
80 void saveOptions();
81
82 private:
83 void init();
84 void load( const <a href="qstring.html">QString</a>&amp; filename );
85 bool okToClear();
86 void drawPieChart( const double scales[], double total, int count );
87 void drawVerticalBarChart( const double scales[], double total, int count );
88 void drawHorizontalBarChart( const double scales[], double total, int count );
89
90 <a href="qstring.html">QString</a> valueLabel( const <a href="qstring.html">QString</a>&amp; label, double value, double total );
91 void updateRecentFiles( const <a href="qstring.html">QString</a>&amp; filename );
92 void updateRecentFilesMenu();
93 void setChartType( ChartType chartType );
94
95 <a href="qpopupmenu.html">QPopupMenu</a> *fileMenu;
96 <a href="qaction.html">QAction</a> *optionsPieChartAction;
97 <a href="qaction.html">QAction</a> *optionsHorizontalBarChartAction;
98 <a href="qaction.html">QAction</a> *optionsVerticalBarChartAction;
99 <a href="qstring.html">QString</a> m_filename;
100 <a href="qstringlist.html">QStringList</a> m_recentFiles;
101 <a href="qcanvas.html">QCanvas</a> *m_canvas;
102 CanvasView *m_canvasView;
103 bool m_changed;
104 ElementVector m_elements;
105 <a href="qprinter.html">QPrinter</a> *m_printer;
106 ChartType m_chartType;
107 AddValuesType m_addValues;
108 int m_decimalPlaces;
109 <a href="qfont.html">QFont</a> m_font;
110 };
111</pre>
112<p> We create a <tt>ChartForm</tt> subclass of <a href="qmainwindow.html">QMainWindow</a>. Our subclass uses
113the <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a> macro to support Qt's <a href="signalsandslots.html">signals and slots</a> mechanism.
114<p> The public interface is very small; the type of chart being displayed
115can be retrieved, the chart can be marked 'changed' (so that the user
116will be prompted to save on exit), and the chart can be asked to draw
117itself (drawElements()). We've also made the options menu public
118because we are also going to use this menu as the canvas view's
119context menu.
120<p> <center><table cellpadding="4" cellspacing="2" border="0">
121<tr bgcolor="#f0f0f0">
122<td valign="top">The <a href="qcanvas.html">QCanvas</a> class is used for drawing 2D vector graphics. The
123<a href="qcanvasview.html">QCanvasView</a> class is used to present a view of a canvas in an
124application's GUI. All our drawing operations take place on the
125canvas; but events (e.g. mouse clicks) take place on the canvas view.
126</table></center>
127<p> Each action is represented by a private slot, e.g. <tt>fileNew()</tt>, <tt>optionsSetData()</tt>, etc. We also have quite a number of private
128functions and data members; we'll look at all these as we go through
129the implementation.
130<p> For the sake of convenience and compilation speed the chart form's
131implementation is split over three files, <tt>chartform.cpp</tt> for the
132GUI, <tt>chartform_canvas.cpp</tt> for the canvas handling and <tt>chartform_files.cpp</tt> for the file handling. We'll review each in turn.
133<p> <h2> The Chart Form GUI
134</h2>
135<a name="1"></a><p> (Extracts from <tt>chartform.cpp</tt>.)
136<p>
137
138<pre> #include "images/file_new.xpm"
139 #include "images/file_open.xpm"
140</pre><pre> #include "images/options_piechart.xpm"
141</pre>
142<p> All the images used by <tt>chart</tt> have been created as <tt>.xpm</tt> files
143which we've placed in the <tt>images</tt> subdirectory.
144<p> <h2> The Constructor
145</h2>
146<a name="2"></a><p> <pre> ChartForm::ChartForm( const <a href="qstring.html">QString</a>&amp; filename )
147 : <a href="qmainwindow.html">QMainWindow</a>( 0, 0, WDestructiveClose )
148</pre><tt>...</tt>
149<pre> <a href="qaction.html">QAction</a> *fileNewAction;
150 <a href="qaction.html">QAction</a> *fileOpenAction;
151 <a href="qaction.html">QAction</a> *fileSaveAction;
152</pre>
153<p> For each user action we declare a <a href="qaction.html">QAction</a> pointer. Some actions are
154declared in the header file because they need to be referred to
155outside of the constructor.
156<p> <center><table cellpadding="4" cellspacing="2" border="0">
157<tr bgcolor="#d0d0d0">
158<td valign="top">Most user actions are suitable as both menu items and as toolbar
159buttons. Qt allows us to create a single QAction which can be added to
160both a menu and a toolbar. This approach ensures that menu items and
161toolbar buttons stay in sync and saves duplicating code.
162</table></center>
163<p> <pre> fileNewAction = new <a href="qaction.html">QAction</a>(
164 "New Chart", QPixmap( file_new ),
165 "&amp;New", CTRL+Key_N, this, "new" );
166 <a href="qobject.html#connect">connect</a>( fileNewAction, SIGNAL( <a href="qaction.html#activated">activated</a>() ), this, SLOT( fileNew() ) );
167</pre>
168<p> When we construct an action we give it a name, an optional icon, a
169menu text, and an accelerator short-cut key (or 0 if no accelerator is
170required). We also make it a child of the form (by passing <tt>this</tt>).
171When the user clicks a toolbar button or clicks a menu option the <tt>activated()</tt> signal is emitted. We connect() this signal to the
172action's slot, in the snippet shown above, to fileNew().
173<p> The chart types are all mutually exclusive: you can have a pie chart
174<em>or</em> a vertical bar chart <em>or</em> a horizontal bar chart. This means
175that if the user selects the pie chart menu option, the pie chart
176toolbar button must be automatically selected too, and the other chart
177menu options and toolbar buttons must be automatically unselected.
178This behaviour is achieved by creating a <a href="qactiongroup.html">QActionGroup</a> and placing the
179chart type actions in the group.
180<p> <pre> <a href="qactiongroup.html">QActionGroup</a> *chartGroup = new <a href="qactiongroup.html">QActionGroup</a>( this ); // Connected later
181 chartGroup-&gt;<a href="qactiongroup.html#setExclusive">setExclusive</a>( TRUE );
182</pre>
183<p> The action group becomes a child of the form (<tt>this</tt>) and the
184exlusive behaviour is achieved by the setExclusive() call.
185<p> <pre> optionsPieChartAction = new <a href="qaction.html">QAction</a>(
186 "Pie Chart", QPixmap( options_piechart ),
187 "&amp;Pie Chart", CTRL+Key_I, chartGroup, "pie chart" );
188 optionsPieChartAction-&gt;<a href="qaction.html#setToggleAction">setToggleAction</a>( TRUE );
189</pre>
190<p> Each action in the group is created in the same way as other actions,
191except that the action's parent is the group rather than the form.
192Because our chart type actions have an on/off state we call
193setToggleAction(TRUE) for each of them. Note that we do not connect
194the actions; instead, later on, we will connect the group to a slot
195that will cause the canvas to redraw.
196<p> <center><table cellpadding="4" cellspacing="2" border="0">
197<tr bgcolor="#f0f0f0">
198<td valign="top">Why haven't we connected the group straight away? Later in the
199constructor we will read the user's options, one of which is the chart
200type. We will then set the chart type accordingly. But at that point
201we still won't have created a canvas or have any data, so all we want
202to do is toggle the canvas type toolbar buttons, but not actually draw
203the (at this point non-existent) canvas. <em>After</em> we have set the
204canvas type we will connect the group.
205</table></center>
206<p> Once we've created all our user actions we can create the toolbars and
207menu options that will allow the user to invoke them.
208<p> <pre> <a href="qtoolbar.html">QToolBar</a>* fileTools = new <a href="qtoolbar.html">QToolBar</a>( this, "file operations" );
209 fileTools-&gt;<a href="qtoolbar.html#setLabel">setLabel</a>( "File Operations" );
210 fileNewAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileTools );
211 fileOpenAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileTools );
212 fileSaveAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileTools );
213</pre><tt>...</tt>
214<pre> fileMenu = new <a href="qpopupmenu.html">QPopupMenu</a>( this );
215 <a href="qmainwindow.html#menuBar">menuBar</a>()-&gt;insertItem( "&amp;File", fileMenu );
216 fileNewAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileMenu );
217 fileOpenAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileMenu );
218 fileSaveAction-&gt;<a href="qaction.html#addTo">addTo</a>( fileMenu );
219</pre>
220<p> Toolbar actions and menu options are easily created from QActions.
221<p> As a convenience to our users we will restore the last window position
222and size and list their recently used files. This is achieved by
223writing out their settings when the application is closed and reading
224them back when we construct the form.
225<p> <pre> <a href="qsettings.html">QSettings</a> settings;
226 settings.<a href="qsettings.html#insertSearchPath">insertSearchPath</a>( QSettings::Windows, WINDOWS_REGISTRY );
227 int windowWidth = settings.<a href="qsettings.html#readNumEntry">readNumEntry</a>( APP_KEY + "WindowWidth", 460 );
228 int windowHeight = settings.<a href="qsettings.html#readNumEntry">readNumEntry</a>( APP_KEY + "WindowHeight", 530 );
229 int windowX = settings.<a href="qsettings.html#readNumEntry">readNumEntry</a>( APP_KEY + "WindowX", -1 );
230 int windowY = settings.<a href="qsettings.html#readNumEntry">readNumEntry</a>( APP_KEY + "WindowY", -1 );
231 setChartType( ChartType(
232 settings.<a href="qsettings.html#readNumEntry">readNumEntry</a>( APP_KEY + "ChartType", int(PIE) ) ) );
233</pre><pre> m_font = QFont( "Helvetica", 18, QFont::Bold );
234 m_font.fromString(
235 settings.<a href="qsettings.html#readEntry">readEntry</a>( APP_KEY + "Font", m_font.toString() ) );
236 for ( int i = 0; i &lt; MAX_RECENTFILES; ++i ) {
237 <a href="qstring.html">QString</a> filename = settings.<a href="qsettings.html#readEntry">readEntry</a>( APP_KEY + "File" +
238 QString::<a href="qstring.html#number">number</a>( i + 1 ) );
239 if ( !filename.<a href="qstring.html#isEmpty">isEmpty</a>() )
240 m_recentFiles.push_back( filename );
241 }
242 if ( m_recentFiles.count() )
243 updateRecentFilesMenu();
244</pre>
245<p> The <a href="qsettings.html">QSettings</a> class handles user settings in a platform-independent
246way. We simply read and write settings, leaving QSettings to handle
247the platform dependencies. The insertSearchPath() call does nothing
248except under Windows so does not have to be <tt>#ifdef</tt>ed.
249<p> We use readNumEntry() calls to obtain the chart form's last size and
250position, providing default values if this is the first time it has
251been run. The chart type is retrieved as an integer and cast to a
252ChartType enum value. We create a default label font and then read the
253"Font" setting, using the default we have just created if necessary.
254<p> Although QSettings can handle string lists we've chosen to store each
255recently used file as a separate entry to make it easier to hand edit
256the settings. We attempt to read each possible file entry ("File1" to
257"File9"), and add each non-empty entry to the list of recently used
258files. If there are one or more recently used files we update the File
259menu by calling updateRecentFilesMenu(); (we'll review this later on).
260<p> <pre> <a href="qobject.html#connect">connect</a>( chartGroup, SIGNAL( <a href="qactiongroup.html#selected">selected</a>(QAction*) ),
261 this, SLOT( updateChartType(QAction*) ) );
262</pre>
263<p> Now that we have set the chart type (when we read it in as a user
264setting) it is safe to connect the chart group to our
265updateChartType() slot.
266<p> <pre> <a href="qwidget.html#resize">resize</a>( windowWidth, windowHeight );
267 if ( windowX != -1 || windowY != -1 )
268 <a href="qwidget.html#move">move</a>( windowX, windowY );
269</pre>
270<p> And now that we know the window size and position we can resize and
271move the chart form's window accordingly.
272<p> <pre> m_canvas = new <a href="qcanvas.html">QCanvas</a>( this );
273 m_canvas-&gt;<a href="qcanvas.html#resize">resize</a>( <a href="qwidget.html#width">width</a>(), height() );
274 m_canvasView = new CanvasView( m_canvas, &amp;m_elements, this );
275 <a href="qmainwindow.html#setCentralWidget">setCentralWidget</a>( m_canvasView );
276 m_canvasView-&gt;<a href="qwidget.html#show">show</a>();
277</pre>
278<p> We create a new <a href="qcanvas.html">QCanvas</a> and set its size to that of the chart form
279window's client area. We also create a <tt>CanvasView</tt> (our own subclass
280of <a href="qcanvasview.html">QCanvasView</a>) to display the QCanvas. We make the canvas view the
281chart form's main widget and show it.
282<p> <pre> if ( !filename.<a href="qstring.html#isEmpty">isEmpty</a>() )
283 load( filename );
284 else {
285 init();
286 m_elements[0].set( 20, red, 14, "Red" );
287 m_elements[1].set( 70, cyan, 2, "Cyan", darkGreen );
288 m_elements[2].set( 35, blue, 11, "Blue" );
289 m_elements[3].set( 55, yellow, 1, "Yellow", darkBlue );
290 m_elements[4].set( 80, magenta, 1, "Magenta" );
291 drawElements();
292 }
293</pre>
294<p> If we have a file to load we load it; otherwise we initialise our
295elements vector and draw a sample chart.
296<p> <pre> <a href="qmainwindow.html#statusBar">statusBar</a>()-&gt;message( "Ready", 2000 );
297</pre>
298<p> It is <em>vital</em> that we call statusBar() in the constructor, since the
299call ensures that a status bar is created for this main window.
300<p> <h3> init()
301</h3>
302<a name="2-1"></a><p> <pre> void ChartForm::init()
303 {
304 <a href="qwidget.html#setCaption">setCaption</a>( "Chart" );
305 m_filename = <a href="qstring.html#QString-null">QString::null</a>;
306 m_changed = FALSE;
307
308 m_elements[0] = Element( Element::INVALID, red );
309 m_elements[1] = Element( Element::INVALID, cyan );
310 m_elements[2] = Element( Element::INVALID, blue );
311</pre><tt>...</tt>
312<p> We use an init() function because we want to initialise the canvas and
313the elements (in the <tt>m_elements</tt> <tt>ElementVector</tt>) when the form is
314constructed, and also whenever the user loads an existing data set or
315creates a new data set.
316<p> We reset the caption and set the current filename to QString::null. We
317also populate the elements vector with invalid elements. This isn't
318necessary, but giving each element a different color is more
319convenient for the user since when they enter values each one will
320already have a unique color (which they can change of course).
321<p> <h2> The File Handling Actions
322</h2>
323<a name="3"></a><p> <h3> okToClear()
324</h3>
325<a name="3-1"></a><p> <pre> bool ChartForm::okToClear()
326 {
327 if ( m_changed ) {
328 <a href="qstring.html">QString</a> msg;
329 if ( m_filename.isEmpty() )
330 msg = "Unnamed chart ";
331 else
332 msg = QString( "Chart '%1'\n" ).arg( m_filename );
333 msg += "has been changed.";
334
335 int x = QMessageBox::<a href="qmessagebox.html#information">information</a>( this, "Chart -- Unsaved Changes",
336 msg, "&amp;Save", "Cancel", "&amp;Abandon",
337 0, 1 );
338 switch( x ) {
339 case 0: // Save
340 fileSave();
341 break;
342 case 1: // Cancel
343 default:
344 return FALSE;
345 case 2: // Abandon
346 break;
347 }
348 }
349
350 return TRUE;
351 }
352</pre>
353<p> The okToClear() function is used to prompt the user to save their
354values if they have any unsaved data. It is used by several other
355functions.
356<p> <h3> fileNew()
357</h3>
358<a name="3-2"></a><p>
359
360<pre> void ChartForm::fileNew()
361 {
362 if ( okToClear() ) {
363 init();
364 drawElements();
365 }
366 }
367</pre>
368<p> When the user invokes the fileNew() action we call okToClear() to give
369them the opportunity to save any unsaved data. If they either save or
370abandon or have no unsaved data we re-initialise the elements vector
371and draw the default chart.
372<p> <center><table cellpadding="4" cellspacing="2" border="0">
373<tr bgcolor="#d0d0d0">
374<td valign="top">Should we also have invoked optionsSetData() to pop up the dialog
375through which the user can create and edit values, colors etc? You
376could try running the application as it is, and then try it having
377added a call to optionsSetData() and see which you prefer.
378</table></center>
379<p> <h3> fileOpen()
380</h3>
381<a name="3-3"></a><p> <pre> void ChartForm::fileOpen()
382 {
383 if ( !okToClear() )
384 return;
385
386 <a href="qstring.html">QString</a> filename = QFileDialog::<a href="qfiledialog.html#getOpenFileName">getOpenFileName</a>(
387 QString::null, "Charts (*.cht)", this,
388 "file open", "Chart -- File Open" );
389 <a name="x2567"></a> if ( !filename.<a href="qstring.html#isEmpty">isEmpty</a>() )
390 load( filename );
391 else
392 <a href="qmainwindow.html#statusBar">statusBar</a>()-&gt;message( "File Open abandoned", 2000 );
393 }
394</pre>
395<p> We check that it is okToClear(). If it is we use the static
396<a href="qfiledialog.html#getOpenFileName">QFileDialog::getOpenFileName</a>() function to get the name of the file
397the user wishes to load. If we get a filename we call load().
398<p> <h3> fileSaveAs()
399</h3>
400<a name="3-4"></a><p> <pre> void ChartForm::fileSaveAs()
401 {
402 <a href="qstring.html">QString</a> filename = QFileDialog::<a href="qfiledialog.html#getSaveFileName">getSaveFileName</a>(
403 QString::null, "Charts (*.cht)", this,
404 "file save as", "Chart -- File Save As" );
405 if ( !filename.<a href="qstring.html#isEmpty">isEmpty</a>() ) {
406 int answer = 0;
407 <a name="x2563"></a> if ( QFile::<a href="qfile.html#exists">exists</a>( filename ) )
408 <a name="x2566"></a> answer = QMessageBox::<a href="qmessagebox.html#warning">warning</a>(
409 this, "Chart -- Overwrite File",
410 QString( "Overwrite\n\'%1\'?" ).
411 arg( filename ),
412 "&amp;Yes", "&amp;No", QString::null, 1, 1 );
413 if ( answer == 0 ) {
414 m_filename = filename;
415 updateRecentFiles( filename );
416 fileSave();
417 return;
418 }
419 }
420 <a href="qmainwindow.html#statusBar">statusBar</a>()-&gt;message( "Saving abandoned", 2000 );
421 }
422</pre>
423<p> This function calls the static <a href="qfiledialog.html#getSaveFileName">QFileDialog::getSaveFileName</a>() to get
424the name of the file to save the data in. If the file exists we use a
425<a href="qmessagebox.html#warning">QMessageBox::warning</a>() to notify the user and give them the option of
426abandoning the save. If the file is to be saved we update the recently
427opened files list and call fileSave() (covered in <a href="tutorial2-07.html">File Handling</a>) to perform the save.
428<p> <h2> Managing a list of Recently Opened Files
429</h2>
430<a name="4"></a><p>
431
432<pre> <a href="qstringlist.html">QStringList</a> m_recentFiles;
433</pre>
434<p> We hold the list of recently opened files in a string list.
435<p>
436
437<pre> void ChartForm::updateRecentFilesMenu()
438 {
439 for ( int i = 0; i &lt; MAX_RECENTFILES; ++i ) {
440 if ( fileMenu-&gt;<a href="qmenudata.html#findItem">findItem</a>( i ) )
441 fileMenu-&gt;<a href="qmenudata.html#removeItem">removeItem</a>( i );
442 if ( i &lt; int(m_recentFiles.count()) )
443 fileMenu-&gt;<a href="qmenudata.html#insertItem">insertItem</a>( QString( "&amp;%1 %2" ).
444 arg( i + 1 ).arg( m_recentFiles[i] ),
445 this, SLOT( fileOpenRecent(int) ),
446 0, i );
447 }
448 }
449</pre>
450<p> This function is called (usually via updateRecentFiles()) whenever the
451user opens an existing file or saves a new file. For each file in the
452string list we insert a new menu item. We prefix each filename with an
453underlined number from <u>1</u> to <u>9</u> to support keyboard access
454(e.g. <tt>Alt+F, 2</tt> to open the second file in the list). We give the
455menu item an id which is the same as the index position of the item in
456the string list, and connect each menu item to the fileOpenRecent()
457slot. The old file menu items are deleted at the same time by going
458through each possible recent file menu item id. This works because the
459other file menu items had ids created by Qt (all of which are &lt; 0);
460whereas the menu items we're creating all have ids &gt;= 0.
461<p>
462
463<pre> void ChartForm::updateRecentFiles( const <a href="qstring.html">QString</a>&amp; filename )
464 {
465 if ( m_recentFiles.find( filename ) != m_recentFiles.end() )
466 return;
467
468 m_recentFiles.push_back( filename );
469 if ( m_recentFiles.count() &gt; MAX_RECENTFILES )
470 m_recentFiles.pop_front();
471
472 updateRecentFilesMenu();
473 }
474</pre>
475<p> This is called when the user opens an existing file or saves a new
476file. If the file is already in the list it simply returns. Otherwise
477the file is added to the end of the list and if the list is too large
478(&gt; 9 files) the first (oldest) is removed. updateRecentFilesMenu() is
479then called to recreate the list of recently used files in the File
480menu.
481<p>
482
483<pre> void ChartForm::fileOpenRecent( int index )
484 {
485 if ( !okToClear() )
486 return;
487
488 load( m_recentFiles[index] );
489 }
490</pre>
491<p> When the user selects a recently opened file the fileOpenRecent() slot
492is called with the menu id of the file they have selected. Because we
493made the file menu ids equal to the files' index positions in the
494<tt>m_recentFiles</tt> list we can simply load the file indexed by the menu
495item id.
496<p> <h2> Quiting
497</h2>
498<a name="5"></a><p> <pre> void ChartForm::fileQuit()
499 {
500 if ( okToClear() ) {
501 saveOptions();
502 qApp-&gt;<a href="qapplication.html#exit">exit</a>( 0 );
503 }
504 }
505</pre>
506<p> When the user quits we give them the opportunity to save any unsaved
507data (okToClear()) then save their options, e.g. window size and
508position, chart type, etc., before terminating.
509<p> <pre> void ChartForm::saveOptions()
510 {
511 <a href="qsettings.html">QSettings</a> settings;
512 settings.<a href="qsettings.html#insertSearchPath">insertSearchPath</a>( QSettings::Windows, WINDOWS_REGISTRY );
513 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "WindowWidth", width() );
514 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "WindowHeight", height() );
515 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "WindowX", x() );
516 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "WindowY", y() );
517 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "ChartType", int(m_chartType) );
518 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "AddValues", int(m_addValues) );
519 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "Decimals", m_decimalPlaces );
520 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "Font", m_font.toString() );
521 for ( int i = 0; i &lt; int(m_recentFiles.count()); ++i )
522 settings.<a href="qsettings.html#writeEntry">writeEntry</a>( APP_KEY + "File" + QString::number( i + 1 ),
523 m_recentFiles[i] );
524 }
525</pre>
526<p> Saving the user's options using <a href="qsettings.html">QSettings</a> is straight-forward.
527<p> <h2> Custom Dialogs
528</h2>
529<a name="6"></a><p> We want the user to be able to set some options manually and to create
530and edit values, value colors, etc.
531<p>
532
533<pre> void ChartForm::optionsSetOptions()
534 {
535 OptionsForm *optionsForm = new OptionsForm( this );
536 optionsForm-&gt;chartTypeComboBox-&gt;setCurrentItem( m_chartType );
537 optionsForm-&gt;<a href="qwidget.html#setFont">setFont</a>( m_font );
538</pre><pre> if ( optionsForm-&gt;<a href="qdialog.html#exec">exec</a>() ) {
539 setChartType( ChartType(
540 optionsForm-&gt;chartTypeComboBox-&gt;currentItem()) );
541 m_font = optionsForm-&gt;<a href="qwidget.html#font">font</a>();
542</pre><pre> drawElements();
543 }
544 delete optionsForm;
545 }
546</pre>
547<p> The form for setting options is provided by our custom <tt>OptionsForm</tt>
548covered in <a href="tutorial2-09.html">Setting Options</a>. The
549options form is a standard "dumb" dialog: we create an instance, set
550all its GUI elements to the relevant settings, and if the user clicked
551"OK" (exec() returns a true value) we read back settings from the GUI
552elements.
553<p>
554
555<pre> void ChartForm::optionsSetData()
556 {
557 SetDataForm *setDataForm = new SetDataForm( &amp;m_elements, m_decimalPlaces, this );
558 if ( setDataForm-&gt;<a href="qdialog.html#exec">exec</a>() ) {
559 m_changed = TRUE;
560 drawElements();
561 }
562 delete setDataForm;
563 }
564</pre>
565<p> The form for creating and editing chart data is provided by our custom
566<tt>SetDataForm</tt> covered in <a href="tutorial2-08.html">Taking Data</a>.
567This form is a "smart" dialog. We pass in the data structure we want
568to work on, and the dialog handles the presentation of the data
569structure itself. If the user clicks "OK" the dialog will update the
570data structure and exec() will return a true value. All we need to do
571in optionsSetData() if the user changed the data is mark the chart as
572changed and call drawElements() to redraw the chart with the new and
573updated data.
574<p> <p align="right">
575<a href="tutorial2-04.html">&laquo; Mainly Easy</a> |
576<a href="tutorial2.html">Contents</a> |
577<a href="tutorial2-06.html">Canvas Control &raquo;</a>
578</p>
579<p>
580<!-- eof -->
581<p><address><hr><div align=center>
582<table width=100% cellspacing=0 border=0><tr>
583<td>Copyright &copy; 2007
584<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
585<td align=right><div align=right>Qt 3.3.8</div>
586</table></div></address></body>
587</html>
Note: See TracBrowser for help on using the repository browser.