Qt/Qml Essentials Training
5-day session

 
Overview
Understanding fundamental and advance topics in Qt Programming
Understanding signals and slots concept
Understanding Widget
Understanding QPainter and 2D painting
Understanding QML/QtQuick
Duration
Five days - 40 hours (8 hours a day)
50% of lecture, 50% of practical labs
Trainer

Audience
Professional embedded Software developers
Professional GUI developers
Prerequisite
Knowledge of C++ programming
Qt uses Template level advance C++ as language. Prior knowledge to C++
is required.
Advance Cpp training agenda is available at
http://www.minhinc.com/training/cpp/advance-cpp-slides.php

Pdf document can be downloaded from
http://www.minhinc.com/training/advance-cpp-slides.pdf

Knowledge of Design Patterns Concepts
Qt uses GOF desing patterns in co-relating c++ classes.
Get slides at
http://www.minhinc.com/training/dp/advance-dp-slides.php

Knowledge of GUI and other concepts
Qt is used for GUI development and many other technologies including Networks,
operating systems, Database, scripting. Basic knowledge of these domains are
required as per the Qt is developed for the particular domain.

Setup
Ubuntu 16/17 LTS, Qt 5.9/5.10
© www.minhinc.com
p1
Lecture
Lecture session will be course content presentation through the trainer.
Any source code example related to the topic will be demonstrated, it would
include executing the binaries.
Complete lecture material can be downloaded from
http://www.minhinc.com/training/advance-qt-slides.pdf
Labs
Labs session would be completely hands on session where each example (with
example data and execution instruction) would be provided to the students. Students
can verify their results with the results provided in the material.
Day 1 Morning

© www.MinhInc.com
p2
Day 1 Afternoon

     Lab
© www.MinhInc.com
p3
Day 2 Morning

Day 2 Afternoon

     Lab
© www.MinhInc.com
p4
Day 3 Morning

Day 3 Afternoon

     Lab
© www.MinhInc.com
p5
Day 4 Morning

Day 4 Afternoon

     Lab
© www.MinhInc.com
p6
Day 5 Morning

Day 5 Afternoon

     Lab
© www.MinhInc.com
p7
 
Day 1 Morning
  1. Introduction
Abstract:It describes X11 gui fundamentals, as how a basic window is created in client server model of X11. This section also describes the flow of hardware event generation to event dispatching to app event queue. It mentions role of X11 server and Window manager entities on Server side. On client side how a event callback function is registered (against a window) with the X11 server and Window manager then how events generated on window are routed to registered callback function of application. Events are further processed through event loop processing manner quite different from sequential processing of non gui application. This section also lists the various Qt classes against each section in GUI programming.

Window registration and creation.

Display *dis;
int screen;
Window win;
GC gc;
void init_x() {
/* get the colors black and white (see section for details) */
 unsigned long black,white;
/* use the information from the environment variable DISPLAY to create the X connection:*/
 dis=XOpenDisplay((char *)0);
 screen=DefaultScreen(dis);
 black=BlackPixel(dis,screen),/* get color black */
 white=WhitePixel(dis, screen);  /* get color white */
/* once the display is initialized, create the window. This window will be have be 200 pixels across and 300 down. It will have the foreground white and background black */
 win=XCreateSimpleWindow(dis,DefaultRootWindow(dis),0,0,200, 300, 5, white, black);
/* here is where some properties of the window can be set. The third and fourth items indicate the name which appears at the top of the window and the name of the minimized window respectively. */
 XSetStandardProperties(dis,win,"My Window","HI!",None,NULL,0,NULL);
/* this routine determines which types of input are allowed in the input.  see the appropriate section for details... */
 XSelectInput(dis, win, ExposureMask|ButtonPressMask|KeyPressMask);
/* create the Graphics Context */
 gc=XCreateGC(dis, win, 0,0);
/* here is another routine to set the foreground and background colors _currently_ in use in the window. */
 XSetBackground(dis,gc,white);
 XSetForeground(dis,gc,black);
/* clear the window and bring it on top of the other windows */
 XClearWindow(dis, win);
 XMapRaised(dis, win);
}
void close_x() {
/* it is good programming practice to return system resources to the system... */
 XFreeGC(dis, gc);
 XDestroyWindow(dis,win);
 XCloseDisplay(dis);
 exit(1);
}

Event Callback
© www.minhinc.com
p8

Message Loop

- Message loop
  1. setting up the input masks
  2. creating an instance of the XEvent
  3. checking for events
  4. handling events.

XEvent event;/* the XEvent declaration !!! */
KeySym key;/* a dealie-bob to handle KeyPress Events */
char text[255];/* a char buffer for KeyPress Events */
/* look for events forever... */
while(1) {
 /* get the next event and stuff it into our event variable.  Note:  only events we set the mask for are detected! */
 XNextEvent(dis, &event);
 if (event.type==Expose && event.xexpose.count==0) {
 /* the window was exposed redraw it! */
  redraw();
 }
 if (event.type==KeyPress && XLookupString(&event.xkey,text,255,&key,0)==1) {
 /* use the XLookupString routine to convert the invent KeyPress data into regular text.  Weird but necessary...  */
  if (text[0]=='q') {
   close_x();
  }
  printf("You pressed the %c key!",text[0]);
 }
 if (event.type==ButtonPress) {
  /* tell where the mouse Button was Pressed */
  printf("You pressed a button at (%i,%i)", event.xbutton.x,event.xbutton.y);
 }
}

© www.minhinc.com
p9
- Event callback handler.
 i- Registering window callback function with the Window Manager.
   Qt Class - QWidget
 ii- Initializing Thread Event loop.
   Qt class - QCoreApplication
 iii- Creating window.
   Qt class - QWidget
 iv-  Generate the event, Hardware event, synthetic events
   Qt class - QEvent
 v- Handling events specific to the window in event callback funciton.
   Qt class - QWidget


QObject  - Event mechanism, signal-slot, timer, Thread

  / \
   -
   |
QCoreApplication - Event loop for console Qt application
                   Network event, Timer event, Non GUI etc.
                   exec() - starts queue
                   quit() - ends queue, returns
  / \
   -
   |
QGuiApplication - Event loop, communicates with Window Manager
                                          Provides session
  / \
   -
   |
QApplication - Event loop for GUI events

© www.minhinc.com
p10
Single Instance of Q[Core|Gui]Application

Day 1 Morning
  1. Introduction
Abstract:This section lists various licensing policies supported by Qt. GPL is completely free where as LGPL is less free to Commeriacial which is completely charged.

Meet Qt
Qt Development Frameworks founded in 1994
Trolltech acquired by Nokia in 2008
Digia tool control of Qt in 2012
Qt Company formed in 2013
80 employees worldwide
Trusted by over 6,500 companies worldwide
8 companies out of 10 top companies uses Qt
Qt: a coss-platform application and UI framework
For desktop, mobile and embedded development
Used by more than 350,000 commercial and open source developers
Backed by Qt consulting, support and training


                  Licensing Options
License     Cost     Runtime Support  Prop.Apps. Changes
Commercial  Charged  Yes     Included Yes        Closed
LGPL        Free     No      Add-On   Yes        Contribute
GPL         Free     No      Add-On   No         Contribute

* Cost: License fee charged (Charged | Free)
* Runtime: Charge for Runtimes (Yes | No)
* Support: (Included | Add-On)
* Prop.Apps: Can create proprietary applications
* Yes: In accordance with the license terms
* No: Source code must be made available
* Changes: Must provide source code changes to Qt
* Closed - No source code must be disclosed
* Contribute: Source code must be provided

GPL
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
© www.minhinc.com
p11
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

LGPL
a)If a program uses LGPL libraries then source code is not required to be given to user when used commercially.
b)If LGPL library is integrated (statically) or program is derived from then LGPL or LGPL library is modified then user source code must be provided when requested through the end user.

Qt Modules

Day 1 Morning
  1. Introduction
Abstract: Qt has meta object system which creates extra information for the classes dervied from QObject and has Q_OBJECT MACRO in class private area. Extra information is stored in spearate moc_<classname> file  which extends Q_OBJECT class to have meta information in it.

* QObject is the heart of Qt's object model
* It is base class of all qt classes
* Based on parent-child relationship
* Adds features to C++, like ...
  - Signals and slots
  - Properties
  - Event handling
  - Memory Management
  - ...
* Some features are standard C++
* Some use Qt's meta-object system
* QObject has no visual representation

© www.minhinc.com
p12

Qt's meta-object system provides the signals and slots mechanism for inter-object communication, run-time type information, and the dynamic property system.
The meta-object system is based on three things:
 1. The QObject class
 2. The Q_OBJECT macro inside the private section of the class
 3. The Meta-Object Compiler (moc) extends class with meta object information

Extra information pushed by moc compiler are
 * QObject::metaObject()
 * QMetaObject::className()
 * QObject::inherits()
 * QObject::tr() and QObject::trUtf8() translate strings for internationalization.
 * QObject::setProperty() and QObject::property() dynamically set and get properties by name.
 * QMetaObject::newInstance() constructs a new instance of the class.

MOC compiler
C++ code in Qt contains few QT specific tags and these tags are first parsed through MOC (Meta object compiler) generating final C++ code for g++ compiler.
struct myobject:QObject{
private:
Q_OBJECT  // for moc compiler, required for signal/slot support
public slots:        // moc term
void myslot();
signals:            // moc term
void mysignal();
};

Sending signal
emit mysignal(); // emit is moc keyword

moc creates meta-object information
moc -o moc_myclass.cpp myclass.h
c++ -c myclass.cpp; c++ -c moc_myclass.cpp
c++ -o myapp moc_myclass.o myclass.o

Day 1 Morning
  1. Introduction

Creator
© www.minhinc.com
p13

Debugger

<<main.cpp>>
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[]){
QApplication app(argc,argv);
QPushButton *button=new QPushButton("Hello World");
button->show();
return app.exec();
}

Day 1 Morning
  1. Introduction
Abstract: qmake application keeps information about all qt library and other dependent library an application would need. qmake typically reads .pro file in the current directry and generate Makefile.

Qt Build system has project file. Project file contains all build related information.
qmake is an application which converts project file to unix Makefile.
Supports MOC, UI and QRC file.
qmake typically contains various keyword (in capital alphabets) which is required to get assigned for a particular result
QT - Qt modules/libraries required
CONFIG - config parameters i.e console for console output
win32 for win32 specific settings
SOURCES, HEADERS for source and header files
RESOURCES for qrc file
LIBS for linking to external library specially non Qt

To create a project file
© www.minhinc.com
p14
$qmake -project QT+=core widgets // to create .pro file
$qmake // creates Makefile

To build
$make

<<helloworld.pro>>
QT += core widgets
TARGET = helloworld
TEMPLATE = app
SOURCES + = main.cpp
HEADERS +=
© www.minhinc.com
p15
 
Day 1 Morning
  2. Qt Core

- String handling classes:
 * Unicode-aware string and character classes.
 * Regular expression engine for pattern matching.

- Strings can be created in a number of ways:
 * From a number using a static function:
   QString n = QString::number(1234);
 * From a char pointer using the static functions:
   QString text = QString::fromLatin1("Hello Qt");
   QString text = QString::fromUtf8(inputText);
   QString text = QString::fromLocal8Bit(cmdLineInput);

- Other properties
 * simplified() // removes duplicate whitespace
 * left(), mid(), right() // part of a string
 * leftJustified(), rightJustified() // padded version
   QString s = "apple";
   QString t = s.leftJustified(8, '.'); // t == "apple..."

- Data can be extracted from strings.
   * Numbers:
   int value = QString::toInt();
   float value = QString::toFloat();
   * Strings:
   QString text = ...;
   QByteArray bytes = text.toLatin1();
   QByteArray bytes = text.toUtf8();
   QByteArray bytes = text.toLocal8Bit();

- Obtaining raw character data from a QByteArray:
  char *str = bytes.data();
  const char *str = bytes.constData();

Day 1 Morning
  2. Qt Core

Item Container Classes
  -Template-based classes can be used to store items of a specified type. i.e. for resizable array of QStrings, it is QVector<QString>.

General purpose template-based container classes
  - Sequential containers
  - Associative containers

Sequential container
QList<QString> Sequence Container. QList is implemented using an array ensuring that index-based access is very fast.
QLinkedList<T> Unlike QList it uses iterator rather then index to access items. Inserting items in middle is easier.
QVector<T> Last in, first out (LIFO).
Qstack<T> Adaptar class and subclass of QVector. push(), pop() and top().
QQueue<T> Adapter class and subclass of QList. First in First out. enqueue(), dequeue() and head().
© www.minhinc.com
p16
Associative containers
QMap<Key, T> maps keys of type Key to values of type T. Stores data in key order.
QMultiMap<Key, T> QMap where key can be associated with multiple maps.
QHash<Key, T> Similar to QMap but stores its data in a arbitrary order. Significantly faster lookup.
QMultiHash<Key, T> Subclass of QHash provides interface for multi-valued hashes.

Qt's Item Containers compared to STL
 - Lighter, safer, and easier to use than STL containers
 - If you prefer STL, feel free to continue using it.
 - Methods exist that convert between Qt and STL e.g. you need to pass std::list to a Qt method

Sequential Container...
QList
QList<QString> list;
list << "one" << "two" << "three";
QString item1 = list[1]; // "two"
for(int i=0; i<list.count(); i++) {
const QString &item2 = list.at(i);
}
int index = list.indexOf("two"); // returns 1

Associative Container...
QMap
QMap<QString, int> map;
map["Norway"] = 5; map["Italy"] = 48;
int value = map["France"]; // inserts key if not exists
if(map.contains("Norway")) {
int value2 = map.value("Norway"); // recommended lookup
}

- Constraints
 - Values types in containers must be assignable types. Constructor,  Copy constructor and assignment operator must defined. Missing this compiler any way generates synthesised in order to have shallow copy.
 - In QMap<Key, T>, Key must support operator<.
 - All value type must also supoort operator<< and operator>> inroder to be read or written using QDataStream.

class Movie{
public:
Movie(){}
Movie(const Movie& other);
operaotr=(const Movie& other);
private:
int id;
QString title;
QDate releaseDate;
};
QDataStream &operator<<(QDataStream &out, const Movie& movie){
out << (qint32)movie.id << movie.title << movie.releaseDate;
return out;
}
QDataStream &operator>>(QDataStream &in, Movie &movie){
qint32 id;
QDate date;
 in>>id>>movie.title >> date;
movie.id=(int)id;
movie.releaseDate = date;
return in;
}

Iterators
 * Java-style iterators simple and easy to use.
 * QListIterator<...> for read
 * QMutableListIterator<...> for read-write

 * STL-style iterators slightly more efficient
 * QList::const_iterator for read
 * QList::iterator for read-write
 * Same works for QSet, QMap, QHash, ...

Java-style
© www.minhinc.com
p17
Modifying During Iteration
  * Use mutable versions of the iterators
  * e.g. QMutableListIterator.

QList<int> list;
list << 1 << 2 << 3 << 4;
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() % 2 != 0)
i.remove();
}

STL-style Iterators
QList<QString> list;
list << "A" << "B" << "C";
QList<QString>::iterator i;
Forward mutable iteration
for (i = list.begin(); i != list.end(); ++i) {
*i = (*i).toLower();
}

* Backward mutable iteration
i = list.end();
while (i != list.begin()) {
--i;
*i = (*i).toLower();
}

* QList<QString>::const_iterator for read-only The foreach Keyword
 - Modifying the container while iterating
 - results in container being copied
 - iteration continues in unmodified version
 - Not possible to modify item
 - iterator variable is a const reference.
 - It is a macro, feels like a keyword
foreach ( variable, container ) statement
foreach (QString str, list) {
if (str.isEmpty())
break;
qDebug() << str;
}

Algorithms
 * STL-style iterators are compatible with the STL algorithms
 * Defined in the STL <algorithm> header
 * Qt has own algorithms
 * Defined in <QtAlgorithms> header
 * If STL is available on all your supported platforms you can choose to use the STL algorithms
 * The collection is much larger than the one in Qt.

 * qSort(begin, end) sort items in range
 * qFind(begin, end, value) find value
 * qEqual(begin1, end1, begin2) checks two ranges
 * qCopy(begin1, end1, begin2) from one range to another
 * qCount(begin, end, value, n) occurrences of value in range Counting 1's in list
QList<int> list;
list << 1 << 2 << 3 << 1;
int count = 0;
qCount(list, 1, count); // count the 1's
qDebug() << count; // 2 (means 2 times 1)
 * For parallel (ie. multi-threaded) algorithms
Implicitly Sharing and Containers
Implicit Sharing
If an object is copied, then its data is copied only when the data of one of the objects is changed
 * Shared class has a pointer to shared data block
 * Shared data block = reference counter and actual data
 * Assignment is a shallow copy
 * Changing results into deep copy (detach)
QList<int> l1, l2; l1 << 1 << 2;
l2 = l1; // shallow-copy: l2 shares date with l1
l2 << 3; // deep-copy: change triggers detach from l1

© www.minhinc.com
p18
Important to remember when inserting items into a container, or when returning a container.

Day 1 Morning
  2. Qt Core

* QVarLengthArray<T, Prealloc> provides a low-level variable-length array.
  Used instead of QVector in places where speed is particularly important.
* QCache<Key, T> provides a cache to store objects of a certain type T
  associated with keys of type Key.
* QContiguousCache<T> provides an efficient way of caching data that is
  typically accessed in a contiguous way.
* QPair<T1, T2> stores a pair of elements.

* QVarLengthArray<T, Prealloc> provides a low-level variable-length array.
  Used instead of QVector in places where speed is particularly important.
* QCache<Key, T> provides a cache to store objects of a certain type T
  associated with keys of type Key.
* QContiguousCache<T> provides an efficient way of caching data that is
  typically accessed in a contiguous way.
* QPair<T1, T2> stores a pair of elements.

Non-template types are QBitArray, QByteArray, QString, and QStringList.

Day 1 Morning
  2. Qt Core

- Working With Files
 - For portable file access do not use the native functions like open() or CreateFile(), but Qt classes instead.

 -File Handling
  * QFile
  * Interface for reading from and writing to files
  * Inherits QIODevice (base interface class of all I/O devices)

 - QTextStream
  * Interface for reading and writing text

 - QDataStream
  * Serialization of binary data

- Additional
  * QFileInfo - System-independent file information
  * QDir - Access to directory structures and their contents

File Convenient Methods
  * Media methods: load(fileName), save(fileName)
  * for QPixmap, QImage, QPicture, QIcon
  * QFileDialog
  * QFileDialog::getExistingDirectory()
  * QFileDialog::getOpenFileName()
  * QFileDialog::getSaveFileName()
  * QDesktopServices::storageLocation(type)
  * returns default system directory where files of type belong

© www.minhinc.com
p19
File operations
  * QFile::exists(fileName)
  * QFile::rename(oldName, newName)
  * QFile::copy(oldName, newName)
  * QFile::remove(fileName)
  * Directory Information
  * QDir::tempPath()
  * QDir::home()
  * Qdir::drives()

Variants
  * QVariant
  * Acts like a union for the most common Qt data types
  * Resides in QtCore (can't know outside types)
  * For QtCore types
QVariant variant(42);
int value = variant.toInt(); // read back
qDebug() << variant.typeName(); // int

  * For none QtCore types
variant.setValue(QColor(Qt::red));
QColor color = variant.value<QColor>(); // read back
qDebug() << variant.typeName(); // QColor

QVariant and Custom Types
 - Custom Type
class Contact {
public:
void setName(const QString &name);
QString name() const;
  ...
};
// make Contact known to meta-type system
Q_DECLARE_METATYPE(Contact);

 - Usage with QVariant
Contact c; c.setName("Peter");
QVariant variant = QVariant::fromValue(c);
qDebug() << variant.typeName(); // Contact
Contact c2 = variant.value<Contact>();
qDebug() << c2.name(); // "Peter

EXAMPLE:
<QT += core TARGET = coreclass TEMPLATE = app SOURCES += coreclass.cpp>
<coreclass.cpp>
#include <QCoreApplication> #include <QtAlgorithms> #include <QFile> #include <QList> #include <QVector> #include <QTextStream> #include <QDataStream> #include <QColor> #include <QString> #include <QDebug> class Contact { QString _name; public: void setName(const QString &name){_name = name;} QString name() const{return _name;} }; Q_DECLARE_METATYPE(Contact); int main(int argc, char *argv[]) { QCoreApplication a(argc,argv); QFile tfile("textfile.txt"); QFile dfile("mydatafile.data"); QTextStream tstream; QDataStream dstream; if(tfile.open(QIODevice::WriteOnly)) { tstream.setDevice(&tfile);
}
if(dfile.open(QIODevice::WriteOnly)) {
 dstream.setDevice(&dfile);
}
QList<QString> slist;
slist<<"one"<<"two"<<"three";
QVector<QString> svec(3);
qCopy(slist.begin(),slist.end(),svec.begin());
for(QVector<QString>::iterator it=svec.begin();it!=svec.end();++it)
tstream<<*it;
dstream<<(QList<QString>)slist;
tfile.close();
dfile.close();
QVariant variant("42");
int value = variant.toInt(); // read back
qDebug() << value << variant.typeName(); // int
variant.setValue(QColor(Qt::red));
QColor color = variant.value<QColor>(); // read back
qDebug() << color.name()<< variant.typeName(); // QColor
// make Contact known to meta-type system
Contact c; c.setName("Peter");
QVariant variant1 = QVariant::fromValue(c);
qDebug() << variant1.typeName(); // Contact
Contact c2 = variant1.value<Contact>();
qDebug() << c2.name(); // "Peter"
return a.exec();
}
OUTPUT
$./coreclass
42 QString
"#ff0000" QColor
Contact
"Peter"

Day 1 Morning
  2. Qt Core

* To map a file into memory on Unix mmap system function is used.
 - On Windows with CreateFileMapping.
© www.minhinc.com
p20
 - Qt QFileDevice provides map() and unmap() that provide the ability to map files into memory.

QFile file("foo");
file.open(QFile::ReadOnly);
uchar *memory = file.map(0, file.size());
if (memory) {
   // have some fun with the data
file.unmap();
}
© www.minhinc.com
p21
 
Day 1 Morning
  3. Memory Management

QObjectis base class of all Qt classes which supports
- Signals and slots
- Dynamic Properties
- Event handling
- Memory Management
- Timer
- Thread
- Qt meta-object system

QObjecthas no visual representation

ObjectTree
- QObjects organize themselves in object trees
- Based on parent-child relationship

QObject(QObject*parent=0)
- Parent adds object to set of children
- Parent owns children
- Construction/Destruction
- Tree be constructured in any order
- Tree be destroyed in any order
- if object has parent: object first removed from parent
- if object has children: deletes each child first
- No object is deleted twice
Note:Parent-child relationship is NOT inheritance

Day 1 Morning
  3. Memory Management

*QObject follows heap and stack life cycle.
*Children destroyed by Parents at the time of their destruction.

OnHeap - Classes inheriting from QObject
QLabel*label = new QLabel("Some Text", parent);
- Parent takes ownership
- Copy is disabled

Onstack - All other classes
QStringListlist;
QColorcolor;
- Cheap to copy
- Exceptions:
© www.minhinc.com
p22
QFile, QApplication (inheriting QObject)
Usually allocated on the stack
Modal dialogs are often allocated on stack

-QPointer(Smart Pointer in Qt)
The QPointer class is a template class that provides guarded pointers to Qobject. A guarded pointer, QPointer<T>, behaves like a normal C++ pointer T * except that it is automatically set to 0 when the referenced object is destroyed (unlike normal C++ pointers, which become "dangling pointers" in such cases).
QPointer<QLabel>label = new QLabel;
label->setText("&Status:");
...
if (label)
label->show();

-QScopePointer(Auto Pointer in Qt)
voidmyFunction(bool useSubClass)
{
MyClass*p = useSubClass ? new MyClass() : new MySubClass;
QIODevice*device = handsOverOwnership();

if(m_value > 3) {
deletep;
deletedevice;
return;
}
try{
process(device);
}
catch(...) {
deletep;
deletedevice;
throw;
}
deletep;
deletedevice;
}

QSharedPointer
TheQSharedPointer class holds a strong reference to a shared pointer. The QSharedPointer is an automatic, shared pointer in C++. It behaves exactly like a normal pointer for normal purposes, including respect  for constness.
QSharedPointerwill delete the pointer it is holding when it goes out of scope, provided no other QSharedPointer objects are referencing it.
AQSharedPointer object can be created from a normal pointer, another SharedPointer object or by promoting a QWeakPointer object to a strong reference.

QWeakPointer
- The QWeakPointer class holds a weak reference to a shared pointer. The QWeakPointer is an automatic weak reference to a pointer in C++.
- It cannot be used to dereference the pointer directly, but it can be used to verify
if the pointer has been deleted or not in another context.
QWeakPointer objects can only be created by assignment from a QSharedPointer.

Day 1 Morning
  3. Memory Management

- Association
© www.minhinc.com
p23
When a class keeps pointers to other class, class is said to be associated. QWidget keeps pointers to QObject its parent class then QWidget is associated to its parent.

- Containment
When one Qt class contains other as member property.

-Aggregation
Other class object is instantiated externally and its life cycle is not dependent upon container.

-Composition
Other class object is instantiated internally and its life cycle is dependent upon container. QWindow has QMenuBar, QMenu, QToolBar created internally.

-Inheritance
When a Qt class inherit other class. Parent class properties and methods becomes visible to derived class depends upon parent class access controls and derivation type (public, protected, private). Class public is visible to external world.

- Polymorphism
Its a type of inheritance where compile time method invocation on base class pointer can be replaced to method invocation on derived class objects. This is possible with non static methods declared with virtual keyword.
classB{
public:
virtualfunc(){cout<<"B::func"<<endl;}
};
classD:class B {
public:
virtualfunc(){count<<"D::func"<<endl;}
}
voiddraw(B* b){
b->func();
}
B*b=new D;
draw(b);

Day 1 Morning
  3. Memory Management
© www.minhinc.com
p24
 
Day 1 Morning
  4. Event Management

Event Processing
 - Qt is an event driven UI toolkit
 - QApplication::exec() runs the event loop

1. Generate Events
 - By input devices: keyboard, mouse, etc.
 - By Qt itself (e.g. timers)
2 Queue Events
 - By event loop
3 Dispatch Events
 - By QApplication to receiver: QObject
 - Key events sent to widget with focus
 - Mouse events sent to widget under cursor
4 Handle Events
 - By QObject event handler methods

------------------        ------------       ---------------------------------
|hardware signals| -----> | X Server | ----> | Application thread            |
------------------        ------------       | Event queue with display open |
                                             ---------------------------------
                                                            |
                                                            | exec()
                                                            v
                                              ------------------------------
                                              | Window handling the event  |
                                              ------------------------------
                                                            |
                                                            V
                                                           ---
                                  ---------    Yes      /       \
                                  |process|    <-----  /  Pass   \
                                  ---------            \ through /
                                                        \event  /
                                                         \filter/
                                                           ---
                                                            | NO
                                                            v
                                                      ------------
                                                      | reject   |
                                                      ------------

- Event Handling through callback and polymorphism
 QObject::event(QEvent *event)
- Handles all event for this object Qt's Widget Model - QWidget
© www.minhinc.com
p25

Derived from QObject
 - Adds visual representation

Base of user interface objects
 - Receives events e.g. mouse, keyboard events

Paints itself on screen
 - Using styles

* Specialized event handlers
QWidget::mousePressEvent(QMouseEvent*) for mouse click
QWidget::keyPressEvent(QKeyEvent)* for key presses
QWidget::actionEvent(QActionEvent * event)
QWidget::changeEvent(QEvent * event)
QWidget::closeEvent(QCloseEvent * event)
QWidget::contextMenuEvent(QContextMenuEvent * event)
QWidget::dragEnterEvent(QDragEnterEvent * event)
QWidget::dragLeaveEvent(QDragLeaveEvent * event)
QWidget::dragMoveEvent(QDragMoveEvent * event)
QWidget::dropEvent(QDropEvent * event)
QWidget::enterEvent(QEvent * event)
QWidget::focusInEvent(QFocusEvent * event)
QWidget::focusOutEvent(QFocusEvent * event)
QWidget::hideEvent(QHideEvent * event)
QWidget::inputMethodEvent(QInputMethodEvent * event)
QWidget::keyReleaseEvent(QKeyEvent * event)
QWidget::leaveEvent(QEvent * event)
QWidget::mouseDoubleClickEvent(QMouseEvent * event)
QWidget::mouseMoveEvent(QMouseEvent * event)
QWidget::mouseReleaseEvent(QMouseEvent * event)
QWidget::moveEvent(QMoveEvent * event)
QWidget::paintEvent(QPaintEvent * event)
QWidget::resizeEvent(QResizeEvent * event)
QWidget::showEvent(QShowEvent * event)
QWidget::tabletEvent(QTabletEvent * event)
QWidget::wheelEvent(QWheelEvent * event)

For all events
virtual bool event(QEvent * event)
Accepting an Event
 - event->accept() / event->ignore()
- Accepts or ignores the event - Accepted is the default. Event propagation - Happens if event is ignored - Might be propagated to parent widget Example of Event Handling * QCloseEvent delivered to top level widgets (windows) * Accepting event allows window to close * Ignoring event keeps window open
void MyWidget::closeEvent(QCloseEvent *event) {
if (maybeSave()) {
writeSettings();
event->accept(); // close window
} else {
event->ignore(); // keep window
}
}

- Event handling through message map
Events and Signals
Signals and slots are used instead of events:
* To communicate between components.
* In cases where there is a well-defined sender and receiver.
© www.minhinc.com
p26
* For example: a button and a slot to handle clicks.
* For some events, there is no sender in Qt.
* For example: redraw, keyboard and mouse events.
* To describe high level logic and control flow. Developers can create custom events if they need to.


Variations of Signal&Slot Connections
Signal(s)                      Slot(s)
one                            many
Many                           one
one                            another signal

Signal to Signal connection
connect(bt, SIGNAL(clicked()), this, SIGNAL(oksignal()));
Making the Connection Rule for Signal & Slot Connection Can ignore arguments, but not create values from nothing
Signal                                          Slot
rangeChanged(int,int)                           setValue(int)
                                                setRange(int,int)
                                                updateUi()

valueChanged(int)                               setValue(int)
                                                UpdateUi()
                                x               setRange(int,int)
                                x               setValue(float)

textChanged(QString)            x               setValue(int)

Clicked()                                       updateUi()
                                x               setValue(int)

Day 1 Morning
  4. Event Management

Events have mainly two types
© www.minhinc.com
p27
a) User interface, ex, Keyboard, Mouse, Timer etc.. Processed through call backs, ex. paintEvent, processEvent etc.
b) Synthetic events

Synthetic Events
* When calling postEvent(), the event must be allocated using new, and must not be deallocated (Qt takes ownership).
* When calling sendEvent(), you must take care of deleting the instance afterwards (or allocate it on the stack).

* You can create your own events by inheriting QEvent, and using an integer between QEvent::User (1000) and QEvent::MaxUser (65535).
* The integer to use is best generated using the static method int QEvent::registerEventType(int hint = -1)
* Naturally, Qt does not understand user events. You must therefore handle user events in inherited classes implementing QObject::customEvent() to deal with your custom events.
* Alternatively, event filters can be used.

Delayed Invocation
* Sometimes, it is desirable to have some code invoked when the application is idle.
* One way to do this is to post custom QEvent and put your code in the QObject::customEvent() handler of the receiving object.
* Another way that is often easier and works when the code you want to invoke is available as a slot,

QMetaObject::invokeMethod() with the connection type
QueuedConnection can be used instead:
QMetaObject::invokeMethod(myobject, "doDelayedStuff", Qt::QueuedConnection);

Invokes doDelayedStuff() subroutine

Delayed Invocation
* A typical use of this is to make a delayed call from a constructor.
* This can be used to emit signals after the object has been created and connected.
* Another use is idle processing.

PingPong
<*.pro>
QT+=core TEMPLATE = app TARGET = pingpong SOURCES += pingpong.cpp
<main.cpp>
#include <QtCore> #include <QDebug> class PingEvent : public QEvent { public: PingEvent() : QEvent(QEvent::Type(QEvent::User)){} }; class PongEvent : public QEvent{ public: PongEvent() : QEvent(QEvent::Type(QEvent::User+1)){} }; class Pinger : public QState{ public: Pinger(QState *parent=0):QState(parent) {} protected: virtual void onEntry(QEvent *){ qDebug()<<"Pinger::onEntry"; machine()->postDelayedEvent(new PingEvent(),30000); } }; class Ponger : public QState{ public: Ponger(QState *parent=0):QState(parent) {} protected: virtual void onEntry(QEvent *){ qDebug()<<"Ponger::onEntry"; machine()->postDelayedEvent(new PongEvent(),30000); } }; class PingTransition : public QAbstractTransition { public: PingTransition() {} protected: virtual bool eventTest(QEvent *e) { qDebug()<<"PingTranstion::eventTest eventType :"<<e->type(); return (e->type() == QEvent::User); }
virtual void onTransition(QEvent *) {
qDebug()<<"PingTransition::onTransition";
}
};
class PongTransition : public QAbstractTransition{
public:
PongTransition() {}
protected:
virtual bool eventTest(QEvent *e) {
qDebug()<<"PingTranstion::eventTest eventType :"<<e->type();
return (e->type() == QEvent::User+1);
}
virtual void onTransition(QEvent *){
qDebug()<<"PongTransition::onTransition";
}
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QStateMachine machine;
Pinger *pinger = new Pinger();
pinger->setObjectName("pinger");
Ponger *ponger = new Ponger();
ponger->setObjectName("ponger");
QAbstractTransition *pingertranstion=new PingTransition();
pingertranstion->setTargetState(ponger);
pinger->addTransition(pingertranstion);

QAbstractTransition *pongertransition=new PongTransition();
pongertransition->setTargetState(pinger);
ponger->addTransition(pongertransition);

machine.addState(pinger);
machine.addState(ponger);
machine.setInitialState(pinger);
machine.start();
return app.exec();
}
OUTPUT
./pingpong
Pinger::onEntry
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(User)
PingTransition::onTransition
Ponger::onEntry
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(1001)
PongTransition::onTransition
Pinger::onEntry
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(None)
PingTranstion::eventTest eventType : QEvent::Type(User)
PingTransition::onTransition
Ponger::onEntry
PingTranstion::eventTest eventType : QEvent::Type(None)
^C

© www.minhinc.com
p28

 
Day 1 Morning
  4. Event Management

*QEventLoop - The QEventLoop class provides a means of entering and leaving an event loop.
*At any time, you can create a QEventLoop object and call exec() on it to start a local event loop. From within the event loop, calling exit() will force exec() to return.
*QEventDispatcher - The QAbstractEventDispatcher class provides an interface to manage Qt's event queue.
*An event dispatcher receives events from the window system and other sources. It then sends them to the QCoreApplication or QApplication instance for processing and delivery. QAbstractEventDispatcher provides fine-grained control over event delivery.

          |                |                                     QWidgets
          |                |                                   -------------
          |                |                        hardware   |::event() |
          |                |                        events +-->|::mousePressEvent()|
          |                |                               |   | .....             |
|event    |                |                               |   ---------------------
|arrival / \   checks for / \   send out                   |
|       /   \   priority /   \  event to  ------------     |
|      /event\ -------> /event\ --------> |checks for|     |
--->   \queue/          \queue/ target    |installed |-----+
        \   /            \   /  window    |filters   |  syn|ev   QObject
         \ /              \ /             ------------  the|ents-----------------
          |                |                            tic|--->|::customEvent()|
          |                |                               |    -----------------
          |                |                               |
          |                |                           sign|     QObject
          |                |                           als |     ----------
                                                           |---->| slots  |
                                                                 ----------

Day 1 Morning
  4. Event Management

Event Filters
 - The usual way to do this is to subclass each widget and implement the event.
 - The alternative is to install an event filter for each instance.

Event Filters
* Subclass from QObject (or any subclass of QObject), and reimplement the method:
bool QObject::eventFilter(QObject* receiver, QEvent* event);
                 --------------
                 |  Qobject   | virutal eventfilter(QObject *receiver, Qevent *e)
                 --------------
                       / \
© www.minhinc.com
p29
                        -
                        |
               ---------------------
               | EventFilterObject|virutal eventfilter(QObject *receiver, Qevent *e)
               ---------------------
* The first parameter is the object for whom the event was intended, and the second argument is the event itself.
* If this method returns true, then the event is considered "handled", otherwise it will be sent on to the next event filter, or the object itself, if no more event filters are installed.
* Install the event filter for an object by invoking the method installEventFilter(). As the argument, pass an instance of the class you have created in the previous step.

Event Filters
* Installing an event filter on the QApplication instance will install a global event filter.
* Event filters can be removed again by using the method
removeEventFilter(const QObject*)
* When multiple event filters are installed, the order they are called in is the reverse of the order in which they are installed, i.e., the most recent installed filter is the first one invoked.

<*.pro>
QT += core
<entity.h>
#ifndef ENTITY_H #define ENTITY_H #include <QEvent> #include <QDebug> class entity2; class event1:public QEvent { public: event1():QEvent(QEvent::Type(QEvent::User)){} }; class event2:public QEvent { public: event2():QEvent(QEvent::Type(QEvent::User+1)){} }; class entity1:public QObject { Q_OBJECT public: entity1(QObject *p=0); protected: void customEvent(QEvent *); public: void start(); void setpartner(entity2*); private: entity2 *ent; }; class entity2:public QObject { Q_OBJECT public: entity2(QObject *p=0); void setpartner(entity1* e); protected: void customEvent(QEvent *); private: entity1 *ent; }; class event1filter:public QObject { Q_OBJECT protected: bool eventFilter(QObject *obj, QEvent *event); }; class event2filter:public QObject { Q_OBJECT protected: bool eventFilter(QObject *obj, QEvent *event); }; #endif
<entity.cpp>
#include <QCoreApplication> #include "entity.h"
entity1::entity1(QObject *p):QObject(p) {
}
void entity1::start() {
qDebug()<<"entity1::start()";
QCoreApplication::instance()->postEvent(ent, new event1());
}
void entity1::customEvent(QEvent *e) {
qDebug()<<"entity1::customevent(), received event type->"<<e->type();
QCoreApplication::instance()->postEvent(ent, new event1());
QCoreApplication::instance()->postEvent(ent, new event2());
}
void entity1::setpartner(entity2 *part) {
ent=part;
}
entity2::entity2(QObject *p):QObject(p) {}
void entity2::customEvent(QEvent *e) {
qDebug()<<"entity2::customevent, received custom event id"<<e->type();
QCoreApplication::instance()->postEvent(ent, new event1());
QCoreApplication::instance()->postEvent(ent, new event2());
}
void entity2::setpartner(entity1 *part) {
ent=part;
}
bool event1filter::eventFilter(QObject *obj, QEvent *event) {
if(event->type() == QEvent::User)
return true;
else
return QObject::eventFilter(obj,event);
}
bool event2filter::eventFilter(QObject *obj, QEvent *event) {
if(event->type() == QEvent::User+1)
return true;
else
return QObject::eventFilter(obj, event);
}
<main.cpp>
#include <QCoreApplication> #include "entity.h" int main(int argc, char *argv[]) { QCoreApplication a(argc,argv); int r; entity1 *ent1=new entity1; entity2 *ent2=new entity2; event1filter *ent1filter=new event1filter; event2filter *ent2filter=new event2filter; ent1->setpartner(ent2); ent2->setpartner(ent1); ent1->installEventFilter(ent1filter); ent2->installEventFilter(ent2filter); ent1->start(); r=a.exec(); return r; }
OUTPUT
./entity12
entity1::start()
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)
entity1::customevent(), received event type-> QEvent::Type(1001)
entity2::customevent, received custom event id QEvent::Type(User)

© www.minhinc.com
p30
Day 1 Morning
  4. Event Management

There are mainly two types of timers.
QTimer  based
 Single Shot
 Periodic
Event based
 QObject::startTimer()
callback
 QOjbect::timerEvent()

signal-slottimer
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);

QTimer::singleShot(200, this, SLOT(updateCaption()));

<<eventtimer.cpp>>
class MyObject : public QObject{
Q_OBJECT
public:
MyObject(QObject *parent = 0);
protected:
void timerEvent(QTimerEvent *event);
};

MyObject::MyObject(QObject *parent):QObject(parent){
startTimer(50);     // 50-millisecond timer
startTimer(1000);   // 1-second timer
startTimer(60000);  // 1-minute timer
}
void MyObject::timerEvent(QTimerEvent *event){
    qDebug() << "Timer ID:" << event->timerId();
}

Day 1 Morning
  4. Event Management

Signals & Slots
 - Object Communication
 - Signal - emitted to notify other objects
 - Slot - method called in response to signal
 - Provides type-safe callbacks
 - After getting used to it, they are
 - easier to use than message maps,
 - more secure than callbacks,
 - more flexible than virtual methods
 - Fosters component-based programming
QMetaObject::Connection QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection) [static]
© www.minhinc.com
p31
QObject::disconnect(...);

<*.pro>
QT += widgets
<lwidget.h>
#include <QWidget> #include <QPushButton> #include <QLabel> #include <QColorDialog> #include <QColor> class lwidget:public QWidget { Q_OBJECT; public: lwidget(QWidget* parent=0); private slots: void on_buttonclicked(); void on_colorselected(QColor); private: QPushButton button; QLabel label1; QLabel label2; QColorDialog colord; };
<lwidget.cpp>
#include "lwidget.h" lwidget::lwidget(QWidget* parent):QWidget(parent), button("Select Color", this), label1("color is :", this),label2("", this) { label1.setGeometry(40,40,70,15); label2.setGeometry(140,40,100,15); button.setGeometry(40,100,100,35); connect(&button,SIGNAL(clicked()),this,SLOT(on_buttonclicked())); } void lwidget::on_buttonclicked() { colord.open(this,SLOT(on_colorselected(QColor))); } void lwidget::on_colorselected(QColor color) { label2.setText(color.name()); }
<sigslot.cpp>
#include <QApplication> #include "lwidget.h" int main(int argc, char *argv[]) { QApplication a(argc,argv); lwidget container; container.show(); return a.exec(); }
OUTPUT

Day 1 Morning
  4. Event Management

* The QSignalMapper class bundles signals from identifiable senders.
* This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object  that sent the signal.
* The class supports the mapping of particular strings or integers with  particular objects using setMapping(). The objects' signals can then be connected to the map() slot which will emit the mapped() signal with the string or integer associated with the original signalling object. Mappings can be removed later using removeMappings().
signalMapper = new QSignalMapper(this);
signalMapper->setMapping(taxFileButton, QString("taxfile.txt"));
signalMapper->setMapping(accountFileButton, QString("accountsfile.txt"));
signalMapper->setMapping(reportFileButton, QString("reportfile.txt"));

connect(taxFileButton, &QPushButton::clicked, signalMapper, &QSignalMapper::map);
connect(accountFileButton, &QPushButton::clicked, signalMapper, &QSignalMapper::map);
connect(reportFileButton, &QPushButton::clicked, signalMapper, &QSignalMapper::map);
Connect the mapped() signal to readFile() where a different file will be opened, depending on which push button is pressed.
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(readFile(QString)));
signalmapper
class ButtonWidget : public QWidget
{
Q_OBJECT
public:
ButtonWidget(QStringList texts, QWidget *parent = 0);
© www.minhinc.com
p32
signals:
void clicked(const QString &text);
private:
QSignalMapper *signalMapper;
};
ButtonWidget::ButtonWidget(QStringList texts, QWidget *parent) : QWidget(parent){
signalMapper = new QSignalMapper(this);
QGridLayout *gridLayout = new QGridLayout;
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]); gridLayout->addWidget(button, i / 3, i % 3);
}
connect(signalMapper, SIGNAL(mapped(QString)), this, SIGNAL(clicked(QString)));
setLayout(gridLayout);
}
© www.minhinc.com
p33
 
Day 2 Morning
  5. Widgets


* Derived from QObject
 - Adds visual representation
* Base of user interface objects
* Receives events
 - e.g. mouse, keyboard events
* Paints itself on screen
 - Using styles

Object Tree and QWidget
new QWidget(0)
 - Widget with no parent is window
QWidgets children
 - Displayed in parent coordinate system
 - Clipped by parents boundaries
QWidget parent
 - Propagates state changes
 - hides/shows them when it is hidden/shown itself
 - enables/disables them when it is enabled/disabled itself
Tristate mechanism
 - For hide/show and enable/disable, ensures that e.g. an explicitly hidden child is not shown when the parent is shown.

Widgets that contain other widgets
* Container Widgets
* Aggregates other child-widgets
* Use layouts for aggregation
* In this example: QHBoxLayout and
QVBoxLayout
* Note: Layouts are not widgets
* Layout Process
* Add widgets to layout
* Layouts may be nested
* Set layout on container widget

© www.minhinc.com
p34
Day 2 Morning
  5. Widgets

* Drivation
 * Drive from QWidget or children
 * Override QPaintEvent
-----------
| QWidget |
---------------------
|virtual QPaintEvent|
---------------------
        / \
         -
         |
---------------
|customwidget|
---------------
|QpaintEvent()|
----------------

* Containment
 * QWidget object contains other QWidgets
-----------               *  ---------
| QWidget |<>--------------->|QWidget|
---------------------        ---------
|virtual QPaintEvent|
---------------------

Day 2 Morning
  5. Widgets

The QPainter class performs low-level painting on widgets and other paint devices.
QPainter provides highly optimized functions to do most of the drawing GUI
programs require. It has three drawing capabilities.
a) Pen
b) Brush
c) Font

QPainter can operate on any object that inherits the QPaintDevice class.
QPainter generaly operates on virtual function paintEvent(...)  update() funciton in
QWidget calls repainting, calling paintEvent()

Pixmap being QPaintDevice, QPainter works on that.

© www.minhinc.com
p35
Day 2 Morning
  5. Widgets

The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a given platform.
QPaintEngine is created and owned by the QPaintDevice that created it.
QPainter provides abstract function for drawing to the user, internally it uses specific QPaintEngine, tied to a target PaintDevice, algorithms.
enum QPaintEngine::Type
Constant                     Value           Description
QPaintEngine::X11             0
QPaintEngine::Windows         1
QPaintEngine::MacPrinter      4
QPaintEngine::CoreGraphics    3    Mac OS X's Quartz2D (CoreGraphics)
QPaintEngine::QuickDraw       2    Mac OS X's QuickDraw
QPaintEngine::QWindowSystem   5    Qt for Embedded Linux
QPaintEngine::PostScript      6    (No longer supported)
QPaintEngine::OpenGL          7
QPaintEngine::Picture         8    QPicture format
QPaintEngine::SVG             9   Scalable Vector Graphics XML format
QPaintEngine::Raster          10
QPaintEngine::Direct3D        11  Windows only, Direct3D based engine
QPaintEngine::Pdf             12  Portable Document Format
QPaintEngine::OpenVG          13
QPaintEngine::User            50  First user type ID
QPaintEngine::MaxUser         100 Last user type ID
QPaintEngine::OpenGL2         14
QPaintEngine::PaintBuffer     15
QPaintEngine::Blitter         16

GUI events are placed to eventQueue and finally processed by paintEvent Functions.
QT += core

<main.cpp>
#include <QApplication> #include "widget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); int r; widget *w=new widget; w->show(); r=a.exec(); return r; }
<widget.h>
#include <QPainter> #include <QPaintEvent> #include <QRadialGradient> #include <QTimer> #include <QTransform> #include "widget.h" widget::widget(QWidget *parent):QWidget(parent){ QTimer *sunroundtimer=new QTimer(this); connect(sunroundtimer,SIGNAL(timeout()),this,SLOT(sunround())); sunroundangle=0; earthownaxisangle=0; earthroundangle=0; sunroundmarsangle=0; marsround1angle=0; marsround2angle=0; update(); sunroundtimer->start(500); } void widget::paintEvent(QPaintEvent *pe) { int side=qMin(width(),height()); QWidget::paintEvent(pe); QPainter *p=new QPainter(this); p->setViewport((width()-side)/2,(height()-side)/2,side,side); p->setWindow(-50,-50,100,100); QTransform transformearth; QTransform transformmoon; transformearth.rotate(sunroundangle); transformearth.translate(30,0); transformmoon.rotate(earthroundangle); transformmoon.translate(7.5,0); QRadialGradient rg(0,0,SUN,0,0); rg.setColorAt(0.0,Qt::white); rg.setColorAt(0.5,Qt::yellow); rg.setColorAt(1,Qt::red); p->setPen(Qt::NoPen); p->setBrush(rg); p->drawEllipse(-SUN,-SUN,SUN*2,SUN*2); p->save(); QRadialGradient erg(0,0,EARTH,-EARTH+1,0); erg.setColorAt(0.0,Qt::white); erg.setColorAt(0.7,Qt::blue); erg.setColorAt(1.0,Qt::black); p->setPen(Qt::NoPen); p->setBrush(erg); //p->rotate(sunroundangle); //p->translate(+30,0);
p->setWorldTransform(transformearth,true);
p->save();
p->rotate(earthownaxisangle);
p->drawEllipse(-EARTH,-EARTH,EARTH*2,EARTH*2);
p->restore();
p->setBrush(Qt::black);
//p->rotate(earthroundangle);
//p->translate(7.5,0);
p->setWorldTransform(transformmoon,true);
p->drawEllipse(-MOON,-MOON,MOON*2,MOON*2);
p->restore();


p->save();
QRadialGradient mrg(0,0,MARS,-MARS+1,0);
mrg.setColorAt(0.0,Qt::white);
mrg.setColorAt(1,Qt::red);
p->setPen(Qt::NoPen);
p->setBrush(mrg);
p->rotate(sunroundmarsangle);
p->translate(+40,-40);
p->drawEllipse(-MARS,-MARS,MARS*2,MARS*2);

p->save();
p->setBrush(Qt::green);
p->rotate(marsround1angle);
p->translate(4.5,0);
p->drawEllipse(-MARSMOON1,-MARSMOON1,MARSMOON1*2,MARSMOON1*2);
p->restore();

p->save();
p->setBrush(Qt::blue);
p->rotate(marsround2angle);
p->translate(5.5,0);
p->drawEllipse(-MARSMOON2,-MARSMOON2,MARSMOON2*2,MARSMOON2*2);
p->restore();
p->restore();
}

void widget::sunround() {
if((sunroundangle+=1)==360) sunroundangle=0;
if((earthownaxisangle+=90)==360) earthownaxisangle=0;
if((earthroundangle+=18)==360) earthroundangle=0;
if((sunroundmarsangle+=0.5)==360) sunroundmarsangle=0;
if((marsround1angle+=18)==360) marsround1angle=0;
if((marsround2angle+=36)==360) marsround2angle=0;
update();
}

<widget.h>
#ifndef WIDGET_H #define WIDGET_H class QPainter; class QPaintEvent; class QTimer; #include <QWidget> class widget: public QWidget { Q_OBJECT public: widget(QWidget *parent=0); protected: void paintEvent(QPaintEvent *); private slots: void sunround();
© www.minhinc.com
p36
private:
QTimer *sunroundtimer;
QTimer *earthownaxistimer;
QTimer *earthroundtimer;
float sunroundangle;
float earthownaxisangle;
float earthroundangle;
float sunroundmarsangle;
float marsround1angle;
float marsround2angle;
QPainter *p;
static const float SUN=8.0;
static const float EARTH=5.0;
static const float MARS=3.0;
static const float MOON=1.5;
static const float MARSMOON1=1;
static const float MARSMOON2=1.5;
};
#endif
OUTPUT

Day 2 Morning
  5. Widgets


                                         Qwidget
                                           / \
                                            -
                                            |
                                       QMainWindow
-It provides a framework for building an application's user interface.
-It has its own layout to which QToolBars, QDockWidgets, QMenuBar and QStatusBar
can be added.
-It's layout has a center area that can be occupied by any kind of widget,i.e QTextEdit or QGraphicsView

QMainWindow::setCentralWidget( widget )

* QAction: menu items added to QMenu
© www.minhinc.com
p37
void MainWindow::setupMenuBar() {
QMenuBar* bar = menuBar();
QMenu* menu = bar->addMenu(tr("&File"));
menu->addAction(action);
menu->addSeparator();
menu->addMenu("Sub Menu");
  ...

QMainWindow::addToolbar( toolbar )

* Adds toolbar to main window
* QMainWindow::addToolBarBreak()

* Adds section splitter
* QToolBar::addAction( action )

* Adds action to toolbar
* QToolBar::addWidget(widget)

* Adds widget to toolbar
void MainWindow::setupToolBar() {
QToolBar* bar = addToolBar(tr("File"));
bar->addAction(action);
bar->addSeparator();
bar->addWidget(new QLineEdit("Find ..."));
...

QToolButton: Quick-access button to commands or options
QToolButton* button = new QToolButton(this);
button->setAction(action);
// Can have a menu
button->setMenu(menu);
// Shows menu indicator on button
button->setPopupMode(QToolButton::MenuButtonPopup);
// Control over text + icon placements
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
...

void MainWindow::createStatusBar() {
QStatusBar* bar = statusBar();
bar->showMessage(tr("Ready"));
bar->addWidget(new QLabel("Label on StatusBar"));
...

QmainWindow::setDockOptions(options)

Specifies docking behavior (animated, nested, tabbed, ...)
void MainWindow::createDockWidget() {
QDockWidget *dock = new QDockWidget(tr("Title"), this);
dock->setAllowedAreas(Qt::LeftDockWidgetArea);
QListWidget *widget = new QListWidget(dock);
dock->setWidget(widget);
addDockWidget(Qt::LeftDockWidgetArea, dock);
  ...

MDIAREA EXAMPLE
<*.pro>
QT+=widgets
<widget.h>
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPainter> #include <QString> class QPaintEvent; class widget:public QWidget { Q_OBJECT public: widget(QWidget *p=0,const QString& textp=""):QWidget(p),text(textp){} void settext(const QString tp) { text=tp; } private: QString text; protected: void paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); QPainter p(this); p.drawText(rect().width()/2,rect().height()/2,text); } }; #endif
<mainwindow.h>
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QMdiArea; class QListWidget; class mainwindow:public QMainWindow { Q_OBJECT public: mainwindow(QMainWindow *p=0); private slots: void itemclck(); private: QMdiArea *ma; QListWidget *lw; }; #endif
<mainwindow.c>
#include <QWidget> #include <QListWidget> #include <QDockWidget> #include <QMdiArea> #include <QDebug> #include "mainwindow.h" #include "widget.h" mainwindow::mainwindow(QMainWindow *p):QMainWindow(p){ ma=new QMdiArea; lw=new QListWidget(this); QDockWidget *dw=new QDockWidget; dw->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); dw->setWidget(lw); addDockWidget(Qt::LeftDockWidgetArea,dw); lw->addItem(new QListWidgetItem(tr("one"))); lw->addItem(new QListWidgetItem(tr("two"))); lw->addItem(new QListWidgetItem(tr("three"))); ma->addSubWindow(new widget(ma,"first")); ma->addSubWindow(new widget(ma,"second")); ma->addSubWindow(new widget(ma,"third")); ma->tileSubWindows(); //ma->cascadeSubWindows(); setCentralWidget(ma); setFixedSize(width(),height()); connect(lw,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(itemclck())); } void mainwindow::itemclck() { qDebug()<<lw->currentRow(); ma->setActiveSubWindow(ma->subWindowList().at(lw->currentRow())); }
<main.cpp>
#include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); mainwindow m; m.show(); return a.exec(); }

© www.minhinc.com
p38
OUTPUT

STACKED EXAMPLE
<*.pro>
QT += widgets <main.cpp> #include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); mainwindow m; m.show(); return a.exec(); }
<mainwindow.cpp>
#include <QWidget> #include <QListWidget> #include <QDockWidget> #include <QStackedLayout> #include <QDebug> #include "mainwindow.h" #include "widget.h" mainwindow::mainwindow(QMainWindow *p):QMainWindow(p){ QDockWidget *dw=new QDockWidget; lw=new QListWidget(dw); dw->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); dw->setWidget(lw); addDockWidget(Qt::LeftDockWidgetArea,dw); lw->addItem(new QListWidgetItem(tr("one"))); lw->addItem(new QListWidgetItem(tr("two"))); lw->addItem(new QListWidgetItem(tr("three"))); sl= new QStackedLayout; sl->addWidget(new widget(this,"first")); sl->addWidget(new widget(this,"second")); sl->addWidget(new widget(this,"third")); QWidget *w=new QWidget; w->setLayout(sl); setCentralWidget(w); connect(lw,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(itemclck())); }
void mainwindow::itemclck() {
qDebug()<<lw->currentRow();
sl->setCurrentIndex(lw->currentRow());
}

<mainwindow.h>
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QListWidget; class QStackedLayout; class mainwindow:public QMainWindow { Q_OBJECT public: mainwindow(QMainWindow *p=0); private slots: void itemclck(); private: QListWidget *lw; QStackedLayout *sl; }; #endif
<widget.h>
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPainter> #include <QString> class QPaintEvent; class widget:public QWidget { Q_OBJECT public: widget(QWidget *p=0,const QString& textp=""):QWidget(p),text(textp){} private: QString text; protected: void paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); QPainter p(this); p.drawText(rect().width()/2,rect().height()/2,text); } }; #endif
OUTPUT

Day 2 Morning
  5. Widgets

The QDialog class is the base class of dialog windows.

A dialog window is a top-level window mostly used for short-term tasks and brief
communications with the user. QDialogs may be modal or modeless. QDialogs can
© www.minhinc.com
p39
provide a return value, and they can have default buttons. QDialogs can also have a
QSizeGrip in their lower-right corner, using setSizeGripEnabled().


Day 2 Morning
  5. Widgets

A dock widget can be tabified on other dock widget with tabifyDockWidget function in QMainWindow.

Day 2 Morning
  5. Widgets

  - Drag and Drop is done through a drag and a drop site.
  - Drop site has to implement dragEnterEvent, dragMoveEvent and dropEvent
  - Dtag site has to implement mousePressEvent and MoseMoveEvent
  - Dragable data is encapsulated in QMideData and finaly in QDrag widget
 ------------------
  |                |
  |                |------() mousePressEvent
  |                |------() mouseMoveEvent
  |                |------() dragEnterEvent
  |   <DragDrop    |------() dragMoveEvent
  |    widge>      |------() dropEvent
  |                |
  |                |
  ------------------
  <<listwidget.h>>
<*.pro>
QT+=widgets RESOURCES = resource.qrc
<resource.qrc>
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>qt-slide-widget_drgdrpicon.png</file> </qresource> </RCC>
<listwidget.h>
#ifndef LISTWIDGET_H #define LISTWIDGET_H #include <QListWidget> struct QDragEnterEvent; struct QDropEvent; struct QMouseEvent; struct QDragMoveEvent; class listwidget:public QListWidget{ Q_OBJECT public: listwidget(QListWidget *p=0); protected: void mousePressEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void dragEnterEvent(QDragEnterEvent *e); void dragMoveEvent(QDragMoveEvent *e); void dropEvent(QDropEvent *e); private: QPoint spos; }; #endif
<listwidget.cpp>
#include <QPixmap> #include <QListWidgetItem> #include <QPoint> #include <QDragEnterEvent> #include <QDragMoveEvent> #include <QDropEvent> #include <QMouseEvent> #include <QDrag> #include <QMimeData> #include <QApplication> #include "listwidget.h" listwidget::listwidget(QListWidget *p):QListWidget(p){ addItems(QStringList()<<"one"<<"two"<<"three"); setAcceptDrops(true); } void listwidget::mousePressEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) spos=e->pos(); QListWidget::mousePressEvent(e); }
void listwidget::mouseMoveEvent(QMouseEvent *e){
QMimeData *mimedata;
QDrag *drag;
QListWidgetItem *item;
if(e->buttons() & Qt::LeftButton)
if((e->pos()-spos).manhattanLength() >= QApplication::startDragDistance()){
item=currentItem();
if(item) {
mimedata=new QMimeData;
mimedata->setText(item->text());
drag=new QDrag(this);
drag->setMimeData(mimedata);
drag->setPixmap(QPixmap(":/qt-slide-widget_drgdrpicon.png"));
if(drag->exec(Qt::MoveAction) == Qt::MoveAction) delete item;
}
}
QListWidget::mouseMoveEvent(e);
}

void listwidget::dragEnterEvent(QDragEnterEvent* e){
listwidget* source=qobject_cast<listwidget*>(e->source());
if(source && source != this){
e->setDropAction(Qt::MoveAction);
e->accept();
}
}

void listwidget::dragMoveEvent(QDragMoveEvent* e){
listwidget* source=qobject_cast<listwidget*>(e->source());
if(source && source != this) {
e->setDropAction(Qt::MoveAction);
e->accept();
}
}

void listwidget::dropEvent(QDropEvent *e){
listwidget* source=qobject_cast<listwidget*>(e->source());
if(source && source!= this){
addItem(e->mimeData()->text());
e->setDropAction(Qt::MoveAction);
e->accept();
}
}
<main.cpp>
#include <QApplication> #include "listwidget.h" int main(int argc, char *argv[]){ QApplication a(argc,argv); listwidget l1; listwidget l2; l1.show(); l2.show(); return a.exec();
© www.minhinc.com
p40
}
OUTPUT

Day 2 Morning
  5. Widgets

Styles sheets are textual specifications that can be set on the whole application using
QApplication::setStyleSheet() or on a specific widget (and its children) using
QWidget::setStyleSheet(). If several style sheets are set at different levels, Qt derives the
effective style sheet from all of those that are set. This is called cascading.

Ex.

QLineEdit { background: yellow }
QCheckBox { color: red }

<.pro>
QT+=widgets # Input RESOURCES += resource.qrc
<main.cpp>
#include <QApplication> #include "mainwindow.h" int main(int argc, char* argv[]){ QApplication a(argc, argv); mainwindow mw; mw.show(); return a.exec(); }
<mainwindow.h>
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> struct QDockWidget; struct stylewidget; struct mainwindow:QMainWindow{ mainwindow(); stylewidget* sw; QDockWidget *ldw,*rdw; private: Q_OBJECT }; #endif
<stylewidget.h>
fndef STYLEWIDGET_H #define STYLEWIDGET_H #include <QWidget> #include <QString> struct QLineEdit; struct QComboBox; struct QPushButton; struct QListWidget; struct stylewidget:QWidget{ stylewidget(); QComboBox* scb; QComboBox* sscb; QLineEdit* le; QPushButton* pb; QListWidget* lw; private slots: void slotscbactivated(const QString&); void slotsscbactivated(const QString&); private: Q_OBJECT }; #endif
<mainwindow.cpp>
#include <QDockWidget> #include "mainwindow.h" #include "stylewidget.h"
mainwindow::mainwindow(){
setCentralWidget(sw=new stylewidget);
addDockWidget(Qt::LeftDockWidgetArea,ldw=new QDockWidget);
addDockWidget(Qt::RightDockWidgetArea,rdw=new QDockWidget);
ldw->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
rdw->setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea);
ldw->setWindowTitle("Left");
rdw->setWindowTitle("Right");
}
<stylewidget.cpp>
#include <QLineEdit> #include <QPushButton> #include <QListWidget> #include <QLabel> #include <QComboBox> #include <QFile> #include <QVBoxLayout> #include <QHBoxLayout> #include <QApplication> #include <QStyleFactory> #include <QDebug> #include "stylewidget.h" stylewidget::stylewidget(){ QVBoxLayout* vlt=new QVBoxLayout; QHBoxLayout* chlt=new QHBoxLayout; chlt->addWidget(scb=new QComboBox); chlt->addWidget(sscb=new QComboBox); vlt->addLayout(chlt); QHBoxLayout* hlt=new QHBoxLayout; hlt->addWidget(le=new QLineEdit); hlt->addWidget(pb=new QPushButton("click")); vlt->addLayout(hlt); vlt->addWidget(lw=new QListWidget); lw->addItem("one"); lw->addItem("two"); lw->addItem("three"); setLayout(vlt); lw->setCurrentRow(0); QRegExp regex(".(.*)\+?Style"); QString defaultstyle=QApplication::style()->metaObject()->className(); qDebug()<<defaultstyle; if(regex.exactMatch(defaultstyle)) defaultstyle=regex.cap(1); qDebug()<<defaultstyle; scb->addItems(QStyleFactory::keys()); scb->setCurrentIndex(scb->findText(defaultstyle, Qt::MatchContains)); sscb->addItems(QStringList()<<"Default"<<"Style"); sscb->setCurrentIndex(sscb->findText("Default")); connect(scb,SIGNAL(activated(QString)),this,SLOT(slotscbactivated(QString))); connect(sscb,SIGNAL(activated(QString)),this,SLOT(slotsscbactivated(QString))); } void stylewidget::slotscbactivated(const QString& stylename){ qApp->setStyle(stylename); } void stylewidget::slotsscbactivated(const QString& stylesheetname){ QFile file(":/"+stylesheetname.toLower() + ".qss");
© www.minhinc.com
p41
file.open(QIODevice::ReadOnly);
qApp->setStyleSheet(file.readAll());
}
<default.css>
/* empty stylesheet */
style.qss
QLineEdit { background-color : palegoldenrod; } QLabel { font:'Tw Cen Mt'; } QPushButton { background-color : wheat; } QListWidget { background-color : wheat; }
resource.qrc
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>style.qss</file> <file>default.qss</file> </qresource> </RCC>
OUTPUT
© www.minhinc.com
p42
 
Day 2 Morning
  6. QPainter and Image management

QPainter provides highly optimized functions to do most of the drawing GUI programs require. It has three drawing capabilities.
a) Pen
   QPen(const QBrush & brush, qreal width, Qt::PenStyle style = Qt::SolidLine,
   Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin)
b) Brush
   QBrush(const QColor & color, Qt::BrushStyle style = Qt::SolidPattern)
c) Font
   QFont(const QString & family, int pointSize=-1, int weight = -1, bool italic=false)

Day 2 Morning
  6. QPainter and Image management

- OpenGL gl library functions can be called along with 2D QPainter painting. Derive from QGLWidget or QOpenGLWidget which inturn creates OpenGL Context.
- Use paintGL() function for QPainter to draw its primitive within begin() and end() function.
- Call opengl function in paintGL() within beginNativePainting() and endNativePainting().
- Other than initilizeGL(), resizeGL() and paintGL() opengGL context has to be mentioned explicitly by calling makeCurrent() and doneCurrent().

<.pro>
QT+= widgets opengl
<main.cpp>
#include <QApplication> #include "cube.h" int main(int argc, char *argv[]){ QApplication a(argc, argv); cube vc; vc.show(); return a.exec(); }
<cube.h>
#ifndef CUBE_H #define CUBE_H #include <QRadialGradient> class QMouseEvent; class QWheelEvent; class QPainter; #include <QGLWidget> class cube : public QGLWidget { Q_OBJECT public: cube(QWidget *parent = 0); ~cube(); protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); private: void createGradient(); void createGLObject(); void drawBackground(QPainter *painter); void drawCube(); void drawLegend(QPainter *painter); GLuint glObject; QRadialGradient gradient; GLfloat rotationX; GLfloat rotationY; GLfloat rotationZ; GLfloat scaling; QPoint lastPos; }; #endif
<cube.cpp>
#include <qmath.h> #include <QTextDocument> #include <QPainter> #include <QWheelEvent> #include <QMouseEvent> #include "cube.h" cube::cube(QWidget *parent) : QGLWidget(parent) {
setFormat(QGLFormat(QGL::SampleBuffers));
rotationX = -38.0;
rotationY = -58.0;
rotationZ = 0.0;
scaling = 1.0;
createGradient();
createGLObject();
}

cube::~cube() {
makeCurrent();
glDeleteLists(glObject, 1);
}

void cube::paintEvent(QPaintEvent * /* event */) {
QPainter painter(this);
drawBackground(&painter);
painter.beginNativePainting();
drawCube();
painter.endNativePainting();
drawLegend(&painter);
}

void cube::drawBackground(QPainter *painter)
{
painter->setPen(Qt::NoPen);
painter->setBrush(gradient);
painter->drawRect(rect());
}

void cube::drawCube() {
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
GLfloat x = 3.0 * GLfloat(width()) / height();
glOrtho(-x, +x, -3.0, +3.0, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(0.0, 0.0, -10.0);
glScalef(scaling, scaling, scaling);
glRotatef(rotationX, 1.0, 0.0, 0.0);
glRotatef(rotationY, 0.0, 1.0, 0.0);
glRotatef(rotationZ, 0.0, 0.0, 1.0);
glEnable(GL_MULTISAMPLE);
setFont(QFont("Times", 24));
qglColor(QColor(255, 223, 127));
glCallList(glObject);

glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}

void cube::createGradient() {
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
© www.minhinc.com
p43
gradient.setCenter(0.45, 0.50);
gradient.setFocalPoint(0.40, 0.45);
gradient.setColorAt(0.0, QColor(105, 146, 182));
gradient.setColorAt(0.4, QColor(81, 113, 150));
gradient.setColorAt(0.8, QColor(16, 56, 121));
}

void cube::createGLObject() {
makeCurrent();
glShadeModel(GL_FLAT);
glObject = glGenLists(1);
glNewList(glObject, GL_COMPILE);
qglColor(QColor(255, 239, 191));
glLineWidth(1.0);
glBegin(GL_LINES);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,1.0,-1.0);

glVertex3f(-1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);

glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(1.0,1.0,1.0);

glEnd();
glEndList();
doneCurrent();
}

void cube::drawLegend(QPainter *painter) {
const int Margin = 11;
const int Padding = 6;
QTextDocument textDocument;
textDocument.setDefaultStyleSheet("* { color: #FFEFEF }");
textDocument.setHtml("<h4 align="center">OpenGL + QPainter</h4>"
"<p align="center">This example issustrates OpenGL and QPainter drawing together</p>");
textDocument.setTextWidth(textDocument.size().width());
QRect rect(QPoint(0, 0), textDocument.size().toSize()
+ QSize(2 * Padding, 2 * Padding));
painter->translate(width() - rect.width() - Margin,0);
//height() - rect.height() - Margin);
painter->setPen(QColor(255, 239, 239));
painter->setBrush(QColor(255, 0, 0, 31));
painter->drawRect(rect);
painter->translate(Padding, Padding);
textDocument.drawContents(painter);
}
void cube::mousePressEvent(QMouseEvent* e){
    QGLWidget::mousePressEvent(e);
    rotationX+=10;
    rotationY+=10;
    rotationZ+=10;
    update();
}
OUTPUT

Day 2 Morning
  6. QPainter and Image management

- The QImage class provides a hardware-independent image representation which is designed and optimized for I/O, and for direct pixel access and manipulation.
- The QPixmap class is an off-screen image representation which is designed and optimized for showing images on screen. Unlike QImage, the pixel data in a pixmap is internal and is managed by the underlying window system.
- The QBitmap is only a convenience class that inherits QPixmap, ensuring a depth of 1.
- The QPicture class is a paint device that records and replays QPainter commands.

 // Specfiy semi-transparent red
      painter.setBrush(QColor(255, 0, 0, 127));
      painter.drawRect(0, 0, width()/2, height());
      // Specify semi-transparent blue
      painter.setBrush(QColor(0, 0, 255, 127));
      painter.drawRect(0, 0, width(), height()/2);


© www.minhinc.com
p44
Day 2 Morning
  6. QPainter and Image management

QImage provides several ways of loading an image file:
The file can be loaded when constructing the QImage object,
or by using the load() or loadFromData() functions later on.

QImage also provides the static fromData() function,
constructing a QImage from the given data.

Call the save() function to save a QImage object.

Day 2 Morning
  6. QPainter and Image management

QImage::QImage(int width, int height, Format format)

Constant	Value	Description
QImage::Format_Invalid	0	The image is invalid.
QImage::Format_Mono	1	The image is stored using 1-bit per pixel. Bytes are packed with the
                                  most significant bit (MSB) first.
QImage::Format_MonoLSB	2	The image is stored using 1-bit per pixel. Bytes are packed with the
                                  less significant bit (LSB) first.
QImage::Format_Indexed8	3	The image is stored using 8-bit indexes into a colormap.
QImage::Format_RGB32	4	The image is stored using a 32-bit RGB format (0xffRRGGBB).
QImage::Format_ARGB32	5	The image is stored using a 32-bit ARGB format (0xAARRGGBB).
QImage::Format_ARGB32_Premultiplied	6	The image is stored using a premultiplied 32-bit
                                  ARGB format (0xAARRGGBB), i.e. the red, green, and blue channels are
                                  multiplied by the alpha component divided by 255. (If RR, GG, or BB has a
                                  higher value than the alpha channel, the results are undefined.) Certain
                                  operations (such as image composition using alpha blending) are faster
                                  using premultiplied ARGB32 than with plain ARGB32.
QImage::Format_RGB16	7	The image is stored using a 16-bit RGB format (5-6-5).
QImage::Format_ARGB8565_Premultiplied	8	The image is stored using a premultiplied 24-bit ARGB format (8-5-6-5).
QImage::Format_RGB666	9	The image is stored using a 24-bit RGB format (6-6-6). The unused most significant
                                  bits is always zero.
QImage::Format_ARGB6666_Premultiplied	10	The image is stored using a premultiplied 24-bit ARGB format (6-6-6-6).
QImage::Format_RGB555	11	The image is stored using a 16-bit RGB format (5-5-5). The unused most
                                  significant bit is always zero.
QImage::Format_ARGB8555_Premultiplied	12	The image is stored using a premultiplied 24-bit ARGB format (8-5-5-5).
QImage::Format_RGB888	13	The image is stored using a 24-bit RGB format (8-8-8).
QImage::Format_RGB444	14	The image is stored using a 16-bit RGB format (4-4-4). The unused bits are always zero.
QImage::Format_ARGB4444_Premultiplied	15	The image is stored using a premultiplied 16-bit ARGB format (4-4-4-4).
QImage::Format_RGBX8888	16	The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8). This is
                                  the same as the Format_RGBA8888 except alpha must always be 255.
QImage::Format_RGBA8888	17	The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8). Unlike ARGB32
                                  this is a byte-ordered format, which means the 32bit encoding differs between big
                                  endian and little endian architectures, being respectively (0xRRGGBBAA) and
                                  (0xAABBGGRR). The order of the colors is the same on any architecture if read as
                                  bytes 0xRR,0xGG,0xBB,0xAA.
QImage::Format_RGBA8888_Premultiplied	18	The image is stored using a premultiplied 32-bit byte-ordered
                                   RGBA format (8-8-8-8).

Value Based
QImage image(3, 3, QImage::Format_RGB32);
QRgb value;

value = qRgb(189, 149, 39); // 0xffbd9527
image.setPixel(1, 1, value);

value = qRgb(122, 163, 39); // 0xff7aa327
image.setPixel(0, 1, value);
image.setPixel(1, 0, value);

value = qRgb(237, 187, 51); // 0xffedba31
image.setPixel(2, 1, value);


Index Based
QImage image(3, 3, QImage::Format_Indexed8);
© www.minhinc.com
p45
QRgb value;

value = qRgb(122, 163, 39); // 0xff7aa327
image.setColor(0, value);

value = qRgb(237, 187, 51); // 0xffedba31
image.setColor(1, value);

value = qRgb(189, 149, 39); // 0xffbd9527
image.setColor(2, value);

image.setPixel(0, 1, 0);
image.setPixel(1, 0, 0);
image.setPixel(1, 1, 2);
image.setPixel(2, 1, 1);


Day 2 Morning
  6. QPainter and Image management

Transforming the original image
createAlphaMask() function builds and returns a 1-bpp mask from the alpha buffer in this image

createHeuristicMask() function creates and returns a 1-bpp heuristic mask for this image.

mirrored() function returns a mirror of the image in the desired direction
scaled() returns a copy of the image scaled to a rectangle of the desired measures
rgbSwapped() function constructs a BGR image from a RGB image.

scaledToWidth() and scaledToHeight() functions return scaled copies of the image.

transformed() function returns a copy of the image that is transformed with the given
  transformation matrix and transformation mode

trueMatrix() function returns the actual matrix used for transforming the image.

There are also functions for changing attributes of an image in-place:
Function                                       Description
setDotsPerMeterX() Defines the aspect ratio by setting the number of pixels that fit horizontally in a physical meter.
setDotsPerMeterY() Defines the aspect ratio by setting the number of pixels that fit vertically in a physical meter.
fill()                      Fills the entire image with the given pixel value.
invertPixels()     Inverts all pixel values in the image using the given InvertMode value.
setColorTable()    Sets the color table used to translate color indexes. Only monochrome and 8-bit formats.
setColorCount()    Resizes the color table. Only monochrome and 8-bit formats.

© www.minhinc.com
p46
Day 2 Morning
  6. QPainter and Image management

OpenGL in Qt
It used for 3D drawing, developed and maintained by silicon graphics.
In Qt provided through libOpenGL.
It can be implemented through QGLWidget, deriving from QWindow and
QOpenGLFunction and through QGraphics views architecture.

QGLContext creates context and contains all buffers details. Many gl context
can be created and only one can be active at a time with context->makeCurrent()
funciton call.

QOpenGL returns its context with context().
QOpenGL provides three functions for initializing, resizing and drawing.
       initializeGL(), resizeGL(), paintGL()

Procedures
          - Position the camera, fix the scene
          - Place the model (object)
          - Set the projection
          - Viewport
<*.pro>
QT += opengl
<main.cpp>
#include <QApplication> #include "myglwidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MyGLWidget w; w.resize(800,600); w.show(); return a.exec(); }
<myglwidget.h>
#ifndef MYGLWIDGET_H #define MYGLWIDGET_H #include <QGLWidget> class MyGLWidget : public QGLWidget{ //signal slot Q_OBJECT public: MyGLWidget(QWidget *parent = NULL) : QGLWidget(parent) {} protected: // Set up the rendering context, define display lists etc.: void initializeGL(); // draw the scene: void paintGL(); // setup viewport, projection etc.: void resizeGL (int width, int height); }; #endif
<myglwidget.cpp>
#include "myglwidget.h" //first funciton to be called void MyGLWidget::initializeGL(){ glClearColor(0.0,1.0,0.0,0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); } // setup viewport and projection void MyGLWidget::resizeGL (int width, int height){ glViewport( 0, 0, (GLint)width, (GLint)height ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 30.0); //glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 30.0); glMatrixMode( GL_MODELVIEW );
}

void MyGLWidget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-20.0f);
glRotatef(30.0,0.0,1.0,0.0);
glRotatef(15.0,1.0,0.0,0.0);
glBegin(GL_QUADS);
glColor3f(0.0,1.0,0.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(1.0,-1.0,-1.0);

glColor3f(1.0,1.0,0.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);


glColor3f(1.0,0.0,0.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,1.0);

glColor3f(1.0,0.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,1.0,-1.0);

glColor3f(0.0,0.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);

glColor3f(0.0,1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,1.0);

glEnd();
}
OUTPUT
© www.minhinc.com
p47
 
Day 2 Morning
  7. Layout Management

Goal of Layout:
 - Positioning of child widgets.
 - Sensible default sizes for windows.
 - Sensible minimum sizes for windows.
 - Resize handling.
 - Automatic updates when contents change:
   Font size, text or other contents of child widgets.
    Hiding or showing a child widget.
   Removal of child widgets.

Various Layout related classes
QWidget layouts
- QLayout The base class of geometry managers
 -+ QBoxLayout Lines up child widgets horizontally or vertically
    +QHBoxLayout Lines up widgets horizontally
    +QVBoxLayout Lines up widgets vertically
  +QStackedLayout Stack of widgets where only one widget is visible at a time
  +QFormLayout Manages forms of input widgets and their associated labels
  +QGridLayout Lays out widgets in a grid
QLayoutItem Abstract item that a QLayout manipulates
QSpacerItem Blank space in a layout
QWidgetItem Layout item that represents a widget

QGraphicsViews Layouts
QGraphicsAnchorLayout Layout where one can anchor widgets together in Graphics View
QGraphicsAnchor Represents an anchor between two items in a QGraphicsAnchorLayout
QLinearLayout

QSizePolicy Layout attribute describing horizontal and vertical resizing policy
QButtonGroup Container to organize groups of button widgets
QGroupBox Group box frame with a title
QStackedWidget Stack of widgets where only one widget is visible at a time

Day 2 Morning
  7. Layout Management


QBoxLayout takes the space it gets (from its parent layout or from the
parent Widget()), divides it up into a row of boxes, and makes each managed widget fill
one box.

If the QBoxLayout's orientation is Qt::Horizontal the boxes are placed in a row.

If the QBoxLayout's orientation is Qt::Vertical, the boxes are placed in a column.

© www.minhinc.com
p48
Day 2 Morning
  7. Layout Management


A QHBoxLayout lays out widgets in a horizontal row, from left to right (or right to left for
right-to-left languages).

A QVBoxLayout lays out widgets in a vertical column, from top to bottom.
// QT(+core gui widgets) TARGET(container) TEMPLATE(app) SOURCES(+container.cpp)/*
       +-------------------------------+
       |  ---------------------------  |
       |  | <LABEL>                 |  |
       |  | ....................... |  |
       |  | .<Text>               . |  |
       |  | .                     . |  |
       |  | .                     . |  |
       |  | .                     . |  |
       |  | .                     . |  |
       |  | .                     . |  |
       |  | ....................... |  |
       |  |                         |  |
       |  | ----------------------- |  |
       |  | | <BUTTON>  <BUTTON>  | |  |
       |  | ----------------------- |  |
       |  ---------------------------  |
       +-------------------------------+
*/

#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QTextEdit>
#include <QPushButton>

int main(int argc, char *argv[]) {
QApplication a(argc, argv);
//container object is a container widget containing other widgets.
QWidget* container=new QWidget;
QLabel* label=new QLabel("Note",container);
QTextEdit* text=new QTextEdit(container);
QPushButton* clear=new QPushButton("clear",container);
QPushButton* save=new QPushButton("save",container);
//QVBoxLayout and QHBoxLayout are non widget layouts
QVBoxLayout* outer=new QVBoxLayout;
outer->addWidget(label);
outer->addWidget(text);
QHBoxLayout* inner=new QHBoxLayout;
inner->addWidget(clear);
inner->addWidget(save);
//push QHBoxLayout in QVBoxLayout as another entity in vertical order
outer->addLayout(inner);
container->setLayout(outer);
container->show();
return a.exec();
}
OUTPUT

Day 2 Morning
  7. Layout Management


The QGridLayout class lays out widgets in a grid.
© www.minhinc.com
p49
QGridLayout takes the space made available to it (by its parent layout or by the
parentWidget()), divides it up into rows and columns, and puts each widget it
manages into the correct cell.

Columns and rows behave identically; we will discuss columns, but there are equivalent
functions for rows.

Each column has a minimum width and a stretch factor. The minimum width is the
greatest of that set using setColumnMinimumWidth() and the minimum width of
each widget in that column. The stretch factor is set using setColumnStretch() and
determines how much of the available space the column will get over and above its
necessary minimum.

QFormLayout *formLayout = new QFormLayout;
formLayout->addRow(tr("&Name:"), nameLineEdit);
formLayout->addRow(tr("&Email:"), emailLineEdit);
formLayout->addRow(tr("&Age:"), ageSpinBox);
setLayout(formLayout);
Same in Grid Layout
nameLabel = new QLabel(tr("&Name:"));
nameLabel->setBuddy(nameLineEdit);
emailLabel = new QLabel(tr("&Name:"));
emailLabel->setBuddy(emailLineEdit);
ageLabel = new QLabel(tr("&Name:"));
ageLabel->setBuddy(ageSpinBox);
QGridLayout *gridLayout = new QGridLayout;
gridLayout->addWidget(nameLabel, 0, 0);
gridLayout->addWidget(nameLineEdit, 0, 1);
gridLayout->addWidget(emailLabel, 1, 0);
gridLayout->addWidget(emailLineEdit, 1, 1);
gridLayout->addWidget(ageLabel, 2, 0);
gridLayout->addWidget(ageSpinBox, 2, 1);
setLayout(gridLayout);

Day 2 Morning
  7. Layout Management

Day 2 Morning
  7. Layout Management


The QStackedLayout class provides a stack of widgets where only one widget is
visible at a time.
QStackedLayout can be used to create a user interface similar to the one provided by
QTabWidget. There is also a convenience QStackedWidget class built on top of
QStackedLayout.

A QStackedLayout can be populated with a number of child widgets ("pages").
For example:
QWidget *firstPageWidget = new QWidget;
QWidget *secondPageWidget = new QWidget;
© www.minhinc.com
p50
QWidget *thirdPageWidget = new QWidget;

QStackedLayout *stackedLayout = new QStackedLayout;
stackedLayout->addWidget(firstPageWidget);
stackedLayout->addWidget(secondPageWidget);
stackedLayout->addWidget(thirdPageWidget);

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(stackedLayout);
setLayout(mainLayout);

Day 2 Morning
  7. Layout Management


The QGraphicsAnchorLayout class provides a layout where one can anchor widgets
together in Graphics View.

The anchor layout allows developers to specify how widgets should be placed relative
to each other, and to the layout itself. The specification is made by adding anchors to
the layout by calling addAnchor(), addAnchors() or addCornerAnchors().

Existing anchors in the layout can be accessed with the anchor() function. Items
that are anchored are automatically added to the layout, and if items are removed, all
their anchors will be automatically removed.
Anchors are always set up between edges of an item, where the "center"
is also considered to be an edge. Consider the following example:

layout->addAnchor(b, Qt::AnchorLeft, a, Qt::AnchorRight);
layout->addAnchor(b, Qt::AnchorTop, a, Qt::AnchorBottom);

Here, the right edge of item a is anchored to the left edge of item
b and the bottom edge of item a is anchored to the top edge of item b,
with the result that item b will be placed diagonally to the right and
below item b.

The addCornerAnchors() function provides a simpler way of anchoring
the corners of two widgets than the two individual calls to addAnchor()
shown in the code above. Here, we see how a widget can be anchored
to the top-left corner of the enclosing layout:

layout->addCornerAnchors(a, Qt::TopLeftCorner, layout, Qt::TopLeftCorner);
© www.minhinc.com
p51
 
Day 2 Morning
  8. Model View Controller(MVC)

The difference between standard and model/view widgets
The standard widgets involves widgets which include internal containers for storing data.

  Model/view widgets do not maintain internal data containers. They access
  external data through a standardized interface and therefore avoid data duplication.

- View has to implement QAbstractItemView
- View has to aggregate QAbstractItemModel interface.
- Any instance of a class that implements QAbstractItemModel is said to be a model
- A delegate do the index ways rendering of the view and editing to the model.
  Delegate has to implement QAbstractItemDelegate

QTableWidget - Ready Made widget view that has a default internal Model. It can not take extern model.

tableWidget = new QTableWidget(12, 3, this);
or
tableWidget = new QTableWidget(this);
tableWidget->setRowCount(10);
tableWidget->setColumnCount(5);


QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg(
(row+1)*(column+1))); tableWidget->setItem(row, column, newItem);

QTableWidgetItem *cubesHeaderItem = new QTableWidgetItem(tr("Cubes"));
cubesHeaderItem->setIcon(QIcon(QPixmap(":/Images/cubed.png")));
cubesHeaderItem->setTextAlignment(Qt::AlignVCenter);


© www.minhinc.com
p52
QTableView - An QAbstractItemView class where delegatee and model can be set externally.
QStandardItemModel model(4, 2);
QTableView tableView;
tableView.setModel(&model);

for (int row = 0; row < 4; ++row) {
        for (int column = 0; column < 2; ++column) {
            QModelIndex index = model.index(row, column, QModelIndex());
            model.setData(index, QVariant((row + 1) * (column + 1)));
        }
}

- QAbstractItemModel, QAbstractItemView, QAbstractItemDelegate
-----------------------
|                     |
|                     |--------() rowCount
|                     |--------() columnCount
|                     |--------() data()
| QAbstractTableModel |--------() setData()
|                     |--------() flags
|                     |
|                     |
|                     |
-----------------------


-----------------------
|                     |
|                     |----() createEditor() // Editor, index widget for view
|                     |----() setEditorData()//set view editor data,view rendering
|                     |----() setModelData() // set Model data, model editring
|QAbstractItemDelegate|----() updateEditorGeometry() // Change editor geometry
|                     |
|                     |
|                     |
-----------------------

Day 2 Morning
  8. Model View Controller(MVC)

List Models, QAbstractListModel
-Table Models are subclassed from QAbstractListModel.
- Various Tree Model available are QFileSystemModel.
   QFileSystemModel *model=new QFileSuystemModel;
   model-><setRootPath(QDir::currentPath());
   QListView *list=new QTableView(splitter);
   list->setModel(model);

Table Models, QAbstractTableModel
-Table Models are subclassed from QAbstractTableModel.
- Various Tree Model available are QFileSystemModel.
   QFileSystemModel *model=new QFileSuystemModel;
   model-><setRootPath(QDir::currentPath());
   QTableView *table=new QTableView(splitter);
   table->setModel(model);

Tree Models
-Tree Models are subclassed from QAbstractItemModel.
- Various Tree Model available are QFileSystemModel.
   QFileSystemModel *model=new QFileSuystemModel;
© www.minhinc.com
p53
   model-><setRootPath(QDir::currentPath());
   QTreeView *tree=new QTreeView(splitter);
   tree->setModel(model);

Other predefined Models
- QStringListModel

Day 2 Morning
  8. Model View Controller(MVC)

- Predefined Views
  - QColumnView
  - QHeaderView
  - QListView
  - QTableView
  - QTreeView

Day 2 Morning
  8. Model View Controller(MVC)

Custom Models
- Custom models need to be subclassed from QAbstractItemModel.
- For QListView or QTableView QAbstractListModel or QAbstractTableModel needs to be subclassed.
- QAbstractItemModel is basic has a table with rows and coloumns. Each entity in table is idenfiied as item and has itemIndex assisciated.
- Hierarchy of tables is possible and each itemIndex can have siblings, parent and children.
- Each item has number of data elemeents associated with it and they can be retrieved by specifying a role to the model's data() function.
- Model has row count and column count for eacy level of hierarchy.
- When subclassing QAbstractItemModel, index(), parent(), rowCount(), columnCount() and data() must be implemented.
- For Model/View architecture perspective where modifcation in model reflects at all views requires

> insertRows()      beginInsertRows()        endInsertTows()
> insertColumn()    beginInsertColumns()     endInsertColumns()
> removeRows()      beginRemoveRows()        endRemoveRows()
> removeColumns()   beginRemoveColumns()     endRemoveColumns()


-----------------------
|                     |
|                     |--------() rowCount
|                     |--------() columnCount
|                     |--------() data()
| QAbstractTableModel |--------() setData()
|                     |--------() flags
|                     |
|                     |
|                     |
-----------------------

<.pro>
QT+=core widgets TARGET=mv TEMPLATES=app SOURCES+=main.cpp model.cpp HEADERS+=model.h
<main.cpp>
#include <QApplication> #include <QTableView> #include "model.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QTableView tv;
QTableView tv1;
QTableView tv2;
model mdl;
tv.setModel(&mdl);
tv1.setModel(&mdl);
tv2.setModel(&mdl);
tv.show();
tv1.show();
tv2.show();
© www.minhinc.com
p54
return a.exec();
}

<model.h>
#ifndef MODEL_H #define MODEL_H #include <QAbstractTableModel> #include <QString> class model: public QAbstractTableModel{ Q_OBJECT public: model(QObject *parent=0); int rowCount(const QModelIndex &parent=QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); Qt::ItemFlags flags(const QModelIndex& index) const; static const int ROWS=2; static const int COLS=3; QString dt[ROWS][COLS]; }; #endif
<model.cpp>
#include <QString>
#include <QVariant>
#include "model.h"
model::model(QObject *parent):QAbstractTableModel(parent){}
int model::rowCount(const QModelIndex &)const{
return ROWS;
}
int model::columnCount(const QModelIndex &) const{
return COLS;
}
QVariant model::data(const QModelIndex &index, int role)const {
if (role == Qt::DisplayRole)
return dt[index.row()][index.column()];
return QVariant();
}
bool model::setData(const QModelIndex & index, const QVariant & value, int role){
if(role==Qt::EditRole)
  dt[index.row()][index.column()]=value.toString();
  emit dataChanged(index,index);
  return true;
}
Qt::ItemFlags model::flags(const QModelIndex& index) const{
 return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}
OUTPUT

Day 2 Morning
  8. Model View Controller(MVC)

-----------------------
|                     |
|                     |----() createEditor() // Editor, index widget for view
|                     |----() setEditorData()//set view editor data, view rendering
|                     |----() setModelData() // set Model data, model editring
|QAbstractItemDelegate|----() updateEditorGeometry() // Change editor geometry
|                     |
|                     |
|                     |
-----------------------

<*.pro>
QT+=widgets
<delegate.h>
#ifndef DELEGATE_H #define DELEGATE_H #include <QStyledItemDelegate> class spinboxdelegate : public QStyledItemDelegate{ Q_OBJECT public: spinboxdelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif
<delegate.cpp>
#include <QSpinBox> #include <QDebug> #include "delegate.h" spinboxdelegate::spinboxdelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *spinboxdelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QSpinBox *editor = new QSpinBox(parent); editor->setFrame(false); editor->setMinimum(0); editor->setMaximum(100); return editor; } void spinboxdelegate::setEditorData(QWidget *editor, const QModelIndex &index) const{ (static_cast<QSpinBox*>(editor))->setValue(index.model()->data(index, Qt::EditRole).toInt()); } void spinboxdelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QSpinBox *spinBox = static_cast<QSpinBox*>(editor); spinBox->interpretText(); model->setData(index, spinBox->value(), Qt::EditRole); } void spinboxdelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); }
<model.h>
#ifndef MODEL_H #define MODEL_H #include <QAbstractTableModel> #include <QString> class model: public QAbstractTableModel{ Q_OBJECT public: model(QObject *parent=0); int rowCount(const QModelIndex &parent=QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role =Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex& index) const;
static const int ROWS=2;
static const int COLS=3;
QString dt[ROWS][COLS];
};
#endif
<model.cpp>
#include <QString> #include <QVariant> #include <QDebug> #include "model.h" model::model(QObject *parent):QAbstractTableModel(parent){ int i=0,j=0; for (i=0;i<ROWS;i++) for (j=0;j<COLS;j++) dt[i][j]=QString("%1").arg(0); } int model::rowCount(const QModelIndex &)const{ return ROWS; } int model::columnCount(const QModelIndex &) const{ return COLS; } QVariant model::data(const QModelIndex &index, int role)const { if (role == Qt::DisplayRole || role== Qt::EditRole) return dt[index.row()][index.column()]; return QVariant(); } bool model::setData(const QModelIndex & index, const QVariant & value, int role){ if(role==Qt::EditRole) dt[index.row()][index.column()]=value.toString(); emit dataChanged(index,index); return true; } Qt::ItemFlags model::flags(const QModelIndex& index) const{ return Qt::ItemIsEditable | QAbstractTableModel::flags(index); }
<main.cpp>
#include <QApplication> #include <QTableView> #include "model.h" #include "delegate.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QTableView tv,tv1; spinboxdelegate dlg,dlg1; model mdl; tv.setModel(&mdl); tv.setItemDelegate(&dlg); tv1.setModel(&mdl);
© www.minhinc.com
p55
tv1.setItemDelegate(&dlg1);
tv.show();
tv1.show();
return a.exec();
}
OUTPUT
© www.minhinc.com
p56
 
Day 3 Morning
  9. Plugin Architecture

- Static linking, liking to library is achieved at  compile-link time.  Executable binary contans the library code. Following ompiler directive used to create the library

<<calc_mean.c>>
//#include <stdio.h>
double mean(double a, double b){
return (a+b)/2;
}

<<calc_mean.h>>
double mean(double, double);

<<calc.c>>
#include <stdio.h>
#include "calc_mean.h"
int main(){
printf("mean of 3, 6 is %f
", mean(3,6));
return 0;
}

$gcc -c calc_mean.c -o calc-mean.o
$ar rcs libmean.a calc_mean.o // create archive file
                              // (static library) *.a file
$gcc -c calc.c -o calc.o //  create binary file
$gcc  -o calc calc.o -L.  -lmean


$ nm libmean.a
  calc_mean.o:
  0000000000000000 T mean

 +--------------+
 |              | <-------
 |  libmean.a   |        |  libmean.a is inside the binary file
 ----------------        |
 |  code & data | o-------
 +--------------+
 calc binary file

- Dynamic linking (late binding), linking to library is achieved at run time.

$gcc -c -fPIC calc_mean.c -o calc_mean.o
$gcc -c calc.c -o calc.o
$gcc -shared -fPIC -o libmean.so calc_mean.o
$ldd libmean.so
 linux-vdso.so.1 =>  (0x00007fffadffe000)
 libc.so.6 => /lib64/libc.so.6 (0x00007f546f7ed000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f546fdc4000)

$gcc -o calc calc.o -L. -lmean
$ldd calc
 linux-vdso.so.1 =>  (0x00007fffa58de000)
 libmean.so => not found
 libc.so.6 => /lib64/libc.so.6 (0x00007f4e10d70000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f4e11146000)


  +--------------+            +--------------+
  |              |   ------>  |  libmean.a   |
  |  code & data |   |        +--------------+
  +--------------+   |
     calc binary     |         libmean library
                     |
                     |
     Libmean.so is external to calc binary



© www.minhinc.com
p57
  +--------------+                            |               |
  |              | <---libmean.so mapped -->  |               |
  |  libmean.so  |     from shared memory     | libmean.so    |
  ----------------                            |               |
  |  code & data |                            |               |
  +--------------+
    calc process                                shared memory

$export LD_LIBRARY_PATH=.
$./calc
mean of 3, 6 is 4.500000
In order to avoid LD_LIBRARY_PATH programmer can add
-Wl,rpath,<lib path> to the command link line

- Runtime linking (late late binding)
 Library is not loaded when binary executes, rather than it is loaded on demand at run time. C function libraries are loaded through Qlibrary class method load() or resolve().


QLibrary myLib("mylib");
typedef void (*MyPrototype)();
MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol");
if (myFunction)
myFunction();

Day 3 Morning
  9. Plugin Architecture

Plugins are class based shared libraries which are loaded through QPluginLoader class rather than Qlibrary.

Qt provides two APIs for creating plugins.
  - A higher-level API for writing extensions to Qt itself: custom database drivers, image formats, text codecs, custom styles, etc.
  - Lower level API where plgin is written from scratch. Base classes of higher level API plugins are written through low level API plugins.


Higher-level plugins are achieved through deriving achieved through deriving existing plugin interfaces, example

Base Class                         Directory Name             Key Case Sensitivity
QAccessibleBridgePlugin accessiblebridge      Case Sensitive
QAccessiblePlugin       accessible            Case Sensitive
QDecorationPlugin       decorations           Case Insensitive
QFontEnginePlugin       fontengines           Case Insensitive
QIconEnginePlugin       iconengines           Case Insensitive
QImageIOPlugin          imageformats          Case Sensitive
QInputContextPlugin     inputmethods          Case Sensitive
QKbdDriverPlugin        kbddrivers            Case Insensitive
QMouseDriverPlugin      mousedrivers          Case Insensitive
QScreenDriverPlugin     gfxdrivers            Case Insensitive
QScriptExtensionPlugin  script                Case Sensitive
QSqlDriverPlugin        sqldrivers            Case Sensitive
QStylePlugin            styles                Case Insensitive
QTextCodecPlugin        codecs                Case Sensitive

Plugin macros are declared in QstylePlugin dervice class as
 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "simplestyle.json")
Json file contains the key. QStylePlugin create function is called against the key.
                        -------------
                        |  QObject  |
                        -------------
                             / \
                              -
© www.minhinc.com
p58
                              |
        --------------- -------------  --------------------
        | QStylePlugin| |  QObject  |  | QSqlDriverPlugin | . . .
        --------------- -------------  --------------------
                             / \
                              -
                              |
                     ---------------------
                     | simplestyleplugin |
                     ---------------------
                     | o create():QStyle*|
                     ---------------------
                       Plugin interface



                     ----------------       --------        ---------
                     |  QCommonStyle| ---|> |QStyle| ---|>  |QObject|
                     ----------------       --------        ---------
                            / \
                             -
                             |
                     ---------------
                     | QProxyStyle |
                     ---------------
                            / \
                             -
                             |
                    ---------------------
                    | simplestyleplugin |
                    ---------------------
                    | o polish(QPalette)|
                    ---------------------
                    Plugin implementation
<<styleplugin.pro>>
TEMPLATE = subdirs
SUBDIRS = app plugin

<<app/app.pro>>
QT += widgets
SOURCES += main.cpp
TARGET = styleplugin
win32 {
debug:DESTDIR = ../debug/
release:DESTDIR = ../release/
} else {
    DESTDIR    = ../
}

<<app/main.cpp>>
#include <QtWidgets>
int main(int argv, char *args[]) {
QApplication app(argv, args);
QApplication::setStyle(QStyleFactory::create("simplestyle"));
QPushButton pb("clickme");
pb.show();
return app.exec();
}

<<plugin/plugin.pro>>
TEMPLATE    = lib
CONFIG     += plugin
QT         += widgets
HEADERS     = simplestyle.h
              simplestyleplugin.h
SOURCES     = simplestyle.cpp
              simplestyleplugin.cpp
TARGET      = simplestyleplugin
win32 {
    CONFIG(debug, release|debug):DESTDIR = ../debug/styles/
    CONFIG(release, release|debug):DESTDIR = ../release/styles/
} else {
    DESTDIR = ../styles/
}
EXAMPLE_FILES += simplestyle.json

<<plugin/simplestyle.json>>
{
    "Keys": [ "simplestyle" ]
}

<<plugin/simplestyle.h>>
#ifndef SIMPLESTYLE_H
#define SIMPLESTYLE_H
#include <QProxyStyle>
QT_BEGIN_NAMESPACE
class QPalette;
QT_END_NAMESPACE
© www.minhinc.com
p59
class SimpleStyle : public QProxyStyle{
Q_OBJECT
public:
SimpleStyle() {};
void polish(QPalette &palette);// Q_DECL_OVERRIDE;
};
#endif


<<plugin/simplestyle.cpp>>
#include <QtWidgets>
#include "simplestyle.h"
void SimpleStyle::polish(QPalette &palette) {
    palette.setBrush(QPalette::Button, Qt::red);
}

<<plugin/simplestyleplugin.h>>
#ifndef SIMPLESTYLEPLUGIN_H
#define SIMPLESTYLEPLUGIN_H
#include <QStylePlugin>
QT_BEGIN_NAMESPACE
class QStringList;
class QStyle;
QT_END_NAMESPACE
class SimpleStylePlugin : public QStylePlugin{
 Q_OBJECT
 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "simplestyle.json")
public:
 SimpleStylePlugin() {}
// QStringList keys() const;
 QStyle *create(const QString &key) Q_DECL_OVERRIDE;
};
#endif

<<plugin/simplestyleplugin.cpp>>
#include <QtWidgets>
#include "simplestyleplugin.h"
#include "simplestyle.h"
//QStringList SimpleStylePlugin::keys() const{
//    return QStringList() << "SimpleStyle";
//}
QStyle *SimpleStylePlugin::create(const QString &key){
    if (key.toLower() == "simplestyle")
        return new SimpleStyle;
    return 0;
}


  ------+  Application
  |                 +----- All QStylePlugin must be in dirctory named styles
  |                 |
  ------+  styles   |
        |           V
        |
        +------ libstyleplugin.so
        |
        +------ libxxxx.so
        |
        +------ libyyyy.so

Plugin .so libraries can be located with funciton QcoreApplication::addLibraryPath(). It is similar to adding path to LD_LIBRARY_PATH environment variable. Styles plugin must be in the directory "styles" in the path provided through QcoreApplication::addLibraryPath()

© www.minhinc.com
p60
Day 3 Morning
  9. Plugin Architecture


Lower level plugin has three parts.
a) Interface classes.
b) Plugin interfaces extending the intefaces.
c) Application instantiating the plugin and accessing it through inteface (plugin extending the interface).

a) Interface class
Making an application extensible through plugins involves the following steps:
  -  Define a set of interfaces (classes with only pure virtual functions) used to talk to the plugins.
  -  Use the Q_DECLARE_INTERFACE() macro to tell Qt's meta-object system about the interface.

 b) Plugin interface
  - Declare a plugin class that inherits from QObject and from the interfaces that the plugin wants to provide.
  - Use the Q_INTERFACES() macro to tell Qt's meta-object system About the interfaces.
  - Export the plugin using the Q_PLUGIN_METADATA() macro.
  - Build the plugin using a suitable .pro file.

c) Application instantiating the plugin and using it through interfaces.
  -  Use QPluginLoader in the application to load the plugins.
  -  Use qobject_cast() to test whether a plugin implements a given interface.

A plugin is loaded through QLoadPlugin::load() api which retruns the base class pointer and respective pointer is achieved through qObject_cast macro.

a) Interface class
<<plugin/textart.pro>>
TEMPLATE = lib
CONFIG += plugin
TARGET = textart
HEADERS += basiceffectsplugin.h textartinterface.h
SOURCES += basiceffectsplugin.cpp
DESTDIR = .

<<plugin/textartinterface.h>>
#ifndef TEXTARTINTERFACE_H
#define TEXTARTINTERFACE_H
#include <QPixmap>
#include <QString>
#include <QStringList>
#include <QFont>
#include <QPen>
#include <QBrush>
class TextArtInterface {
public:
 virtual ~TextArtInterface(){}
 virtual QStringList effects() const=0;
 virtual QPixmap applyEffect(const QString &effect,const QString& text, const QFont &font,
         const QSize &size, const QPen& pen, const QBrush& brush)=0;
};
Q_DECLARE_INTERFACE(TextArtInterface,"com.software-inc.TextArt.TextArtInterface/1.0")
#endif

b)Plugin interfae
<<plugin/basiceffectsplugin.h>>
#ifndef BASICEFFECTSPLUGIN_H
#define BASICEFFECTSPLUGIN_H
#include <QObject>
© www.minhinc.com
p61
#include "textartinterface.h"
class BasicEffectsPlugin : public QObject, public TextArtInterface{
Q_OBJECT
Q_INTERFACES(TextArtInterface)
/*Q_PLUGIN_METADATA(IID "com.software-inc.TextArt.TextArtInterface/1.0"
            FILE "mymetadata.json") */
Q_PLUGIN_METADATA(IID "com.software-inc.TextArt.TextArtInterface/1.0")
public:
 QStringList effects() const;
 QPixmap applyEffect(const QString &effect, const QString &text,
                          const QFont &font, const QSize &size,
                          const QPen &pen, const QBrush &brush);
};
#endif

<<plugin/basiceffectsplugin.cpp>>
#include <QStringList>
#include <QFontMetrics>
#include <QPainter>
#include <QPainterPath>
#include "basiceffectsplugin.h"
QStringList BasicEffectsPlugin::effects() const{
 return QStringList()<< "Plain" << "Outline" << "Shadow";
}
QPixmap BasicEffectsPlugin::applyEffect(const QString &effect,
 const QString &text, const QFont &font, const QSize &size,
 const QPen &pen, const QBrush &brush){
 QFont myFont = font;
 QFontMetrics metrics(myFont);
 while ((metrics.width(text) > size.width() || metrics.height() > size.height())
                      && myFont.pointSize() > 9) {
  myFont.setPointSize(myFont.pointSize() - 1);
  metrics = QFontMetrics(myFont);
 }
 QPixmap pixmap(size);
 QPainter painter(&pixmap);
 painter.setFont(myFont);
 painter.setPen(pen);
 painter.setBrush(brush);
 painter.setRenderHint(QPainter::Antialiasing, true);
 painter.setRenderHint(QPainter::TextAntialiasing, true);
 painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
 painter.eraseRect(pixmap.rect());
 if (effect == "Plain")
  painter.setPen(Qt::NoPen);
 else if (effect == "Outline") {
  QPen pen(Qt::black);
  pen.setWidthF(2.5);
  painter.setPen(pen);
 } else if (effect == "Shadow") {
  QPainterPath path;
  painter.setBrush(Qt::darkGray);
  path.addText(((size.width() - metrics.width(text)) / 2) + 3, (size.height() -
                           metrics.descent()) + 3, myFont, text);
  painter.drawPath(path);
  painter.setBrush(brush);
 }
 QPainterPath path;
 path.addText((size.width() - metrics.width(text)) / 2, size.height() -
                           metrics.descent(), myFont, text);
 painter.drawPath(path);
 return pixmap;
}
c) Application instantiating the plugin
<<app.pro>>
QT += widgets
TEMPLATE = app
TARGET = textartdialog
INCLUDEPATH += . plugin
HEADERS += tdialog.h
SOURCES += main.cpp tdialog.cpp

<<tdialog.h>>
#ifndef TDIALOG_H
#define TDIALOG_H
#include <QDialog>
struct TextArtInterface;
class tdialog:public QDialog {
Q_OBJECT
public:
 tdialog(QDialog *p=0);
private:
 QList<TextArtInterface*> interfaces;
};
#endif

<<tdialog.cpp>>
#include <QApplication>
© www.minhinc.com
p62
#include <QVBoxLayout>
#include <QListWidget>
#include <QDir>
#include <QPluginLoader>
#include <QFont>
#include <QListWidgetItem>
#include <QPixmap>
#include <QLinearGradient>
#include "tdialog.h"

#include "textartinterface.h"
tdialog::tdialog(QDialog *p):QDialog(p){
 QString text="Qt Everywhere";
 QListWidget *listwidget;
 QDir plugindir;
 QVBoxLayout *vlt=new QVBoxLayout;
 vlt->addWidget(listwidget=new QListWidget);
 setLayout(vlt);
 listwidget->setViewMode(QListWidget::IconMode);
 listwidget->setMovement(QListWidget::Static);
 listwidget->setIconSize(QSize(200,60));
 (plugindir=QApplication::applicationDirPath()).cd("./plugin");
 foreach(QString filename, plugindir.entryList(QDir::Files)) {
  QPluginLoader loader(plugindir.absoluteFilePath(filename));
  if( TextArtInterface *interface=qobject_cast<TextArtInterface*>(loader.instance()))
  interfaces.append(interface);
 }
 QLinearGradient gradient(0,0, listwidget->iconSize().width()/2,
       listwidget->iconSize().height()/2);
 gradient.setColorAt(0.0, QColor("darkolivegreen"));
 gradient.setColorAt(1.0, QColor("lightgreen"));

 foreach(TextArtInterface *interface, interfaces) {
  foreach (QString effect, interface->effects()) {
   QListWidgetItem *item=new QListWidgetItem(effect, listwidget);
   item->setData(Qt::DecorationRole, interface->applyEffect(effect,"Qt Everywhere",
     QFont("Tw Cen Mt",listwidget->iconSize().height(),Qfont::Bold),
      listwidget->iconSize(),QColor("darkseagreen"),gradient));
  }
 }
 listwidget->setCurrentRow(0);
}

<<main.cpp>>
#include <QApplication>

#include "tdialog.h"

int main(int argc, char* argv[]){
 QApplication a(argc, argv);
 tdialog td;
 td.show();
 return a.exec();
}


© www.minhinc.com
p63
Day 3 Morning
  9. Plugin Architecture

- Creating static plugin
Static plugin can be created with CONFIG+=static entry in .pro file of the plugin.
<<plugin/plugin.pro>>
TEMPLATE = lib
CONFIG += plugin static
DESTDIR = .
TARGET = textart
HEADERS += basiceffectsplugin.h textartinterface.h
SOURCES += basiceffectsplugin.cpp

This will generate libtextart.a library file.

-linking static plugin to application
Application linking to the user static plugin library has to provide the library path and library name against LIBS config variable.

<<app.pro>>
QT += widgets
TEMPLATE = app
TARGET = textartdialog
LIBS += -Lplugin -ltextart
INCLUDEPATH += . plugin
HEADERS += tdialog.h
SOURCES += main.cpp tdialog.cpp

If library is Qt specific (i.e qjpeg) then it can be added through QTPLUGIN config variable.
QTPLUGIN += qjpeg
            qgif
            qkrcodecs

Application has to include Q_IMPORT_PLUGIN in global space taking parameter of plugin class name

<<main.cpp >>
#include <QtPlugin>
#include <QApplication>
#include "tdialog.h"

Q_IMPORT_PLUGIN(BasicEffectsPlugin)
int main(int argc, char* argv[]){
 QApplication a(argc, argv);
 tdialog td;
 td.show();
 return a.exec();
}

For Qt secific plugins (i.e qjpeg), Q_IMPORT_PLUGIN is implicitly added to the source file when QTPLUGIN is added to the .pro file

Source code has to list the plugin through QPluginLoader::staticInstances() funciton
<<tdialog.cpp>>
#include <QApplication>
#include <QVBoxLayout>
#include <QListWidget>
#include <QDir>
#include <QPluginLoader>
#include <QFont>
#include <QListWidgetItem>
#include <QPixmap>
#include <QLinearGradient>
#include "tdialog.h"

© www.minhinc.com
p64
#include "textartinterface.h"
tdialog::tdialog(QDialog *p):QDialog(p){
 QString text="Qt Everywhere";
 QListWidget *listwidget;
 QDir plugindir;
 QVBoxLayout *vlt=new QVBoxLayout;
 vlt->addWidget(listwidget=new QListWidget);
 setLayout(vlt);
 listwidget->setViewMode(QListWidget::IconMode);
 listwidget->setMovement(QListWidget::Static);
 listwidget->setIconSize(QSize(200,60));
  foreach(QObject *plugin, QPluginLoader::staticInstances()){
  if( TextArtInterface *interface=qobject_cast<TextArtInterface*>(plugin))
  interfaces.append(interface);
 }
 QLinearGradient gradient(0,0, listwidget->iconSize().width()/2, listwidget->iconSize().height()/2);
 gradient.setColorAt(0.0, QColor("darkolivegreen"));
 gradient.setColorAt(1.0, QColor("lightgreen"));
 foreach(TextArtInterface *interface, interfaces) {
  foreach (QString effect, interface->effects()) {
   QListWidgetItem *item=new QListWidgetItem(effect, listwidget);
   item->setData(Qt::DecorationRole, interface->applyEffect(effect,"Qt Everywhere",QFont("Tw Cen Mt",listwidget->iconSize().height(),QFont::Bold),listwidget->iconSize(),QColor("darkseagreen"),gradient));
  }
 }
 listwidget->setCurrentRow(0);
}
© www.minhinc.com
p65
 
Day 3 Morning
  10. Graphics Views

Graphics View provides an item-based approach to model-view programming Several views can observe a single scene, and the scene contains items of varying geometric shapes.

QGraphicsScene provides the Graphics View scene. The scene has the following responsibilities:
 - Providing a fast interface for managing a large number of items
 - Propagating events to each item
 - Managing item state, such as selection and focus handling
 - Providing untransformed rendering functionality; mainly for printing
QGraphicsScene scene;
QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));

QGraphicsItem *item = scene.itemAt(50, 50);
// item == rect

Scene Coordinate
QGraphicsView provides the view widget, which visualizes the contents of a scene. You can attach several views to the same scene, to provide several viewports into the same data set.
QGraphicsScene scene;
myPopulateScene(&scene);

QGraphicsView view(&scene);
view.show();

QGraphicsItem is the base class for graphical items in a scene. Graphics View provides several standard items for typical shapes, such as rectangles (QGraphicsRectItem), ellipses (QGraphicsEllipseItem) and text items (QGraphicsTextItem),

View Coordinate

QGraphicsItem supports the following features:
 - Mouse press, move, release and double click events, as well as mouse hover events, wheel events, and context menu events.
 - Keyboard input focus, and key events
 - Drag and drop
 - Grouping, both through parent-child relationships, and with QGraphicsItemGroup
 - Collision detection

QGraphicsItem

     / \
      -
      |


virtual void paint(QPainter* painter,const QStyleOptionGraphicsItem* option,QWidget* widget=0)=0

Item coordinate

QGraphicsWidget
The QGraphicsWidget class is the base class for all widget items in a  QGraphicsScene.

QGraphicsWidget is an extended base item that provides extra functionality over QGraphicsItem. It is similar to QWidget in many ways:

 - Provides a palette, a font and a style().
  - Has a defined geometry().
  - Supports layouts with setLayout() and layout().
© www.minhinc.com
p66
  - Supports shortcuts and actions with grabShortcut() and insertAction()

QGraphicsLayout
Coordinate Mapping
 - Inorder to find item in view cordinate
 QGraphicsView::mapToScene(),followed by GraphicsScene::itemAt()
 -In order to know where in the viewport an item is located,  QGraphicsItem::mapToScene() on the item, then QGraphicsView::mapFromScene() on the view
 -In order to find what items are inside a view ellipse, pass a QPainterPath to mapToScene(), and then pass the mapped path to QGraphicsScene::items()

Day 3 Morning
  10. Graphics Views

1. set up your tripod and point the camera at the scene (viewing transformation).
2. Arrange the scene to be photographed into the desired component (modeling transformation).
3. choose the camera lens or adjust the zoom (projection transformation).
4. Determine how large you want the final photograph to be - for example, you might want it enlarged (viewport transformation).

                                                       ( )
                                                   . .
                                                 .  .
                                          .   .   .
     Viewing                        .   .  .    .   Positioning the
                             .      .   .     .     viewing volume in
                      .         .    .      .       the world
               .             .   .        .
              -------------------       .
              |       .         |     .
              |    .            |   .
              | .               | .
              -------------------


                                                       ( )
                                                   . .
                                               . .  .
                                          .   .   .
                                    .   .  .    .
    Modeling                 .      .   .     . Positiioning the
                      .         .    .      .   models in the world
               .             .    .       .
              -------------------       .
              |        /xx     |     .
              |    .  xxxx/    |   .
              | .      xx/     | .
              -------------------

                                                       ( )
                                                   . .
                                                 .  .
                                          .   .   .
                                   ----------   .
    Projection               -      |   -   | .
                      -         -   |-      |
               -             -   -  ---------
              -------------------       -      Determining the
              |       -         |     -        shape of the
              |    -            |   -          viewing volume
              | -               | -
              -------------------




    Viewport
              ----------------------------
              |              .           |
              |          . xxxxx .       |
              |       . xxxxxxxxxxx .    |
              |     . xxxxxxxxxxxxxxx .  |
              |       . xxxxxxxxxxx .    |
              |          . xxxxx .       |
              |              .           |
© www.minhinc.com
p67
              ----------------------------
Day 3 Morning
  10. Graphics Views
© www.minhinc.com
p68
 
Day 3 Morning
  11. XML and JSON Parsing

Day 3 Morning
  11. XML and JSON Parsing

</h>
*JSON
</h>

Day 3 Morning
  11. XML and JSON Parsing
© www.minhinc.com
p69
 
Day 3 Morning
  12. Inter process Communication(IPC)

class
-----
QProcess
----

  QObject
    / \
     -
     |
 QIODevice
    / \
     -
     |
 QProcess


 - Parent Child relationship
QProcess is a QIODevice which can be written and read through QTextStream and QDataStream.
QProcess maintains states
                   +-----------+
Emits finished() and
|Not Running|
stateChanged(NotRunning)
+-----------+
after running
^ ^ | |
 process terminates
| |
starts
| | | | +--------+ +------------+ | | v v +-------+
process start up
+--------+
Emits
|Running|<|--------------------|Starting|
stateChanged(Starging)
+-------+ +--------+
Emits started
and
StateChanged(Running)
QProcess start with start() system call where it can be monitored.

QProcess process;
process.start( "command" );
process.waitForFinished();
QTextStream stream( &process );
QString output = stream.readAll();

Signals
void finished(int exitCode, QProcess::ExitStatus exitStatus)
void readyReadStandardError()
void readyReadStandardOutput()
void started()
void stateChanged(QProcess::ProcessState newState)

Important functions
void kill()
void terminate()
int exitCode() const
QProcess::ExitStatus exitStatus() const
virtual qint64 bytesAvailable() const
virtual bool canReadLine() const

Synchronous functions
bool waitForStarted(int msecs = 30000) //returns when the started() signal has been emitted, i.e., the process has started successfully (or has failed to start)
virtual bool waitForReadyRead(int msecs = 30000)
virtual bool waitForBytesWritten(int msecs = 30000)
bool waitForFinished(int msecs = 30000)

Static functions
int execute(const QString &program, const QStringList &arguments)
int execute(const QString &command)

© www.minhinc.com
p70
If you are not interested in processing the output of the external process, nor in supplying input to it, use the static convenience method QProcess::execute() that starts the process, waits for its termination, and returns:
QStringList arguments;
arguments << "Argument1" << "Argument2";
QProcess::execute("do_it_now", arguments);
// won't get here until do_it_now terminates

bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), qint64 *pid = Q_NULLPTR)
bool startDetached(const QString &command)
Use QProcess::startDetached() instead if you want the child process to detach from the current one. This method will not wait for termination, and the child process will not be terminated when the current process terminates ("fire and forget").

QString nullDevice()
QStringList systemEnvironment()

 - Message passing
since QProcess is child of current process message can be passed to the child with writeData
qint64 QProcess::writeData(const char *data, qint64 len)
in synchronous call parent can wait for data written through
virtual bool waitForBytesWritten(int msecs = 30000)

similarily data can be read back through
virtual qint64 readData(char *data, qint64 maxlen)
complete data can be read from the channel with
QByteArray readAllStandardOutput()

 - popen
Like popen in unix when parent process can read stdout/stderr child data through FILE* and can also write through FILE*, in QProcess different channels like
QProcess::StandardOutput
QProcess::StandardError
of child can be read in parent process.

channel mixing
child's stdout/stderr channels can be mixed to stdout
void QProcess::setProcessChannelMode(ProcessChannelMode mode)
mode can be 
QProcess::MergedChannels
Day 3 Morning
  12. Inter process Communication(IPC)
                      -----------------
          +-----------| Shared Memory |--------+
          |           -----------------        |
          |                                    |
          |
Mapped into 
|
Mapped into
| | ------------------ -------------------- |Process Address1| | Process Address 2| ------------------ --------------------
class
------
QSharedMemory
QSystemSemaphore
-----
      QObject         QSystemSemaphore
        / \
          -
         |
   QSharedMemory
A shared memory segment is identified by a QString key. This key can be set in the constructor or via
QSharedMemory::setKey() .
An attempt to create() a shm segment that already exists, or to attach() to a segment that does not exist will result in
an error.
© www.minhinc.com
p71
The only way to check if a memory segment with a given key exists is to try to attach to it.

Note:- In HP-UX only one attachement is allowed per process so 	QSharedMemory can not be used accross multiple threads

Creation
QSharedMemory shm;
shm.setKey("MyShm");
if( !shm.create( 4242 /*bytes*/, QSharedMemory::ReadWrite ) ) {
/* failure, error details available in shm.error()/shm.errorString() */
}
/* create() also attaches to memory, so we can use it right away */
shm.lock();
void* data = shm.data();
/* ... do interesting stuff with data... */
shm.unlock();

Destruction
/* Detach from memory, if we're the last process to do so, the memory is released */
shm.detach();
The QSharedMemory instance should be kept around as long as we want to keep the memory.

Attach
QSharedMemory shm;
shm.setKey("MyShm");
if( !shm.attach( QSharedMemory::ReadWrite ) ) {
/* failure, error details available in shm.error()/shm.errorString() */
}
shm.lock();
void* data = shm.data();
/* ... do interesting stuff with data... */
shm.unlock();
shm.detach()
© www.minhinc.com
p72
 
Day 4 Morning
  13. Multithreading

multithreading is young technique in Qt and still far from mainstream programming.
mutlithreading is used when a programming can be broken into several independent tasks that needs to be executed asynchornously.
dependent task needs synchronization to avoid data sharing, deadlock and race conditions issues.

class
--------
QThread, QThreadPool, QRunnable // Parallel tasks
QtConcurrent

QThreadStorage //Thread storage

QAtomicInt, QAtomicPonter,QWaitCondition, QMutex, QReadWriteLock, QSemaphore //Synchornization
-----
  QObject
    / \
     -
     |
     +------------+
     |            |
QThread QThreadpool

Thread model
        started() o------+
       finished()o-----+ |
                       | |
                      -----------
                      |         |----o start()
                      |         |    .
                      |         |    .<<calls>>
                      | QThread |    .
                      |         |    v
                      |         |----o run() <--- Entry point function
                      |         |
                      -----------
                         | | | |
                         | | | +----o idealThreadCount()
                         | | +-----o setThreadPrioriy()
                         | +------o isFinished()/isRunning()
                         +-------o wait()
signals
-------
void finished()
void started()

Day 4 Morning
  13. Multithreading

Creating and Starting a thread
1)Subclass QThread
 ----------------
                 | QThread     |<-- call start() to enter thread in ::run()
                  ----------------
                  | run=0;         |
                  ----------------
                            /
                             _
© www.minhinc.com
p73
                             |
                  --------------
                 |    mythread |
                 ------------------
                  |   run()            | <--- call exec() in run to have event loop
                  ------------------

2)call start() method
3)It creates another event queue, that can be run as exec()
4)Implement code in run() function

QThread::run(){
.
.
exec();
}

wait for threads to end
bool isFinished() const
bool isRunning() const

call 
wait
method to wait for thread to finish similar pthread_join
bool wait(unsigned long time = ULONG_MAX)

A thread can stop execution temporarily by calling
void msleep(unsigned long msecs)
void sleep(unsigned long secs)
void usleep(unsigned long usecs)
from within run().

A thread can terminate by calling 
exit()
void exit(int returnCode = 0)

A object can be moved to another thread with
void QObject::moveToThread(QThread *targetThread)

cross-Thread Signals/Slots
Qt::QueuedConnection:
connect( sender, SIGNAL(...), receiver, SLOT(...),
Qt::QueuedConnection
);
...
// emit the signal on the sender thread as usual
This technique requires that the receiving thread (but not necessarily the sending one) has an event loop running.
If you do not specify Qt::QueuedConnection, the default is Qt::AutoConnection, which will do the right thing if emitter and receiver are on different threads.

There is one additional connect method, namely BlockingQueuedConnection. This will make the sender block until the receiving slots have been executed.
-Warning: Overuse of this can easily result in deadlocks.

QThreadPool
QThreadPool
is a low-level class for managing threads. A
QThreadPool
maintains a pool of up to
QThreadPool::maxThreadCount()
threads (default:
QThread::idealThreadCount()
-------------------- | QRunnable | ------------------- | run()=0 | ------------------- / - | -------------------- | task | <-- add this task to QThreadPool -------------------- | run() | <-- QThreadPool::start() would enter here
© www.minhinc.com
p74
                     --------------------
QRunnable
Tasks that can be run on the thread pool implement:
class QRunnable {
public:
virtual void run() = 0;
};

There is one global QThreadPool instance,
QThreadPool::globalInstance()
, which is also used by QtConcurrent to schedule its tasks. QRunnable tasks can be added to QThreadPool like
runnabletask1 *task1 = new helloworldtask();
runnabletask2 *task2 = new helloearthtask();
QThreadPool::globalInstance()->start(task1);
QThreadPool::globalInstance()->start(task2);

example
-------
concepts.pro
QT       += core
TARGET = concepts
TEMPLATE = app
HEADERS += calculator.h workerthread.h threadcontroller.h runnabletask.h
SOURCES += concepts.cpp

<calculator.h>
#ifndef CALCULATOR_H #define CALCULATOR_H #include <QObject> #include <QDebug> class calculator : public QObject { Q_OBJECT public: void factorial(int a) {qDebug()<<"emiting signal";emit sig_factorial(a);} public slots: void on_sigfactorial(int a) { qDebug()<<"calculating factorial of"<<a; } signals: void sig_factorial(int); }; #endif
<workerthread.h>
#include "calculator.h" #include <QThread> #include <QDebug> #include <QCoreApplication> class workerthread: public QThread { Q_OBJECT public: workerthread(calculator* calcp){calc=calcp;} void run() { qDebug()<<"workerthread started"; calc->moveToThread(QCoreApplication::instance()->thread()); /*calculator calc; QObject::connect(&calc, &calculator::sig_factorial,&calc,&calculator::on_sigfactorial); calc.factorial(10);*/ // QThread::exec(); } calculator* calc; };
<threadcontroller.h>
#include <QThread> #include "workerthread.h" class threadcontroller { //QThread mythread; workerthread mythread;
public:
//    QThread& getthread() { return mythread;}
workerthread& getthread(){ return mythread;}
~threadcontroller(){mythread.quit();mythread.wait();}
};

<runnabletask.h>
#include <QRunnable> #include <QDebug> class helloworldtask : public QRunnable { public: void run() { qDebug()<< "Hello world"<< QThread::currentThread(); } }; class helloearthtask : public QRunnable { public: void run() { qDebug()<< "Hello Earth"<< QThread::currentThread(); } };
<concepts.cpp>
//QT (+ core)TARGET (concepts) TEMPLATE (app) INCLUDES (+calcualtor.h) SOURCES (+concepts.cpp) #include <QCoreApplication> #include <QThread> #include <QThreadPool> #include "calculator.h" #include "threadcontroller.h" #include "runnabletask.h" int main(int argc, char *argv[]) { QCoreApplication a(argc,argv); //threadcontroller anotherthread; calculator calc; workerthread anotherthread(&calc); //calc.moveToThread(&anotherthread.getthread()); calc.moveToThread(&anotherthread); QObject::connect(&calc,&calculator::sig_factorial,&calc,&calculator::on_sigfactorial); //anotherthread.getthread().start(); anotherthread.start(); calc.factorial(10); // ThreadPool /*qDebug()<<"ideal thread count"<<QThread::idealThreadCount(); qDebug()<<"active thread count"<<QThreadPool::globalInstance()->activeThreadCount(); helloworldtask *task1 = new helloworldtask(); helloearthtask *task2 = new helloearthtask(); QThreadPool::globalInstance()->start(task1); QThreadPool::globalInstance()->start(task2);*/ return a.exec(); }

QCuncurrent
The QtConcurrent namespace make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores.
Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.

------------
Functions
-----------
QtConcurrent::map() applies a function to every item in a container, modifying the items in-place.
QtConcurrent::mapped() is like map(), except that it returns a new container with the modifications.
QtConcurrent::mappedReduced() is like mapped(), except that the modified results are reduced or folded into a single result.
QtConcurrent::filter() removes all items from a container based on the result of a filter function.
QtConcurrent::filtered() is like filter(), except that it returns a new container with the filtered results.
QtConcurrent::filteredReduced() is like filtered(), except that the filtered results are reduced or folded into a single result.
QtConcurrent::run() runs a function in another thread.
QFuture represents the result of an asynchronous computation.
QFutureIterator allows iterating through results available via QFuture.
QFutureWatcher allows monitoring a QFuture using signals-and-slots.
QFutureSynchronizer is a convenience class that automatically synchronizes several QFutures.

© www.minhinc.com
p75
 ::run()
::run() function runs a function 'QString functionReturningAString()' in another thread.
extern QString functionReturningAString();
QFuture<QString> future = QtConcurrent::run(functionReturningAString);
...
QString result = future.result();
class objects, first argument must be const refrence to class object or pointer to object. const refrenct is required for const members, pointer is for non const members.

Class member Const reference;
// call 'QList<QByteArray>  QByteArray::split(char sep) const' in a separate thread
QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');
...
QList<QByteArray> result = future.result();

Pointers: -
// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread
QImage image = ...;
QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);
...
future.waitForFinished();
// At this point, the pixels in 'image' have been inverted


 QFutureWatcher
QFutureWatcher class allows monitoring a QFuture using signals and slots.
// Instantiate the objects and connect to the finished signal.
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

// Start the computation.
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);

 ::map()
QtConcurrent::mapped() takes an input sequence and a map function. This map function is then called for each item in the sequence, and a new sequence containing the return values from the map function is returned.
The map function must be of the form:

U function(const T &t);
T and U can be any type (and they can even be the same type), but T must match the type stored in the sequence. The function returns the modified or mapped content.
QImage scaled(const QImage &image)
{
    return image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

 QtConcurrent::mappedReduced()
 QtConcurrent::mappedReduced() is similar to QtConcurrent::mapped(), but instead of returning a sequence with the new results, the results are combined into a single value using a reduce function.

The reduce function must be of the form:

V function(T &result, const U &intermediate)
T is the type of the final result, U is the return type of the map function. Note that the return value and return type of the reduce function are not used.

void addToCollage(QImage &collage, const QImage &thumbnail)
{
    QPainter p(&collage);
    static QPoint offset = QPoint(0, 0);
    p.drawImage(offset, thumbnail);
    offset += ...;
}

QList<QImage> images = ...;
© www.minhinc.com
p76
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

collage is result where as thumbnail in addToCollage is intermediate

Day 4 Morning
  13. Multithreading

QMutex
      ---------
      |QMutex |---o lock/unlock()
      |       |---o tryLock()
      ---------

QMutexLocker - autoPtr class
      --------------
      |QMutexLocker|----o lock(QMutex*)
      --------------

QWaitCondition
       ----------------
       |QWaitCondition|----o wait()
       ----------------

QWaitCondition::wait() lets a thread wait for a certain event.
 o You can specify a maximum waiting time.
 o You must pass a locked QMutex, to atomically go from locked state to wait state. The mutex will be automatically locked before the thread is woken.
 o Wake one (random) thread waiting on a wait condition with
QWaitCondition::wakeOne()
and all waiting threads with
QWaitCondition::wakeAll()
. example
QT+=core
TEMPLATE = app
TARGET = produceconsumer
INCLUDEPATH += .

# Input
SOURCES += main.cpp
CONFIG+=console

<main.cpp>
#include <QCoreApplication>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QDebug>

QWaitCondition consumer;
QWaitCondition producer;
QMutex mutex;
int count=0;
int maxcount=4;

class workerthread:public QThread {
public:
 workerthread(QObject* parent=NULL):QThread(parent){};
void run() {
 while(1) {
  mutex.lock();
  if(!count)
   producer.wait(&mutex);
  mutex.unlock();
  QThread::msleep(1000);
  mutex.lock();
  count--;
  qDebug()<<"worker consumed" << count;
  consumer.wakeAll();
  mutex.unlock();
 }
}
};
class masterthread:public QThread {
public:
    masterthread(QObject* parent=NULL):QThread(parent){};
 void run() {
  while(1){
   mutex.lock();
   if(count==maxcount)
    consumer.wait(&mutex);
   mutex.unlock();
   QThread::msleep(1000);
   mutex.lock();
   count++;
   qDebug()<<"master thread produced"<<count;
   producer.wakeAll();
   mutex.unlock();
 }
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc,argv);
masterthread mthread;
workerthread wthread;
mthread.start();
wthread.start();
mthread.wait();
wthread.wait();
return a.exec();
}

Semaphore
Semaphores
 o Semaphores (QSemaphore) are generalized mutexes.
 o While a mutex can only be locked once at a time, a semaphore can be locked n times before it will refuse further locks. This is useful when protecting many identical resources.
 o The maximum number of locks ("resources") is specified in the constructor.
© www.minhinc.com
p77
 o You lock a semaphore with QSemaphore::acquire(), specifying the number of resources (locks) you want. If not enough resources are available, the call will block until all requested resources can be locked.
 o release() frees the specified number of resources.
 o tryAcquire(int n=1) tries to get the specified number of resources; returns false if it does not succeed.
 o tryAcquire(int n, int timeout) will wait for timeout milliseconds before giving up on getting the resources.
 o available() returns the number of available resources (but remember that this can change at any time, so the result is not very useful).

QT+=core
TEMPLATE = app
TARGET = produceconsumer
INCLUDEPATH += .

# Input
SOURCES += main.cpp
CONFIG+=console

<main.cpp>
#include <QCoreApplication> #include <QThread> #include <QSemaphore> #include <QMutex> #include <QDebug> int count=0; int maxcount=4; QSemaphore consumer; QSemaphore producer(maxcount); class workerthread:public QThread { public: workerthread(QObject* parent=NULL):QThread(parent){}; void run() { while(1) { consumer.acquire(); count--; qDebug()<<"worker thread consumed"<<count;
QThread::msleep(1000);
producer.release();
}
}
};
class masterthread:public QThread {
public:
 masterthread(QObject* parent=NULL):QThread(parent){};
 void run() {
  while(1){
   producer.acquire();
   count++;
   qDebug()<<"master thread produced"<<count;
   QThread::msleep(1000);
   consumer.release();
  }
 }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc,argv);
masterthread mthread;
workerthread wthread;
mthread.start();
wthread.start();
mthread.wait();
wthread.wait();
return a.exec();
}

Read/Write Locks
 o Qt class for this scenario: QReadWriteLock, with methods lockForRead() and lockForWrite(), as well as unlock().
 o tryLockForRead() and tryLockForWrite() exist as well.  (also with an optional timeout).
 o QReadLocker and QWriteLocker are resource acquisition classes much like QMutexLocker.

Day 4 Morning
  13. Multithreading

Thread-local data
 o General rule: static variables are always global, local ("automatic") variables are always thread-local.
 o Sometimes, you may need to have data that is local to a thread, but you can't make it function-local. For this purpose, you can use QThreadStorage
 o QThreadStorage is a template class taking the data type to store as it's template argument, e.g.  QThreadStorage<int*>.

 o Use setLocalData() to store data, localData() to fetch data, and hasLocalData() to test if any data has been set.
 o Due to compiler limitations, QThreadStorage can currently only store pointers, and the data must be created on the heap, as QThreadStorage takes ownership of it and deletes it as necessary.

Caveats

The QThreadStorage destructor does not delete per-thread data. QThreadStorage only deletes per-thread data when the thread exits or when setLocalData() is called multiple times.
QThreadStorage can be used to store data for the main() thread. QThreadStorage deletes all data set for the main() thread when QApplication is destroyed, regardless of whether or not the main() thread has actually finished.
© www.minhinc.com
p78
 
Day 4 Morning
  14. Web Kit

Day 4 Morning
  14. Web Kit

Day 4 Morning
  14. Web Kit

Day 4 Morning
  14. Web Kit

Day 4 Morning
  14. Web Kit
© www.minhinc.com
p79
 
Day 4 Morning
  15. Databases

Day 4 Morning
  15. Databases

Day 4 Morning
  15. Databases

Day 4 Morning
  15. Databases

Day 4 Morning
  15. Databases
© www.minhinc.com
p80
 
Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

© www.minhinc.com
p81
Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)

Day 4 Morning
  16. Internationalization & Localization(I18N L10N)
© www.minhinc.com
p82
 
Day 4 Afternoon
  17. Networking

Day 4 Afternoon
  17. Networking

Day 4 Afternoon
  17. Networking

Day 4 Afternoon
  17. Networking
© www.minhinc.com
p83
 
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

© www.minhinc.com
p84
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

© www.minhinc.com
p85
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

© www.minhinc.com
p86
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

© www.minhinc.com
p87
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics

© www.minhinc.com
p88
Day 5 Morning
  21. Qml/QtQuick Basics

Day 5 Morning
  21. Qml/QtQuick Basics
© www.minhinc.com
p89
 
Day 5 Morning
  18. Drag & Drop

Day 5 Morning
  18. Drag & Drop

Day 5 Morning
  18. Drag & Drop

Day 5 Morning
  18. Drag & Drop
© www.minhinc.com
p90
 
Day 5 Morning
  19. Deployment and Testing
Static Linking
Mechanics: Everything the application needs is pulled from the library into the binary.
 o No extra binary to ship.
 o Advantage: No version conflicts.
 o Disadvantage: Bugfixes in the library require recompilation
 o Disadvantage: Library code is not shared between different Qt applications.
 o Disadvantage: Qt plugins (codecs, styles, image formats, etc.) do not work.

Dynamic Linking against Private Library Copy
Mechanics: Qt code is stored in a separate binary, which is combined with the application at run time to form the final executable,i.e dll and so files

To avoid conflicts with other installed Qt libraries, use -rpath, or a wrapper script that sets LD_LIBRARY_PATH (Unix/Linux) or PATH (Windows) before calling the real application, e.g.:
#!/bin/sh
MYAPPDIR=/opt/myapp
LD_LIBRARY_PATH=$MYAPPDIR/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
exec $MYAPPDIR/bin/myapp

Dynamic Linking Against System's Qt (Unix only)
 o Bugfixes in the library do not require recompilation.
 o Updates to Qt are shipped by the operating system vendor.
 o Library code is shared between different Qt applications (esp. useful when targeting the KDE desktop).
 o Disadvantage: Choice of Qt version and configuration constrained by lowest common denominator of what the target distributors provide (Linux distributors are pretty uniform, though).
 o Disadvantage: Some Unix vendors do not provide a system Qt.

Day 5 Morning
  19. Deployment and Testing

GDB - GNU Debugger
 o GDB is a free debugger for Linux and UNIX
 o GDB is a command-line tool, but GUI frontends exist (e.g., DDD and kdbg)
  o Requirements
  o Build Qt and application with debug information.
  o Qmake projects:
  CONFIG+=debug
  o Rebuild project:
  make clean && make && make install


Valgrind - Profiler
  o Valgrind is a free high-quality debugger/profiler tool for Linux. It support X86, AMD64, PPC32, and PPC64
  o Many "skins" available: memcheck, cachegrind, massif and helgrind
  o Valgrind is easy to use - no recompilation, no relinking, and no modification of source code.
example
  valgrind -tool=memcheck myapp
© www.minhinc.com
p91
  <command-line-argument> This will print out information about access to unallocated memory, mismatching new/delete etc. on the console.

  o Consider the following piece of code
const char* str = "Hello World!";
char* copy = (char*)new char[strlen(str)];
strcpy(copy,str);
delete copy;
The array allocated for the copy of the string is one byte too short to contain the string plus the
trailing null. This code may or may not crash when writing one byte past the end of the char array. In some cases, it does not crash, but the code is clearly wrong anyway.
The other error is that memory allocated with new[] is deallocated with delete and not delete[], as it should have been!

Valgrind - an example
 o Valgrinding the code on the previous page yields:
  ==12294== Invalid write of size 1
  ==12294== at 0x4002178E: strcpy (mac_replace_strmem.c:174)
  ==12294== by 0x8048672: main (main.cpp:5)
  ...
  ==12294== Mismatched free() / delete / delete []
  ==12294== at 0x40028ED7: __builtin_delete (vg_replace_malloc.c:244)
  ==12294== by 0x40028EF5: operator delete(void*) (vg_replace_malloc.c:253)
  ==12294== by 0x8048680: main (main.cpp:6)
  ...
  ==12294== Address 0x43E9C43C is 0 bytes inside a block of size 12 alloc'd
  ==12294== at 0x40028D70: __builtin_vec_new (vg_replace_malloc.c:203)
  ==12294== by 0x40028DC7: operator new[](unsigned) (vg_replace_malloc.c:216)
  ==12294== by 0x804865E: main (main.cpp:4)

So valgrind finds both of our problems. "Invalid write of size 1" means that we write one byte into unallocated memory (the trailing null of the string), "Mismatched free()/delete/delete[]" means that we are freeing memory with a function or operator that does not match the one that was used to allocate it-and it even tells us where that particular piece of memory was allocated and which operator was used!

Day 5 Morning
  19. Deployment and Testing

QMake
 o QMake is a makefile generator.
 o Supports multiple platforms and multiple C++ compilers.
 o Automatically maintains dependencies.
 o Includes support for MOC, UI and QRC files.
 o Is very terse-you do not have to write much.
 o Supports compiling both applications and libraries.
 o Supports Unix-style Makefiles, nmake Makefiles, Visual C++ and VS.NET, and MacOS Xcode, among others.

VARIABLES
 o All System Variables are written in capital letters.
 o You can also add your own variables.
 o Variables can be referenced using $$:
  PARSER = myparser.cpp
  SOURCES= main.cpp $$PARSER
 o Lines can be split using backslashes.
 o # is the comment character; comments extend till the end of the line.

Most Common System Variables
 o TEMPLATE Defines the type of project. Must be one of:
© www.minhinc.com
p92
 o app, vcapp Creates a binary.
 o lib, vclib Creates a library.
 o subdirs Invokes make recursively for subdirectories.
 o HEADERS List of header files.
 o SOURCES List of (C/C++) source files.
 o TARGET Name of the executable (adds .exe on Windows).
  Defaults to the name of the .pro file/directory.

 o QT Specifies the Qt features to be included. Core and GUI are included by default. To make other feature available, use
   QT += xml sql network
  If you do not need the GUI classes (e.g., because you are building a server application), use
   QT -= gui

Other Useful System Variables
 o DEFINES List of C preprocessor macros (-D option).
 o LIBS List of additional libraries to be linked in.
 o INCLUDEPATH Sets the include search path (-I option).
 o DEPENDPATH Sets the dependency search path for QMake.
 o DESTDIR Specifies where to put the target file.
 o MOC_DIR Specifies directory to place moc files in.
 o OBJECT_DIR Specifies directory to place object files in.

System Variables
 o LEXSOURCES Specifies a list of lex files.
 o YACCSOURCES Specifies a list of yacc sources.
 o SUBDIRS Specifies a list of directories to run make recursively in.
 o VERSION Specifies the version for the library template.
 o FORMS Specifies interfaces (.ui) files from Qt Designer.
 o RESOURCES Specifies resource collection (.qrc) files to include in build.

The CONFIG System Variable
 o The system variable CONFIG is a list of system configurations. The following options exist:
 o release Compile with optimization enabled, ignored if debug is specified.
 o debug Compile with debug options enabled.
 o warn_on The compiler should emit more warnings than normally, ignored if warn_off is specified.
 o warn_off The compiler should emit no warnings or as few as possible.
 o ordered Order subdirectories so parallelized builds work.
 o qt The target is a Qt application/library and requires Qt header files/library.
 o opengl The target requires the OpenGL (or Mesa) headers/libraries.
 o thread The target is a multi threaded application or library.
 o x11 The target is an X11 application or library.
 o windows The target is a Win32 window application.
 o console The target is a Win32 console application.
 o shared The target is a shared object/DLL.
 o static The target is a static library.
 o plugin The target is a plugin (requires TARGET=lib, and implies shared).
 o exceptions Turns on compiler exception support.
 o rtti Turns on compiler RTTI support.
 o stl Turns on Qt STL support.
 o flat only for TEMPLATE=vcapp; puts all sources files into one group and all header files into another group, independent of the directory structure.

subdirs template
 test.pro:
 TEMPLATE = subdirs
 SUBDIRS = dirA dirB dirC

 o If QMake is used in the subdirectories to generate the Makefiles, the project files in these directories should be called <dir-name>.pro.
 o Example: dirA/dirA.pro. This makes it possible for qmake to execute qmake in the subdirectories.
© www.minhinc.com
p93
Modifying Variables
 o Variables can be modified in a number of ways:
 A = abc
 X = xyz
 A += abc def # A = abc abc def
 B = $$A # B = abc abc def
 B -= abc # B = def
 B *= abc def # B = abc def
 B ~= s/ab[xc]/xyz/ # B = xyz def
 o This can be used to modify variables from the command line:
  qmake -after "LIBS+=-pg" "CONFIG+=debug" "CONFIG-=release"
  Development Process QMake 393/478
  Scopes
 o You can use scopes to conditionally assign to variables.
 o Scopes can be specified based on the following things:
 o OS mode (win32, unix, mac, . . . )
 o Patterns matching the platform (QMAKESPEC environment variable, or -platform command line option): solaris-cc or linux-* or *-g++* or *-64 etc.
 o Options appearing in the CONFIG variable, including your own.
 o The result of a function (described later)

Scopes
 o Scopes can be specified in "concatenation" syntax: scope1:scope2:. . . :scopen:var = value
 o Examples:
  SOURCES = common.cpp
  win32:SOURCES += win_hack.cpp # OS.
  unix:profile:LIBS += -pg # profile is a user supplied
  # option from the CONFIG
  # variable.

 o Scopes can also be specified in groups using { . . . }:
  win32 {
  debug {
  SOURCES += debug.cpp # win32 && debug
  }
  release {
  SOURCES += release.cpp # win32 && release
  }
  }
 o Be aware that with the { . . . } syntax, the opening brace must be on the same line as the test, and the closing brace must be on a line by itself.

 o The two methods can be combined.
  win32 {
  debug:SOURCES += debug.cpp
  release:SOURCES += release.cpp
  }
 o Scopes can be negated with an exclamation mark:
  network:SOURCES += network.cpp
  !network:SOURCES += no_network.cpp
 o Alternatively you can use else.
  Development Process QMake 397/478
  Functions
 o A number of predefined functions exists, they are split in two categories:
 o test functions used as part of tests.
 o replacement functions used to create strings (i.e., right-hand-side values).
 o It is also possible to implement your own functions, which is beyond the scope of this course, please refer to the reference manual.

Test Functions
 o isEmpty( variablename ) This function will succeed if the variable variablename is empty (same as count(variable, 0)).
© www.minhinc.com
p94
 o CONFIG( config ) Like a scope qualifier, but allows mutual exclusions to be specified. Rarely needed, the specifiers that are useful here should not go into the .pro file anyway, but rather be specified on the command line.
 o count( variablename, number ) This function will succeed if the variable variablename contains number elements.
 o contains( variablename, value ) This function will succeed if variablename contains the value value.

 o system( command ) This function will execute the command in a secondary shell and will succeed if the command exits with an exit status of 0.
 o error( txt ) This function will never return. It will display the given string to the user, and then exit qmake.
 o message( txt ) This function will always succeed, and will display the given string to the user. warning() is a synonym.
 o infile( filename, var, val ) Succeeds if filename, as parsed by QMake, contains a variable var set to val. If val is not specified, it tests for the mere declaration of var.  Development Process QMake 400/478 Test functions
 o include( filename ) This function will include the contents of filename into the current project at the point it was included. The function succeeds if filename was included.
 o exists( filename ) Succeeds if filename exists. If you must have a certain file for proceeding further, you can use error() (see below) for terminating in case this file does not exist:
  !exists( file.dat ):error( "file.dat missing" )
  Development Process QMake 401/478
  Replacement Functions
 o basename( file ) This function returns the basename of file, i.e., the filename stripped of the path and a possible extension. The path can be extracted with dirname().
 odirname( file ) Returns the path of the directory containing the file.
 o prompt(question) Displays question, waits for input from standard input, and returns that input. Warning: This will break automated builds, unless standard input is redirected.  It might be useful for very simple install scripts, though.
 o system( command ) This function will execute the command in a secondary shell and will return stdout and sdterr concatenated.
 o find( variablename, substr ) Returns all values in variablename that match the regular expression substr. See the QRegExp documentation for the regular expression syntax.
 o for( iterator, list ) Iterates over list, using the loop variable iterator. The syntax <num>..<num> is supported as well.
 o join( varname, glue, before, after ) Joins the value of variablename according to what QStringList::join() does.

 o member( varname, position ) Equivalent to QList::at().
 o quote( string ) Turns string into a single entity and returns that.
 o unique( varname ) Removes duplicate values from varname and returns the new list.
 o sprintf( string, arguments... ) Like QString::sprintf(), but uses %1-%9 for the placeholders.

Day 5 Morning
  19. Deployment and Testing

Qt Debugging Aids
 o You can output debugging messages with qDebug(),
  qDebug( "Method computed: %d", myIntVariable );
  qDebug() << "Mouse was clicked at " << mouseEvent->pos();
 o Setting the environment variable QT_FATAL_WARNINGS makes the application terminate on warnings.
 o Connecting a signal and a slot incorrectly is only shown if Qt is compiled with debug information.
© www.minhinc.com
p95
 o Defining QT_NO_DEBUG_OUTPUT and/or QT_NO_WARNING_OUTPUT during compilation of your application, turns the messages in question off.
 o Q_ASSERT is like the good old assert, except that you can compile it out by compiling Qt with the QT_NO_DEBUG flag.
 o Q_ASSERT_X() is an assert that lets you specify a message to output on assertion failure.
 o To show a QString in MSVC++ you need to insert the following code into the file
  ...Program FilesMicrosoft Visual Studio
  Common7PackagesDebuggerAutoexp.dat (adjust
  for your Visual Studio installation):
  ; from Qt
  QString=<d->data,su>

Printing QString in GDB
 o Insert the following code into your ~/.gdbinit, and you can do qs str (where str is a QString):
  define qs
  set $i=0
  set $d = $arg0.d
  while $i < $d->size
  printf "%c", (char)($d->data[$i++] & 0xff)
  end
  printf "
"
  end
 o kdesdk/scripts/kde-devel-gdb contains many more of these functions.

 o You can pass a name to each Qt object with setObjectName().
 o This name can be retrieved with QObject::objectName().
 o As a lot of the debugging information is only really helpful if these names are set, it is good Qt programming style to do so.
 o QObject::dumpObjectInfo() dumps information about object internals, like signals/slots.
 o QObject::dumpObjectTree() dumps the parent/child relationships of all descendant objects.
 o Installing a global event filter can help you get information about your widgets.
 o Questions which can be answered include: "Which children does this widget have?" and "How far does this widget stretch?"
 o #include "shootabug.h" and insert the following into your
  main:
  qApp->installEventFilter( new ShootABug() );
  Development Process Qt Debugging Aids
  Shoot a Bug
  class ShootABug :public QObject
  {
  Q_OBJECT
  public:
  bool eventFilter( QObject* recv, QEvent* event )
  {
  if ( event->type() != QEvent::MouseButtonPress )
  return false; // pass it on
  QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
  if ( (mevent->modifiers() & Qt::ControlModifier ) &&
  (mevent->button() & Qt::LeftButton) ) { // Ctrl + left mouse click.
  qDebug("----------------------------------------------------");
  qDebug("Widget name : %s", qPrintable( recv->objectName() ) );
  qDebug("Widget class: %s", recv->metaObject()->className() );
  qDebug("
Object info:");
  recv->dumpObjectInfo();
  qDebug("
Object tree:");
  recv->dumpObjectTree();
  qDebug("----------------------------------------------------");
© www.minhinc.com
p96
  return true; // Block
  }
  return false;
  Qt Debugging Aids
 o On X11 systems, the command-line switch -nograb prevents Qt from grabbing the mouse and keyboard and thus prevents the dreaded "debugger lock-ups".
 o On Linux, Qt even detects if it is running from within gdb and automatically turns off grabbing. This can be overridden with
  -dograb. (Careful!)
 o Qt also supports the command-line switch -sync which makes all Xlib calls synchronous.

Day 5 Morning
  19. Deployment and Testing

Introduction
 o Testing helps you gain confidence in your product, and makes paradigms like refactoring possible.
 o Test-driven development is (part of) a whole development methodology based entirely on unit tests.
 o At least two kind of test types exists: unit testing and black box testing.
 o QTestLib is about unit testing, while products like KD Executor and Squish are more about black box testing.

 o When writing unit tests, you write code that tests individual functions or methods.
 o These tests are compiled into a test binary, which is compiled against the functions of your classes that you want to test.
 o Since the tests are compiled into a separate binary, your final product will not contain any traces of test functions.
 o As an added bonus, unit testing can well improve the design of your application.

QTestLib Facts
 o Lightweight 6000 lines of code, 60 exported symbols.
 o Self-contained Requires only a few symbols from Qt.
 o Rapid testing No special test-runners; No special registration for tests.
 o Data-driven testing A test can be executed multiple times with different test data.
 o Basic GUI testing Offers functionality for mouse and keyboard simulation.
 o Type-safety Extensive use of templates prevent errors introduced by implicit type casting.
 o Easily extendable Custom types can easily be added to the test data and test output.

Writing a Simple Test
 o Test cases are implemented as functions in a class which must inherit QObject.
 o The macro QTEST_MAIN implements a main function and registers the test class at the same time.
 o Add CONFIG += qtestlib to your qmake file to compile QTestLib into a test binary.
 o A number of macros exist in order to verify your result, including QVERIFY and QCOMPARE

Data-Driven Testing
 o When testing a certain function it might be useful to test it with different parameters.
 o We could do this with a number of calls to e.g. QCOMPARE.
 o The alternative is to use QTestLib's capability for data-driven testing.
 o Here, one function is the actual test case, while another, with the postfix _data, contains the dataset. The test function is invoked for each data item in the data set.
© www.minhinc.com
p97
  Development Process Unit Testing with QTestLib 468/478
  Data Driven Testing
 o In the _data function, you set up your data using the method
  QTest::addColumn(), and create test data using
  QTest::newRow():
  QTest::addColumn<QString>( "input" );
  QTest::addColumn<QString>( "result" );
  QTest::newRow( "all lower" ) << "hello" << "hello";
  QTest::newRow( "mixed" ) << "HellO" << "hello";
 o In the test case, you fetch the data using the QFETCH macro:
  QFETCH( QString, input );
  QFETCH( QString, result );
  QCOMPARE( input.toLower(), result );
  Development Process Unit Testing with QTestLib 469/478
  Data Driven Testing
 o It is possible to use your own data types as long as they have
  been registered using Q_DECLARE_METATYPE.
 o The macro QEXPECT_FAIL can be set up to expect failure
  from a given data in the set:
  QFETCH( QString, data );
  QFETCH( int, result );
  QEXPECT_FAIL( "expected error",
  "To be fixed", Abort );
  QCOMPARE( data.count(), result );
 o The first parameter is the name of the data value, the second a message to display, and the third tells whether the test case should continue. after an error.
 o See example unit-test/data-driven

GUI Testing
 o Using QTestLib, you can simulate mouse and keyboard events.
 o Keyboard events: keyClick(), keyClicks(), keyEvent()
 o Mouse events: mouseClick(), mouseDClick(), mousePress(), mouseRelease(), mouseMove()
 Examples:
  QTest::keyClicks( lineEdit, "Hello World" );
  QTest::keyClick( lineEdit, Qt::Key_Backspace );
  QTest::keyEvent( QTest::Press, lineEdit, 'a',
  Qt::ControlModifier );
  QTest::mouseClick( lineEdit, Qt::LeftButton );

GUI Testing
 o During testing, it can be useful to wait a few milliseconds, e.g.  when waiting for a remote server to respond.
 o This can be done using QTest::qSleep() or
  QTest::qWait().
 o qSleep() is blocking, i.e. no event processing is done, while qWait() keeps the event loop running while waiting.
 o The methods keyPress(), keyClick(), . . . all take an optional argument specifying the amount of milliseconds to wait before continuing.
 o In addition, the command-line arguments -keydelay, -mousedelay, and -eventdelay can be used to insert a
  delay after each key and/or mouse event.

Data-Driven GUI Testing
 o To support data driven GUI testing, the class QTestEventList can be used for storing key and mouse events.
 o The class has methods similar to those of QTest, namely addKeyPress(), addKeyClick(), addMouseClick(), . . . .
 o To playback the events, use QTestEventList::simulate(), which takes a widget on which the events are invoked.

QSignalSpy
 o Unit testing is about stimulating an object, and verifying response.
 o QObjects can emit signals in response.
 o The class QSignalSpy is designed to verify emitted signals.
© www.minhinc.com
p98
 o The class inherits QList< QList<QVariant> >, the outer list items each represent a signal emission, while the inner list items represent its argument.

Benchmarking
  Test functions can be benchmarked.
 o Apply the QBENCHMARK macro to parts of test functions.
 o Run the test case in the usual way.
  class MyFirstBenchmark: public QObject
  {
  Q_OBJECT
  private slots:
  void myFirstBenchmark()
  {
  QString string1;
  QString string2;
  QBENCHMARK {
  string1.localeAwareCompare(string2);
  }
  }
  };

Dmarking Backends
 Backends measure and report performance in different ways:
 o These are selected via command line options.
 o The default "Walltime" backend measures and reports elapsed time.
 o -tickcounter selects the cross-platform CPU tick counter backend.
 o -eventcounter selects the cross-platform event counter backend.
 o -callgrind selects the Linux-specific Callgrind backend.
 o Some backends may run benchmarked code multiple times to ensure accurate timings.
  See the QTestLib manual for more details.

 Project Task: Test the Compass Widget
 o Create unit tests for the compass widgets you implemented, alternatively use the one from solutions/compasswidget.
 o Discuss what you can do during development of your application, in order to better support unit testing.
 o Optional: Modify the compass widget according to the
© www.minhinc.com
p99
 
Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI

© www.minhinc.com
p100
Day 5 Afternoon
  20. Embedded Qt and HMI

Day 5 Afternoon
  20. Embedded Qt and HMI
© www.minhinc.com
p101