. An Introduction to Qt and Workshop Qt in Education
http://www.pelagicore.com/documents/2011-Apr-QtWorkshop.odp © 2011 Nokia Corporation and its Subsidiary(-ies). The enclose...
The Presenter <ul>Johan Thelin  <johan.thelin@pelagicore.com> <li>Creates middleware for in-vehicle infotainment based on ...
Thesis work within embedded Linux, open source and design </li></ul>
What is Qt? <ul><li>C++ framework – bindings for other languages </li><ul><li>Python, Ruby, C#, etc. </li></ul><li>Origina...
What is Qt? <ul><li>Qt is made up of modules </li><ul><li>All modules have a common scheme and are built from the same API...
What is Qt? <ul><li>Qt extends C++ with macros and introspection
All code is still plain C++ </li></ul>foreach (int value, intList) { … } QObject *o = new QPushButton; o->metaObject()->cl...
Desktop target platforms <ul><li>Windows
Mac OS X
Linux/Unix X11 </li></ul>
Embedded target platforms <ul><li>Windows CE
Symbian
Maemo
Embedded Linux </li><ul><li>Direct framebuffer access </li></ul></ul>
Community target platforms <ul><li>Android – Necessitas and Ministri </li></ul>http://sourceforge.net/p/necessitas/home/ <...
Hello World
Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); ...
Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); ...
Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); ...
Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); ...
Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); ...
The QObject <ul><li>They can have a name ( QObject::objectName )
They are placed in a hierarchy of  QObject  instances
They can have connections to other  QObject  instances
Example: does it make sense to copy a widget at run-time? </li></ul>“ QObject instances are individuals!”
Meta data <ul><li>Qt implements introspection in C++
Every  QObject  has a  meta object
The meta object knows about </li><ul><li>class name ( QObject::className )
inheritance ( QObject::inherits )
properties
signals and slots
general information ( QObject::classInfo ) </li></ul></ul>
Memory Management <ul><li>QObject  can have parent and children
When a parent object is deleted, it deletes its children </li></ul>QObject *parent = new QObject(); QObject *child1 = new ...
Memory Management <ul><li>This is used when implementing visual hierarchies. </li></ul>QDialog *parent = new QDialog(); QG...
Usage Patterns <ul><li>Use the  this- pointer as top level parent
Allocate parent on the stack </li></ul>void Widget::showDialog() { Dialog dialog; if (dialog.exec() == QDialog::Accepted) ...
Heap <ul><li>When using  new  and  delete , memory is allocated on the heap.
Heap memory must be explicitly freed using  delete  to avoid memory leaks.
Objects allocated on the heap can live for as long as they are needed. </li></ul>new delete Construction Destruction
Stack <ul><li>Local variables are allocated on the stack.
Stack variables are automatically destructed when they go out of scope.
Objects allocated on the stack are always destructed when they go out of scope. </li></ul>int a } Construction Destruction
Stack and Heap <ul><li>To get automatic memory management, only the parent needs to be allocated on the stack. </li></ul>i...
Signals and Slots <ul><li>Dynamically and loosely tie together events and state changes with reactions
What makes Qt tick </li></ul>
Signals and Slots in Action emit clicked();
Signals and Slots in Action private slots: void on_addButton_clicked(); void on_deleteButton_clicked(); connect(clearButto...
Signals and Slots in Action { ... emit clicked(); ... } { ... emit clicked(); ... } { ... emit clicked(); ... } { QString ...
What is a slot? <ul><li>A slot is defined in one of the slots sections
A slot can return values, but not through connections
Any number of signals can be connected to a slot
It is implemented as an ordinary method
It can be called as an ordinary method </li></ul>public slots: void aPublicSlot(); protected slots: void aProtectedSlot();...
What is a signal? <ul><li>A signal is defined in the signals section
A signal always returns void
A signal must not be implemented </li><ul><li>The moc provides an implementation </li></ul><li>A signal can be connected t...
Usually results in a direct call, but can be passed as events between threads, or even over sockets (using 3 rd  party cla...
The slots are activated in arbitrary order
A signal is emitted using the emit keyword </li></ul>signals: void aSignal(); emit aSignal();
Making the connection QObject::connect( src, SIGNAL( signature ), dest, SLOT( signature ) ); <function name> ( <arg type>....
Making the connection <ul><li>Qt can ignore arguments, but not create values from nothing </li></ul>Signals rangeChanged(i...
Automatic Connections <ul><li>When using Designer it is convenient to have automatic connections between the interface and...
Triggered by calling  QMetaObject::connectSlotsByName
Think about reuse when naming </li><ul><li>Compare  on_widget_signal  to  updatePageMargins </li></ul></ul>on_  object nam...
Much more... <ul><li>QtQuick – cool animated user interfaces </li></ul>http://qt.nokia.com/qtquick/
Goal of the day <ul><li>Build and entire application </li><ul><li>Document window(s)
Dialogs
Menus, toolbars, statusbars
Basic file management Open, Save and Save As </li></ul></ul>We will run out of time!
Goal of the day
Creating a project <ul><li>In QtCreator, create a  Qt4 Gui Application  project
Use the  QtCore  and  QtGui  modules
Base the skeleton project on a  QMainWindow </li></ul>
Creating a project <ul><li>The resulting project contains five files </li><ul><li>TextEditor.pro  – the project  definitio...
mainwindow.ui  – the user  interface of the main window
mainwindow.h/cpp  – the class  declaration and implementation  of the main window
main.cpp  – the main function,  getting everything initialized  and running </li></ul></ul>
The plan <ul><li>This lecture will build a text editor in an iterative process
Features will be added to the application, while maintaining a functioning application through-out the process
This is how most software is being built  in real life! </li></ul>
Starting with the user interface <ul><li>Add a  QTextEdit  widget to the main window form </li></ul>
Starting with the user interface <ul><li>Apply a layout to the central widget </li></ul>
Starting with the user interface <ul><li>Set the layout margin properties to zero </li></ul>You have to  deselect and rese...
Adding actions <ul><li>With the text editing central widget in place, the next step will be to let the user create new doc...
For each of these user actions, a  QAction  object will be created </li></ul>
Why QAction <ul><li>Many user interface elements refer to the same action
Do not forget tooltips, statusbar tips, etc. </li></ul>Ctrl+S Action
Why QAction <ul><li>A  QAction  encapsulates all settings needed for menus, tool bars and keyboard shortcuts
Commonly used properties are </li><ul><li>text  – the text used everywhere
icon  – icon to be used everywhere
shortcut  – shortcut
checkable / checked  – if the action is checkable and the current check status
toolTip / statusTip  – tips text for tool tips (hover and wait) and status bar tips (hover, no wait) </li></ul></ul>
Why QAction QAction *action = new QAction( parent ); action->setText(&quot;text&quot;); action->setIcon(QIcon(&quot;:/icon...
Why QAction <ul><li>Designer has an action editor at the bottom of the screen
Tools – Form Editor –  Views – Action Editor </li></ul><ul><li>Adding a new action brings up a dialog with the details (na...
Upcoming SlideShare
Loading in...5
×

Qt Workshop

3,778

Published on

The slides from a Qt workshop held on a FSCONS Hacknight. Video of the first half is available from here: http://vimeo.com/22332184

Published in: Technology, Self Improvement
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,778
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
171
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide
  • Qt, is a cross platform development framework written in C++. This does not limit the languages used. Bindings are available for Python, Ruby, C# (mono), Ada, Pascal, Perl, PHP (see: http://qt.nokia.com/products/programming-language-support ) Most people know Qt for its cross platform user interface abilities. Cross platform development is about so much more. For instance, just compare file paths between Windows and Unix. Qt provides classes for almost all conceivable tasks.
  • Qt supports a multitude of functions in a cross platform manner. This means that Qt is a large package. Qt is divided into modules, and when building and deploying, you can choose which module to use. This helps reducing the number of bytes needed to deploy. Also, there are a few platform specific modules (e.g. QtDBUS for inter process communication – unix only, QtAxContainer and QtAxServer for building and using ActiveX components – Windows only)
  • Qt extends C++ while sticking to pure C++. Examples of what you get (there is much more): “ foreach” loops Meta-information, great for casting, working with dynamic trees of classes, etc. Using meta-information, dynamic connections such as the connect example is possible.
  • Qt is available for all major desktop platforms. Windows XP/Vista/7 are officially supported OS X, latest version of Qt supports at least down to 10.3 (10.4 or later is required for development) Linux/Unix with X11, i.e. not tied to Linux. Official support for Linux, AIX, HPUX, Solaris. Community support for FreeBSD, OpenBSD, NetBSD, etc. Notice that the X11 support is not focused to deploying KDE on all desktops. Instead, Qt aims to integrate as a native part of all desktops, including Gnome.
  • Qt is also available for a number of embedded platforms. Windows CE, versions 5 and 6. Symbian S60, well tested with 3.1, 3.2 and 5.0. Maemo, so you can use it on your N900 tablets Embedded Linux, using the framebuffer directly, i.e. no X11 and a smaller footprint. Can accelerate on some platforms. A nice example is the beagleboard. Tier 3 platforms: QNX, WxWorks. Supported by partner companies.
  • Qt is also available for a number of embedded platforms. Windows CE, versions 5 and 6. Symbian S60, well tested with 3.1, 3.2 and 5.0. Maemo, so you can use it on your N900 tablets Embedded Linux, using the framebuffer directly, i.e. no X11 and a smaller footprint. Can accelerate on some platforms. A nice example is the beagleboard. Tier 3 platforms: QNX, WxWorks. Supported by partner companies.
  • Walkthrough The target of the project This will be the starting point of the exercises for this lecture.
  • Walkthrough The entire source, focus on: - simplicity - small code
  • Walkthrough Focus on includes. All Qt classes are included by name, compare with iostream, etc. No “.h” ending, capitalization.
  • Walkthrough One QApplication object, drives the application, manages global settings. There must always be a QApplication object. You can always access the QApplication object through the qApp pointer. You can look at this as a singleton, but the instantiation must be made explicitly from the main function.
  • Walkthrough QLabel, is a widget. The text is passed to the constructor before the widget is shown. Elaborate, everything is built from widgets. Widgets can be labels (as here), buttons, sliders, group boxes, windows, etc. As the label does not have a parent widget, i.e. it is not contained by another widget, it is a top-level widget. This means that it will result in a new window that is decorated by the native window manager.
  • Walkthrough Calling exec start the event loop. This gets everything running. The event loop ends when last window closes (can be turned off). Having started the event loop, you must change mind-set. Everything from here on is event driven, be it user interaction (keys or mouse), network or timer.
  • So, why cannot QChar be a QObject. QObjects are individuals! This means that you cannot write obj1 = obj2, copy is not a valid operation. Why? QObjects have names, for instance addButton, deleteButton, etc (from the first lecture&apos;s demo). How do you copy this? You don&apos;t want two addButtons? QObjects are structured in hierarchies. How do you copy that context? Do you want them at the same level? Leaf level? Root level? QObjects can be interconnected (add calls a slot) How do you copy this? Do you want to duplicate connections?
  • QObjects carry meta-data, that is data about the object itself. This makes it possible to add introspection to Qt, for instance to ask a class which methods it has Every QObject has a meta object which can be retreived using the metaObject method. The meta object knows about the class, its name, base class, properties, methods, slots and signals. Continues
  • QObjects can be used in a way that takes care of all the dirty parts of memory management. It becomes almost as easy as working with a garbage collector, but you are still in full control. The trick is that all QObjects have a parent, or an owner. When the parent is deleted, it deletes all its children. This reduces the number of objects that you need to keep track of to one, in the ideal case. Continues
  • The very same parent-child relationship is used to represent visual hierarchies. Refer to the tree structure, the box contains the radio buttons (option1/2). The parent contains the box and the button. Compare to the previous slide. Continues
  • So, how does this make memory management easy. I still need to keep track of an object and make sure that I delete it? No, not if you use the stack cleverly. First of all, the example from the previous slide would probably have been implemented in the parent&apos;s constructor, i.e. this is the top-level parent. Second, when using the dialog, you allocate it on the stack. This means that the dialog, along with all its children, will be deleted when the scope ends. Continues
  • These slides intend to jog the students&apos; memory, not explain the stack vs heap decision in full. The heap is used when you allocate memory dynamically . In C++, that means new/delete. In C you have used malloc and free. Heap memory must be explicitly freed, i.e. you must call delete on everything that you allocate. If you do not do so, you will leak memory. This will, eventually, lead to memory shortage and a crash. Dynamically allocated objects live until you delete them, so you have full control of when something is constructed or destructed. Continues
  • The stack is used for automatic memory allocations (as opposed to dynamic memory). The stack grows and shrinks when you make function calls. It is used for local variables, function arguments and return addresses. Objects allocated on the stack are destructed when they go out of scope. The scope ends with a }, or return, or for single-line scopes, at the end of the line. Continues
  • To get almost automatic memory management using Qt, the trick is to allocate the outermost parents on the stack, and the rest on the heap. For instance, the main function scope will be valid for as long as the application is running, so we allocate the application and window on the stack. The window, in turn, creates a bunch of child widgets in its constructor. To avoid destruction when the scope of the constructor ends, they are allocated dynamically. But, they are given the window as their parent object and are thus also destructed when the main function scope ends.
  • One of the key factors of Qt is the signals and slots mechanism. It is a mechanism to dynamically and loosely tie together events and changes with reactions Dynamically = at run-time Loosely = sender and receiver do not know each other events = timer event, clicks, etc. Not to be confused with actual events (QEvent). state changes = size changed, text changed, value changed, etc reactions = source code that actually does something This is what makes a Qt application tick Continues
  • Looking at an example from the first lecture. The three buttons all emit the clicked signal when they are clicked by the user (or activated by other means). They do this regardless whether something is connected to them or not, and regardless of what is connected to them. Continues
  • We choose to connect the buttons to the list widget&apos;s clear slot, and two custom slots in our custom code. As said earlier, the buttons do not care what they are connected to, and the slots are equally independent of what triggers them. You can even call them programatically as ordinary functions. Continues
  • So, the add button emits clicked, ending up in the on_addButton_clicked slot resulting in the following code being run. It simply asks for input and then adds it to the list. The delete button emits clicked, ending up in the on_deleteButton_clicked slot, where all selected items are deleted. The clear button emits clicked, which ends up in the clear slot of the QListWidget, which to us is a black box that does what its documentation says.
  • A slot is an ordinary function, just that it can be connected to signals. They do not have to be connected, you can call a slot like any other function, and you implement it as usual. Slots are declared in one of the sections public, protected and private slots. These access restrictions work as intended when calling the function, but a private or protected slot can be connected to any other signal, so they can be triggered from outside the class. Slots can return values, but connections cannot carry return arguments. Any number of signals can be connected to a single slot. This means that a single slot can serve several sources of events – think keyboard shortcut, button, etc. Continues
  • Signals are defined in the signals section. This section can be considered protected, as a signal can only be emitted from within a class or its decendants. Signals always return void, and must not be implemented. Instead, moc provides function bodies that trigger the actual slot-activation-code. A signal can be connected to any number of slots, so a single event can trigger multiple reactions. It is fully possible to connect signals and slots across threads. Third party libraries such as Qxt ( http://doc.libqxt.org/0.5.0/classQxtRPCPeer.html ). Inside a signal emitting class, you use the emit keyword to emit a signal. The emit keyword is defined as nothing, what actually takes place is a call to the signal function which calls the slots. Continues
  • You can make signals to slots connections between any two QObjects. Qt verifies that the signatures of the signal and slot match. The signature consists of the name of the signal or slot followed by the argument types . There must be no values nor variable names in the signature. It is also recommended to stick to using standard types, e.g. the ItemClass custom type reduces the reusability and should thus be avoided. Continues
  • When matching signatures, Qt is very forgiving. The basic rule is that Qt cannot create or convert values, but apart from that anything is allowed (i.e. skipping arguments). The examples on the slide demonstrate this. The errors are (from the top): missing the last int (cannot create) QString does not match int (cannot convert) missing the only int (cannot create) Continues
  • When making connections from Designer to your own source, Qt uses the automatic connection mechanism. It lets signals automatically connect to slots with the corresponding name (structure and examples on the slide). The automatic connections are made when connectSlotsByName is called. That is done at the end of the setupUi function generated by Designer. When using this mechanism, think about reusability. Sometimes handwriting a couple of connect statements can greatly improve readability of the code. Continues
  • Read clockwise The application stops executing with the last window has been closed...
  • Mention that OS X removes the [*], instead a dot in the left-most ball is used to indicate if the document is modified or not.
  • windowtitles should be interpreted as automatic window titles...
  • Qt Workshop

    1. 1. . An Introduction to Qt and Workshop Qt in Education
    2. 2. http://www.pelagicore.com/documents/2011-Apr-QtWorkshop.odp © 2011 Nokia Corporation and its Subsidiary(-ies). The enclosed Qt Materials are provided under the Creative Commons Attribution-Share Alike 2.5 License Agreement. The full license text is available here: http://creativecommons.org/licenses/by-sa/2.5/legalcode . Nokia, Qt and the Nokia and Qt logos are the registered trademarks of Nokia Corporation in Finland and other countries worldwide.
    3. 3. The Presenter <ul>Johan Thelin <johan.thelin@pelagicore.com> <li>Creates middleware for in-vehicle infotainment based on MeeGo
    4. 4. Thesis work within embedded Linux, open source and design </li></ul>
    5. 5. What is Qt? <ul><li>C++ framework – bindings for other languages </li><ul><li>Python, Ruby, C#, etc. </li></ul><li>Originally for user interfaces – now for everything </li><ul><li>Databases, XML, WebKit, multimedia, networking, OpenGL, scripting, non-GUI... </li></ul></ul>“ Qt is a cross platform development framework written in C++.”
    6. 6. What is Qt? <ul><li>Qt is made up of modules </li><ul><li>All modules have a common scheme and are built from the same API design ideas </li></ul></ul>QtCore Phonon QtXmlPatterns QtXml QtWebKit QtSvg QtSql QtScript QtOpenVG QtOpenGL QtNetwork QtMultimedia QtGui
    7. 7. What is Qt? <ul><li>Qt extends C++ with macros and introspection
    8. 8. All code is still plain C++ </li></ul>foreach (int value, intList) { … } QObject *o = new QPushButton; o->metaObject()->className(); // returns ”QPushButton” connect(button, SIGNAL(clicked()), window, SLOT(close()));
    9. 9. Desktop target platforms <ul><li>Windows
    10. 10. Mac OS X
    11. 11. Linux/Unix X11 </li></ul>
    12. 12. Embedded target platforms <ul><li>Windows CE
    13. 13. Symbian
    14. 14. Maemo
    15. 15. Embedded Linux </li><ul><li>Direct framebuffer access </li></ul></ul>
    16. 16. Community target platforms <ul><li>Android – Necessitas and Ministri </li></ul>http://sourceforge.net/p/necessitas/home/ <ul><li>iOS, Kindle, QNX, wxWorks... </li></ul>
    17. 17. Hello World
    18. 18. Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); QLabel l( &quot;Hello World!&quot; ); l.show(); return app.exec(); }
    19. 19. Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); QLabel l( &quot;Hello World!&quot; ); l.show(); return app.exec(); }
    20. 20. Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); QLabel l( &quot;Hello World!&quot; ); l.show(); return app.exec(); }
    21. 21. Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); QLabel l( &quot;Hello World!&quot; ); l.show(); return app.exec(); }
    22. 22. Hello World #include <QApplication> #include <QLabel> int main( int argc, char **argv ) { QApplication app( argc, argv ); QLabel l( &quot;Hello World!&quot; ); l.show(); return app.exec(); }
    23. 23. The QObject <ul><li>They can have a name ( QObject::objectName )
    24. 24. They are placed in a hierarchy of QObject instances
    25. 25. They can have connections to other QObject instances
    26. 26. Example: does it make sense to copy a widget at run-time? </li></ul>“ QObject instances are individuals!”
    27. 27. Meta data <ul><li>Qt implements introspection in C++
    28. 28. Every QObject has a meta object
    29. 29. The meta object knows about </li><ul><li>class name ( QObject::className )
    30. 30. inheritance ( QObject::inherits )
    31. 31. properties
    32. 32. signals and slots
    33. 33. general information ( QObject::classInfo ) </li></ul></ul>
    34. 34. Memory Management <ul><li>QObject can have parent and children
    35. 35. When a parent object is deleted, it deletes its children </li></ul>QObject *parent = new QObject(); QObject *child1 = new QObject(parent); QObject *child2 = new QObject(parent); QObject *child1_1 = new QObject(child1); QObject *child1_2 = new QObject(child1); delete parent;
    36. 36. Memory Management <ul><li>This is used when implementing visual hierarchies. </li></ul>QDialog *parent = new QDialog(); QGroupBox *box = new QGroupBox(parent); QPushButton *button = new QPushButton(parent); QRadioButton *option1 = new QRadioButton(box); QRadioButton *option2 = new QRadioButton(box); delete parent;
    37. 37. Usage Patterns <ul><li>Use the this- pointer as top level parent
    38. 38. Allocate parent on the stack </li></ul>void Widget::showDialog() { Dialog dialog; if (dialog.exec() == QDialog::Accepted) { ... } } Dialog::Dialog(QWidget *parent) : QDialog(parent) { QGroupBox *box = QGroupBox(this); QPushButton *button = QPushButton(this); QRadioButton *option1 = QRadioButton(box); QRadioButton *option2 = QRadioButton(box); ...
    39. 39. Heap <ul><li>When using new and delete , memory is allocated on the heap.
    40. 40. Heap memory must be explicitly freed using delete to avoid memory leaks.
    41. 41. Objects allocated on the heap can live for as long as they are needed. </li></ul>new delete Construction Destruction
    42. 42. Stack <ul><li>Local variables are allocated on the stack.
    43. 43. Stack variables are automatically destructed when they go out of scope.
    44. 44. Objects allocated on the stack are always destructed when they go out of scope. </li></ul>int a } Construction Destruction
    45. 45. Stack and Heap <ul><li>To get automatic memory management, only the parent needs to be allocated on the stack. </li></ul>int main(int argc, char **argv) { QApplication a(argc, argv); MyMainWindow w; w.show(); return a.exec(); } MyMainWindow::MyMainWindow(... { new QLabel(this); new ... } MyMainWindow QApplication
    46. 46. Signals and Slots <ul><li>Dynamically and loosely tie together events and state changes with reactions
    47. 47. What makes Qt tick </li></ul>
    48. 48. Signals and Slots in Action emit clicked();
    49. 49. Signals and Slots in Action private slots: void on_addButton_clicked(); void on_deleteButton_clicked(); connect(clearButton,SIGNAL(clicked()),listWidget,SLOT(clear())); connect(addButton,SIGNAL(clicked()),this,SLOT(...)); 2x clear();
    50. 50. Signals and Slots in Action { ... emit clicked(); ... } { ... emit clicked(); ... } { ... emit clicked(); ... } { QString newText = QInputDialog::getText(this, &quot;Enter text&quot;, &quot;Text:&quot;); if( !newText.isEmpty() ) ui->listWidget->addItem(newText); } { foreach (QListWidgetItem *item, ui->listWidget->selectedItems()) { delete item; } } clear();
    51. 51. What is a slot? <ul><li>A slot is defined in one of the slots sections
    52. 52. A slot can return values, but not through connections
    53. 53. Any number of signals can be connected to a slot
    54. 54. It is implemented as an ordinary method
    55. 55. It can be called as an ordinary method </li></ul>public slots: void aPublicSlot(); protected slots: void aProtectedSlot(); private slots: void aPrivateSlot(); connect(src, SIGNAL(sig()), dest, SLOT(slt()));
    56. 56. What is a signal? <ul><li>A signal is defined in the signals section
    57. 57. A signal always returns void
    58. 58. A signal must not be implemented </li><ul><li>The moc provides an implementation </li></ul><li>A signal can be connected to any number of slots
    59. 59. Usually results in a direct call, but can be passed as events between threads, or even over sockets (using 3 rd party classes)
    60. 60. The slots are activated in arbitrary order
    61. 61. A signal is emitted using the emit keyword </li></ul>signals: void aSignal(); emit aSignal();
    62. 62. Making the connection QObject::connect( src, SIGNAL( signature ), dest, SLOT( signature ) ); <function name> ( <arg type>... ) clicked() toggled(bool) setText(QString) textChanged(QString) rangeChanged(int,int) setTitle(QString text) setValue(42) A signature consists of the function name and argument types. No variable names, nor values are allowed. Custom types reduces reusability. setItem(ItemClass)
    63. 63. Making the connection <ul><li>Qt can ignore arguments, but not create values from nothing </li></ul>Signals rangeChanged(int,int) rangeChanged(int,int) rangeChanged(int,int) valueChanged(int) valueChanged(int) valueChanged(int) textChanged(QString) clicked() clicked() Slots setRange(int,int) setValue(int) updateDialog() setRange(int,int) setValue(int) updateDialog() setValue(int) setValue(int) updateDialog()
    64. 64. Automatic Connections <ul><li>When using Designer it is convenient to have automatic connections between the interface and your code
    65. 65. Triggered by calling QMetaObject::connectSlotsByName
    66. 66. Think about reuse when naming </li><ul><li>Compare on_widget_signal to updatePageMargins </li></ul></ul>on_ object name _ signal name ( signal parameters ) on_addButton_clicked(); on_deleteButton_clicked(); on_listWidget_currentItemChanged(QListWidgetItem*,QListWidgetItem*)
    67. 67. Much more... <ul><li>QtQuick – cool animated user interfaces </li></ul>http://qt.nokia.com/qtquick/
    68. 68. Goal of the day <ul><li>Build and entire application </li><ul><li>Document window(s)
    69. 69. Dialogs
    70. 70. Menus, toolbars, statusbars
    71. 71. Basic file management Open, Save and Save As </li></ul></ul>We will run out of time!
    72. 72. Goal of the day
    73. 73. Creating a project <ul><li>In QtCreator, create a Qt4 Gui Application project
    74. 74. Use the QtCore and QtGui modules
    75. 75. Base the skeleton project on a QMainWindow </li></ul>
    76. 76. Creating a project <ul><li>The resulting project contains five files </li><ul><li>TextEditor.pro – the project definition file
    77. 77. mainwindow.ui – the user interface of the main window
    78. 78. mainwindow.h/cpp – the class declaration and implementation of the main window
    79. 79. main.cpp – the main function, getting everything initialized and running </li></ul></ul>
    80. 80. The plan <ul><li>This lecture will build a text editor in an iterative process
    81. 81. Features will be added to the application, while maintaining a functioning application through-out the process
    82. 82. This is how most software is being built in real life! </li></ul>
    83. 83. Starting with the user interface <ul><li>Add a QTextEdit widget to the main window form </li></ul>
    84. 84. Starting with the user interface <ul><li>Apply a layout to the central widget </li></ul>
    85. 85. Starting with the user interface <ul><li>Set the layout margin properties to zero </li></ul>You have to deselect and reselect the central widget to see these properties after you have applied the layout
    86. 86. Adding actions <ul><li>With the text editing central widget in place, the next step will be to let the user create new documents, close the current document and to exit the application
    87. 87. For each of these user actions, a QAction object will be created </li></ul>
    88. 88. Why QAction <ul><li>Many user interface elements refer to the same action
    89. 89. Do not forget tooltips, statusbar tips, etc. </li></ul>Ctrl+S Action
    90. 90. Why QAction <ul><li>A QAction encapsulates all settings needed for menus, tool bars and keyboard shortcuts
    91. 91. Commonly used properties are </li><ul><li>text – the text used everywhere
    92. 92. icon – icon to be used everywhere
    93. 93. shortcut – shortcut
    94. 94. checkable / checked – if the action is checkable and the current check status
    95. 95. toolTip / statusTip – tips text for tool tips (hover and wait) and status bar tips (hover, no wait) </li></ul></ul>
    96. 96. Why QAction QAction *action = new QAction( parent ); action->setText(&quot;text&quot;); action->setIcon(QIcon(&quot;:/icons/icon.png&quot;)); action->setShortcut(QKeySequence(&quot;Ctrl+G&quot;)); action->setData(myDataQVariant); Setting properties for text, icon and keyboard short-cut Creating a new action A QVariant can be associated with each action, to carry data associated with the given operation
    97. 97. Why QAction <ul><li>Designer has an action editor at the bottom of the screen
    98. 98. Tools – Form Editor – Views – Action Editor </li></ul><ul><li>Adding a new action brings up a dialog with the details (name, text, tips...)
    99. 99. Action icons can be added either from files or resources </li></ul>
    100. 100. Icon resources <ul><li>Putting icons in a resource file lets Qt embed them into the executable </li><ul><li>Avoid having to deploy multiple files
    101. 101. No need to trying to determine the path for the icons for each specific install type
    102. 102. All fits neatly into the build system
    103. 103. ...
    104. 104. You can add anything into resources, not only icons </li></ul></ul>
    105. 105. Creating a resource file <ul><li>Adding a resource file to a project is just as adding any source file to a project
    106. 106. When having added the resource file, make sure to close any Designer forms and re-open them for Designer to discover the resource </li></ul>
    107. 107. Adding resources <ul><li>Opening the resource file gives you the resource file editor
    108. 108. Before any resources can be added to the resource file, you must first create a directory in the resource file
    109. 109. In this case we put icons into the /icons directory </li></ul>
    110. 110. Adding actions <ul><li>From Designer, you can now pick an icon for the actions that you plan to show in toolbars
    111. 111. Click “...” next to the icon setting
    112. 112. Pick “ Choose Resource...” </li></ul><ul><li>Pick the icon from the resource directory tree </li></ul>
    113. 113. Adding actions <ul><li>When you have added your actions to the action editor, you need to add them to the form
    114. 114. To add them to the toolbar, simply drag and drop </li></ul>
    115. 115. Adding actions <ul><li>To add them to a menu, double click on “Type here” and enter the menu title, then drag and drop action onto the menu </li></ul>Typing “&File”, makes “F” a keyboard shortcut To enter “&” in a menu, type “&&” as the text.
    116. 116. Adding actions <ul><li>In this first iteration, we add the most basic actions </li></ul>The name is automatically generated when entering the text for the action Close and Exit are added to the menu. To add a separator, double click “Add Separator” then drag it into place. Text Name Icon Short-cut Tool-tip New actionNew Ctrl+N Create a new document Close actionClose Ctrl+W Close current window Exit actionExit Exit application
    117. 117. Implementing new <ul><li>By right clicking on the action in the action editor, you can go the corresponding slot
    118. 118. Slots are generated on the fly in both header and implementation
    119. 119. Implementing the new slot is easy – just create a new MainWindow and show it </li></ul>void MainWindow::on_actionNew_triggered() { MainWindow *w = new MainWindow(); w->show(); }
    120. 120. Closing and Exiting MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); connect(ui->actionClose, SIGNAL(triggered()), this, SLOT(close())); connect(ui->actionExit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); } Setting the WA_DeleteOnClose attribute makes the widget delete itself when it is closed All widgets has a close slot out-of-the-box The QApplication class has a slot for closing all windows The qApp pointer refers to the current QApplication instance
    121. 121. Status update <ul><li>Now, we have a window with a working text editing widget
    122. 122. New windows can be created
    123. 123. Windows can be closed
    124. 124. The application can exit (i.e. close all windows) </li></ul>
    125. 125. Do not close what is modified <ul><li>Now, the windows close regardless of their contents
    126. 126. The expected behavior would be to ask the user before close a modified document
    127. 127. To implement this, we add a modified flag which is set whenever the text of the QTextEdit is changed
    128. 128. We also intercept close events and ask the user before closing modified events </li></ul>
    129. 129. The modified flag <ul><li>Declaration and initialization </li></ul>class MainWindow : public QMainWindow { ... private: bool m_modified; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_modified(false) { ...
    130. 130. The modified flag <ul><li>Keeping track of the document </li></ul>MainWindow::MainWindow(QWidget *parent) ... { ... connect(ui->textEdit, SIGNAL(textChanged()), this, SLOT(documentModified())); } void MainWindow::documentModified() { m_modified = true; }
    131. 131. Closing safely <ul><li>When a window is closed, the top-level widget can accept or ignore the close event </li><ul><li>Accept means that the window will close (and be deleted in this case)
    132. 132. Ignore means that the window will remain open </li></ul><li>All events are handled in the QObject::event method
    133. 133. QWidget provides virtual methods for the most common events, e.g. QWidget::closeEvent </li></ul>
    134. 134. Closing safely <ul><li>Re-implementing the closeEvent method to ask the user before closing a window with a modified document </li></ul>void MainWindow::closeEvent(QCloseEvent *e) { if(m_modified) { if(QMessageBox::warning(this, &quot;Document Modified&quot;, &quot;The document has been modified, do you want to close it?n&quot; &quot;You will lose all your changes.&quot;, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { e->accept() ; } else { e->ignore() ; } } else { e->accept(); } } Unmodified windows are always closed Depending on the user's answer, the event is accepted or ignored
    135. 135. QMessageBox <ul><li>The QMessageBox class can be used to show
    136. 136. question dialogs
    137. 137. information dialogs
    138. 138. warning dialogs
    139. 139. critical dialogs
    140. 140. about dialogs for both the current application and Qt itself </li></ul>Roughly the same type of dialogs with a title, a message and one or more buttons. The green words are function names for static members. To show an information dialog, use QMessageBox::information , etc.
    141. 141. QMessageBox QMessageBox::warning(this, &quot;Document Modified&quot;, &quot;The document has been modified, do you want to close it?n&quot; &quot;You will lose all your changes.&quot;, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes Parent window Dialog title The message of the dialog. Notice the use of ' n ' The buttons to use. Pick from Ok , Open , Save , Cancel , Close , Discard , Apply , Reset , Restore defaults , Help , Save all , Yes , Yes to all , No , No to all , Abort , Retry and Ignore The default button The return value is the button used for closing the dialog
    142. 142. When is a document modified? <ul><li>The user expects to see if a document is modified or not from the title of the window
    143. 143. By setting a window title with the sub-string “ [*] ”, the modified indication can be activated using setWindowModified . </li></ul>void MainWindow::updateWindowTitle() { setWindowTitle(tr(&quot;%1 [*] &quot;).arg(qApp->applicationName())); setWindowModified(m_modified); } This function is called from the constructor as well as from the documentModified slot
    144. 144. Application name <ul><li>When building the title, we used the QApplication::applicationName method
    145. 145. The QApplication object keeps track of the application's name, version, producer, etc.
    146. 146. This is used for window titles, etcetera </li></ul>a.setApplicationName(&quot;Text Editor&quot;); a.setApplicationVersion(&quot;0.1&quot;); a.setOrganizationName(&quot;ExampleSoft&quot;); a.setOrganizationDomain(&quot;example.com&quot;); a.setWindowIcon(QIcon(&quot;:/icons/new.png&quot;)); Application icon Producer name and domain Application name and version
    147. 147. Status update <ul><li>Now, we have a window with a working text editing widget
    148. 148. New windows can be created
    149. 149. Windows can be closed
    150. 150. The application can exit (i.e. close all windows)
    151. 151. We can keep track of document modifications
    152. 152. A window cannot be closed without accepting the loss of document modifications </li></ul>
    153. 153. Selecting a font <ul><li>The standard font of the text editor is very “plain”. To remedy, we will let the user pick the font
    154. 154. We add an action, add a View menu and put the action in the menu </li></ul>Text Name Icon Short-cut Tool-tip Select Font... actionSelectFont Select the display font New menus are always placed to the right, but they can be dragged in to place afterwards
    155. 155. Selecting a font <ul><li>In the slot, a new QFont value is requested using the QFontDialog::getFont method </li></ul>void MainWindow::on_actionSelectFont_triggered() { bool ok; QFont font = QFontDialog::getFont(&ok, ui->textEdit->font(), this); if(ok) ui->textEdit->setFont(font); } The boolean, ok , is used to determine if the user actually picked a font. This is because QFont values always are valid.
    156. 156. More on fonts <ul><li>Using the current implementation, each window pops up with the default font and the user has to pick a new font
    157. 157. The user expects settings to stick, i.e. use the last value when opening new windows </li></ul>
    158. 158. QSettings <ul><li>Settings are stored differently on all major platforms
    159. 159. By using a QSettings object, you get a cross platform interface for handing settings
    160. 160. Any QVariant can be stored – but think about readability for advanced users </li></ul>QSettings settings; myString = settings.value(&quot;key&quot;,&quot;default&quot;).toString(); settings.setValue(&quot;key&quot;, myString); settings.remove(&quot;key&quot;);
    161. 161. Back to the font <ul><li>Saving the font
    162. 162. Restoring the font </li></ul>void MainWindow::on_actionSelectFont_triggered() { bool ok; QFont font = QFontDialog::getFont(&ok, ui->textEdit->font(), this); if(ok) { QSettings settings; settings.setValue(&quot;viewFont&quot;, font); ui->textEdit->setFont(font); } } MainWindow::MainWindow(QWidget *parent) : ... { ... QSettings settings; ui->textEdit->setFont( settings.value(&quot;viewFont&quot;, QApplication::font()).value<QFont>()); ... Default value
    163. 163. Custom fonts!
    164. 164. Status update <ul><li>Now, we have a window with a working text editing widget
    165. 165. New windows can be created
    166. 166. Windows can be closed
    167. 167. The application can exit (i.e. close all windows)
    168. 168. We can keep track of document modifications
    169. 169. A window cannot be closed without accepting the loss of document modifications
    170. 170. User configurable fonts
    171. 171. Persistent user settings </li></ul>
    172. 172. The edit menu <ul><li>The actions cut, copy and paste are easy to add
    173. 173. The actions are added to both the tool bar and menu </li></ul>Right click on the tool bar to add separators Text Name Icon Short-cut Tool-tip Cut actionCut Ctrl+X Cut Copy actionCopy Ctrl+C Copy Paste actionPaste Ctrl+V Paste
    174. 174. The edit menu <ul><li>Slots for the new actions are implemented in the text editing widget
    175. 175. To avoid trying to copy in vain, let's add connections for enabling and disabling the actions depending on the selection </li></ul>connect(ui->actionCut, SIGNAL(triggered()), ui->textEdit, SLOT(cut())); connect(ui->actionCopy, SIGNAL(triggered()), ui->textEdit, SLOT(copy())); connect(ui->actionPaste, SIGNAL(triggered()), ui->textEdit, SLOT(paste())); connect(ui->textEdit, SIGNAL(copyAvailable(bool)), ui->actionCut, SLOT(setEnabled(bool))); connect(ui->textEdit, SIGNAL(copyAvailable(bool)), ui->actionCopy, SLOT(setEnabled(bool)));
    176. 176. Undoing <ul><li>Adding support for undo and redo is just as easy as for the clipboard operations </li></ul>Text Name Icon Short-cut Tool-tip Undo actionUndo Ctrl+Z Undo the last action Redo actionRedo Ctrl+Y Redo the last action connect(ui->actionUndo, SIGNAL(triggered()), ui->textEdit, SLOT(undo())); connect(ui->actionRedo, SIGNAL(triggered()), ui->textEdit, SLOT(redo())); connect(ui->textEdit, SIGNAL(undoAvailable(bool)), ui->actionUndo, SLOT(setEnabled(bool))); connect(ui->textEdit, SIGNAL(redoAvailable(bool)), ui->actionRedo, SLOT(setEnabled(bool)));
    177. 177. Status update <ul><li>Now, we have a window with a working text editing widget
    178. 178. New windows can be created
    179. 179. Windows can be closed
    180. 180. The application can exit (i.e. close all windows)
    181. 181. We can keep track of document modifications
    182. 182. A window cannot be closed without accepting the loss of document modifications
    183. 183. User configurable fonts
    184. 184. Persistent user settings
    185. 185. The expected clipboard actions: cut, copy and paste
    186. 186. Undo and redo </li></ul>
    187. 187. Unmodifying documents <ul><li>Until now, documents can be modified, but never unmodified
    188. 188. When is the modified flag cleared? </li><ul><li>In the constructor, i.e. new documents are not modified
    189. 189. When a document is loaded
    190. 190. When a document is saved </li></ul><li>This means that we must implement file operations </li></ul>
    191. 191. Interfacing files <ul><li>Qt file handing is too large a subject to cover here!
    192. 192. Loading
    193. 193. Saving </li></ul>QFile file(m_fileName); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) qFatal(&quot;Error opening file for writing&quot;); QTextStream out(&file); out << textString; QFile file(m_fileName); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) qFatal(&quot;Error opening file for reading&quot;); QTextStream in(&file); in >> textString;
    194. 194. The document file name <ul><li>If order to implement file operations, each document window must have a file name
    195. 195. As a start, it is set in the constructor </li></ul>MainWindow::MainWindow( const QString &fileName , QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_modified(false), m_fileName(fileName) { ... if(!m_fileName.isNull()) loadFile(); updateWindowTitle(); } The name can be QString() , i.e. null, as new, unnamed documents needs this
    196. 196. Updating the window title <ul><li>The window title must reflect the filename
    197. 197. Results in: </li><ul><li>untitled* - Text Editor
    198. 198. testing.txt - Text Editor </li></ul></ul>void MainWindow::updateWindowTitle() { setWindowTitle(tr(&quot;%1[*] - %2&quot;) .arg(m_fileName.isNull()?&quot;untitled&quot;:QFileInfo(m_fileName).fileName()) .arg(QApplication::applicationName())); setWindowModified(m_modified); } Extracts the file name part of a file name with a path
    199. 199. Loading documents <ul><li>Documents are loaded from the loadFile member function
    200. 200. It attempts to load the current file
    201. 201. If it fails, it sets the current filename to null </li></ul>void MainWindow::loadFile() { QFile file(m_fileName); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, QApplication::applicationName(), tr(&quot;Could not open file %1.n%2&quot;) .arg(QFileInfo(m_fileName).fileName()) .arg(file.errorString())); m_fileName = QString(); } else { QTextStream in(&file); ui->textEdit->setText(in.readAll()); } m_modified = false; updateWindowTitle(); }
    202. 202. Loading documents <ul><li>Documents are loaded from the loadFile member function
    203. 203. It attempts to load the current file
    204. 204. If it fails, it sets the current filename to null </li></ul>void MainWindow::loadFile() { QFile file(m_fileName); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, QApplication::applicationName(), tr(&quot;Could not open file %1.n%2&quot;) .arg(QFileInfo(m_fileName).fileName()) .arg(file.errorString())); m_fileName = QString(); } else { QTextStream in(&file); ui->textEdit->setText(in.readAll()); } m_modified = false; updateWindowTitle(); }
    205. 205. Loading documents <ul><li>Documents are loaded from the loadFile member function
    206. 206. It attempts to load the current file
    207. 207. If it fails, it sets the current filename to null </li></ul>void MainWindow::loadFile() { QFile file(m_fileName); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, QApplication::applicationName(), tr(&quot;Could not open file %1.n%2&quot;) .arg(QFileInfo(m_fileName).fileName()) .arg(file.errorString())); m_fileName = QString(); } else { QTextStream in(&file); ui->textEdit->setText(in.readAll()); } m_modified = false; updateWindowTitle(); }
    208. 208. Loading documents <ul><li>Documents are loaded from the loadFile member function
    209. 209. It attempts to load the current file
    210. 210. If it fails, it sets the current filename to null </li></ul>void MainWindow::loadFile() { QFile file(m_fileName); if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, QApplication::applicationName(), tr(&quot;Could not open file %1.n%2&quot;) .arg(QFileInfo(m_fileName).fileName()) .arg(file.errorString())); m_fileName = QString(); } else { QTextStream in(&file); ui->textEdit->setText(in.readAll()); } m_modified = false; updateWindowTitle(); }
    211. 211. Opening documents <ul><li>Now, we can load files on start-up </li></ul>int main(int argc, char *argv[]) { QApplication a(argc, argv); ... MainWindow *w; if(a.arguments().length()>1) w = new MainWindow(a.arguments().last()); else w = new MainWindow(); w->show(); return a.exec(); } You can specify arguments in the Run Settings, under the project tab in QtCreator
    212. 212. Adding file actions <ul><li>Actions to let the user open and save documents
    213. 213. The actions are added to the File menu and tool bar </li></ul>Text Name Icon Short-cut Tool-tip Open... actionOpen Ctrl+O Open a document Save actionSave Ctrl+S Save the current document Save As... actionSaveAs Ctrl+Shift+S Save current document as
    214. 214. Opening documents <ul><li>Asking for file names, we use the QFileDialog::getOpen / SaveFileName methods </li></ul>QFileDialog::getOpenFileName(this, &quot;Open document&quot;, QDir::currentPath(), &quot;Text documents (*.txt)&quot;); Parent window Dialog title Initial directory File type filter File type filters can contain several file extensions: &quot;Document (*.txt *.rtf *.doc)&quot; But also several document types: &quot;Document (*.txt);;Images (*.png)&quot;
    215. 215. Opening documents void MainWindow::on_actionOpen_triggered() { QString fileName = QFileDialog::getOpenFileName(this, &quot;Open document&quot;, QDir::currentPath(), &quot;Text documents (*.txt)&quot;); if(!fileName.isNull()) { MainWindow *w = new MainWindow(fileName); w->show(); } } <ul><li>Putting all together opens documents </li></ul>
    216. 216. Opening documents <ul><li>We can avoid opening a new window if the current one is unmodified and without file name </li></ul>void MainWindow::on_actionOpen_triggered() { QString fileName = QFileDialog::getOpenFileName(...); if(!fileName.isNull()) { if(!m_modified && m_fileName.isNull()) { m_fileName = fileName; loadFile(); } else { MainWindow *w = new MainWindow(fileName); w->show(); } } }
    217. 217. Saving documents <ul><li>Saving documents is slightly more complicated than loading </li><ul><li>Save without a name leads to Save As
    218. 218. Save As sets a name and attempts to save
    219. 219. Save is one of the options when a modified document is closed
    220. 220. Save As can be canceled
    221. 221. Saving can fail </li></ul></ul>
    222. 222. Saving documents bool MainWindow::saveFile() { if(m_fileName.isNull()) return saveFileAs(); QFile file(m_fileName); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(...); m_fileName = QString(); updateWindowTitle(); return false; } QTextStream out(&file); out << ui->textEdit->toPlainText(); m_modified = false; updateWindowTitle(); return true; } If the name is null, we need to save as Save the document If the file cannot be opened for writing, we display a warning and set the file name to null Update the modified flag and title Return true on success
    223. 223. Saving documents bool MainWindow::saveFileAs() { QString fileName = QFileDialog::getSaveFileName(...); if(!fileName.isNull()) { m_fileName = fileName; return saveFile(); } return false; } Ask the user for a file name If a name is given, attempt to save If no name is given, the save is a failure The method saveFileAs never calls saveFile unlese !fileName.isNull() thus there is no risk for infinite recursion
    224. 224. Saving documents <ul><li>As save and save as not are automatically connected slots, they need to be connected to the corresponding actions in the constructor </li></ul>connect(ui->actionSave, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui->actionSaveAs, SIGNAL(triggered()), this, SLOT(saveFileAs()));
    225. 225. Saving documents <ul><li>The final piece of the puzzle is the close event </li></ul>saved? Y Do not close Close
    226. 226. Saving documents void MainWindow::closeEvent(QCloseEvent *e) { if(m_modified) { switch(QMessageBox::warning(this, &quot;Document Modified&quot;, &quot;The document has ...&quot;, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel)) { case QMessageBox::Yes: if(saveFile()) e->accept(); else e->ignore(); break; case QMessageBox::No: e->accept(); break; case QMessageBox::Cancel: e->ignore(); break; } } else { e->accept(); } } The user wants to save The user do not want to save Cancel the closing Close unmodified documents Depending on the save, close or ignore
    227. 227. Status update <ul><li>Now, we have a window with a working text editing widget
    228. 228. New windows can be created
    229. 229. Windows can be closed
    230. 230. The application can exit (i.e. close all windows)
    231. 231. We can keep track of document modifications
    232. 232. A window cannot be closed without accepting the loss of document modifications
    233. 233. User configurable fonts
    234. 234. Persistent user settings
    235. 235. The expected clipboard actions: cut, copy and paste
    236. 236. Undo and redo
    237. 237. Can load documents
    238. 238. Can save documents </li></ul>
    239. 239. Thank you for your attention! [email_address]
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×