Cet article constitue un regroupement de notes prises pour la préparation de la certification « Qt Essentials Curriculum Block - version 1.1 ». Ces notes proviennent de différentes sources, indiquées dans le chapitre « Références » et organisées selon les différents items proposés dans la page « Qt Essentials Curriculum Block ».

Pour rappel, les personnes qui passent la certification s'engagent à ne pas divulguer d'informations sur cette certification. Ces notes ont donc étaient rassemblées avant le passage de l’examen et il ne sera pas possible de répondre aux questions par la suite.

1 Fundamentals of Qt Programming

1.1 UI and cross-platform libraries

1.1.1 Learn the difference between a native APIs and cross platform APIs

Quels sont les différentes API natives ? Limitations ? Avantages ?

1.1.2 Know the difference between toolkits and frameworks

Bonne question...

1.1.3 Understanding the reasoning for portable software

...

1.2 First development steps

1.2.1 Learn how to write a simple Qt application

Installation du SDK ? Compilation d'un main avec window ?

#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QLabel *label = new QLabel("Hello Qt!");
    label->show();
    return app.exec();
}

Nom des objets Qt : commence par un Q ; nécessite include

Compilation :

From a command prompt, change the directory to hello, and type

qmake -project

to create a platform-independent project file (hello.pro), and then type

qmake hello.pro
make // ou nmake sur VS

Run it by typing hello on Windows, ./hello on Unix, and open hello.app on Mac OS X

Widget avec texte en HTML :

QLabel *label = new QLabel("

Hello

   Qt!

");

Changement de styles :

./age -style motif

Buddy = widget qui accepte le focus lors que l'on utilise le raccourci clavier d'un label :

label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);

1.2.2 Understand the need for layout management

Gestion de la position des widgets = to manage the geometry of widgets in a window

a widget is a visual element in a user interface,Buttons, menus, scroll bars, and frames are all examples of widgets, peut contenir d'autres widgets, noms : QMenuBar, a few QToolBars, a QstatusBar dans Qt.

1.2.3 Be able to find answers to questions about Qt

Documentation officielle sur Qt Creator (F1), en ligne (doc.qt.nokia.com/) ou Qt Assistant ou dans doc/html

Relation d'héritage entre les objets, accessible dans l'aide avec les lignes Inherits (parent) et Inherited by (enfants)

1.2.4 Learn how to use qmake

1.3 QObject basics

1.3.1 Understand the fundamentals of QObject

Basé sur les méta-objets : introspection (permet d'avoir des informations sur un objet au runtime, permet les propriétés, la traduction des chaînes de caractères, l'utilisation des scripts) et signaux/slots

Mécanisme :

1.3.2 Be able to use Qt properties and other core features provided by the Qt's meta-type system

Q_OBJECT

signaux/slots et connect()

tr() → permet la traduction des chaînes

parent-enfant : suppression des objets en mémoire et suppression des widgets à l'écran

1.4 Memory management

1.4.1 Understand where and when Qt deletes objects

QObject utilise un système de parent-enfant pour supprimer automatiquement les objets liés à un objet. Minimise les risques de fuite mémoire

Principe :

1.4.2 Know when a developer is responsible for providing code deleting allocated objects

Les objets à détruire sont ceux créé avec new et sans parents :

layout manager = active automatiquement une relation parent-enfant

QApplication app(argv, argc); // sur la pile
{
    label = new QPushButton(tr("&Find"));
    button = new QPushButton(label, tr("&Find")); // parent-enfant
}
delete label;
// delete button; → non

1.4.3 Understand when heap and stack allocation are used in Qt

1.5 Edit and build

1.5.1 Be able to create and manage a Qt project via *.pro files

1.5.2 Know key facts about the Qt build process and the tools used (qmake, moc, Makefiles)

Moc → Qt meta-object compiler = compile les .h pour convertir les macro (Q_OBJECT, signals, slots, etc.) ; génère un xxx_moc.cpp. Appelé automatiquement par qmake. Si oublié, génère message d'erreur :

undefined reference to finddialog.o: 
    In function `FindDialog::tr(char const*, char const*)':
    /usr/lib/qt/src/corelib/global/qglobal.h:1430: 
    undefined reference to `FindDialog::staticMetaObject'

Visual C++' :

finddialog.obj : error LNK2001: 
    unresolved external symbol "public:~virtual int __thiscall 
    MyClass::qt_metacall(enum QMetaObject::Call,int,void * *)"

1.5.3 Learn how to use Qt with Qt Creator and supported IDEs

1.6 Signals and slots

1.6.1 Learn the advantages of signals/slots

Permet de connecter des objets entre eux sans avoir besoin que les objets se connaissent mutuellement (découplage)

1.6.2 Understand the concept of signal/slots

Nécessite la macro Q_OBJECT

mots clés : signals, private/protected/public slots, Q_SIGNALS, Q_SLOTS, SIGNAL(), SLOT()

Utilisé par pré-process (programme moc) pour générer le code (.moc)

Slot : identique à fonctions membres classiques (surchargable, peut être virtuelle, private protected ou public, peut être appelée)

SIGNAL et SLOT ne font en gros que convertir les paramètres en chaînes de caractères

1.6.3 Learn how to connect signals to slots

Général :

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

Qobject::connect(
    button, SIGNAL(clicked()), 
    &app, SLOT(quit()));

Avec values et entre plusieurs widgets :

Qobject::connect(
    spinBox, SIGNAL(valueChanged(int)), 
    slider, SLOT(setValue(int)));

Qobject::connect(
    slider, SIGNAL(valueChanged(int)),
    pinBox, SLOT(setValue(int)));

Connections :

Déconnexion possible mais en général pas utile (automatique par Qt quand les objets sont détruits) :

disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));

Paramètres :

Les signaux et slots doivent avoir les mêmes types de paramètres dans le même ordre :

connect(
    ftp, SIGNAL(rawCommandReply(int, const QString &)), 
    this, SLOT(processReply(int, const QString &)));

Si le signal a des paramètres supplémentaires, ils sont ignorés :

connect(
    ftp, SIGNAL(rawCommandReply(int, const QString &)),
    this, SLOT(checkErrorCode(int)));

Si problème de connexion, émission d'un warning en runtime debug

Emettre un signal :

emit nom_du_signal(params) ;

1.6.4 Be able to use and define your own signals/slots

Ajout de fonction déclarées avec signals (ou Q_SIGNALS) et private/protected/public slots (ou Q_SLOTS)

1.7 Overview of modules and classes

1.7.1 Be able to list major Qt modules

Plusieurs modules (= librairies). Les plus importantes : QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg, and QtXml.

Inclusion d'un objet en spécifiant le module ou non ou tout le module :

#include <QLabel>
#include <QtGui/QLabel>
#include <QtGui>

1.7.2 Understand the concept and functionality of a Qt module

1.7.3 Understand the major APIs provided by different Qt modules

1.8 Some thoughts about portability

1.8.1 Understand the advantages of portable software

1.8.2 Know the concepts of making software more portable

1.8.3 Know the limitations of Qt's portability

1.8.4 Understand how to make your project portable

2 Developing an Application

2.1 Events

2.1.1 Understand the concept of events

Lancement de l'event loop : app.exec(); = en attente d'un event utilisateur, réponse du programme à l'event

Lors de l'appel de QApplication::exec(), nous lançons la boucle d'évènement de Qt. Qt émet quelques événements au démarrage (affichage et dessin des widgets). Ensuite, la boucle d'événements tourne en permanence pour capturer les events et les envoyer aux QObject.

event() capture tous les events puis dispatch aux différentes fonctions spécialisées :

Lors de traitement long, la boucle d'event ne tourne plus et il faut lancer manuellement le traitement des events :

qApp->processEvents();
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

Avec une QProgressDialog :

QProgressDialog progress(this);
progress.setRange(0, RowCount);
progress.setModal(true);
for (int row = 0; row < RowCount; ++row) {
    progress.setValue(row);
    qApp->processEvents();
    if (progress.wasCanceled()) {
        return false;
    }
}

Autres solutions :

void Spreadsheet::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == myTimerId) {
        while (step < MaxStep && !qApp->hasPendingEvents()) {
            performStep(step);
            ++step;
        }
    } else {
        QTableWidget::timerEvent(event);
    }
}

2.1.2 Understand the difference between events and signal/slots

Event passe pas une boucle de gestion d'events. Les signaux-slots sont connectés directement ou en passant par la boucle de gestion des events.

Signaux : pour utiliser un widget ; event : pour implémenter un widget

2.1.3 Be able to implement event handling

Events dérivent de QEvent :

Qevent::type() retourne QEvent::MouseButtonPress

Pour modifier le comportement d'un event, il suffit de dériver la classe et surcharger la fonction.

void QWIdget::paintEvent(QPaintEvent *event) 
void QWIdget::mousePressEvent(QMouseEvent *event)

Teste si le bouton est un LeftButton :

if (event->button() == Qt::LeftButton) {

Test si au moins le LeftButton est appuyé :

if (event->buttons() & Qt::LeftButton) {

void CodeEditor::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Home:
        if (event->modifiers() & Qt::ControlModifier) {}
        break;
    case Qt::Key_End:
        ...
    default:
        QWidget::keyPressEvent(event);
    }
}

Pour Tab et Shift+Tab, event() n'envoit pas à keyPressEvent :

bool CodeEditor::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast(event);
        if (keyEvent->key() == Qt::Key_Tab) {
            return true;
        }
    }
    return QWidget::event(event);
}

2.1.4 Understand the role of events in painting

Testé si un rectangle est concerné par un event de dessin :

if (!event->region().intersect(rect).isEmpty()) {}

2.1.5 Understand the role of event filters and be able to use them

Il est possible d'utiliser 5 niveaux de filtres :

En 2 étapes :

CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) : QDialog(parent)
{
    firstNameEdit->installEventFilter(this);
    lastNameEdit->installEventFilter(this);
}

bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
{
    if (target == firstNameEdit || target == lastNameEdit
            || target == cityEdit || target == phoneNumberEdit) {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast(event);
            if (keyEvent->key() == Qt::Key_Space) {
                focusNextChild();
                return true;
            }
        }
    }
    return QDialog::eventFilter(target, event);
}

2.1.6 Understand the concept of event propagation

Un event peut être accepté (et donc appliqué) ou rejeté :

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (okToContinue()) {
        event->accept();
    } else {
        event->ignore();
    }
}

2.1.7 Learn how to post/send events

PostEvent() // mis en file d'attente
SendEvent() // envoyé immédiatement

2.1.8 Be able to create/send/handle custom events

QEvent::User

2.2 Basic drawing

2.2.1 Learn how to draw on widgets

Redessiner automatiquement l'arrière plan avec la couleur Dark :

setBackgroundRole(QPalette::Dark);
setAutoFillBackground(true);

Surcharger l'event de dessin.

void IconEditor::paintEvent(QPaintEvent *event) 
{
    QPainter painter(this);
    painter.drawLine(x1, y1, x2, y2);
    painter.fillRect(rect, color);
}

Utilisation des palettes de couleurs. Plusieurs groupes :

QWidget ::palette()

Couleur d'arrière-plan :

painter.setPen(palette().foreground().color());

Dessiner le rectangle de focus :

if (hasFocus()) {
    QStyleOptionFocusRect option;
    option.initFrom(this);
    option.backgroundColor = palette().dark().color();
    painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}

ou

style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);

ou utiliser un QStylePainter

2.2.2 Understand the difference between QPixmap, QImage and QPicture

QImage   // pour I/O et mnaipulation de pixels
QPixmap  // affichage à l'écran
QBitmap  // depth = 1
QPicture // pour QPainter

2.2.3 Be able to load an image from a file

QImageReader::supportedImageFormats()
QImageWriter::supportedImageFormats() 

2.3 Main windows and actions

2.3.1 Know how to use QmainWindow

Dériver QMainWindow. Mettre :

Plusieurs zones dans une QMainWindow :

Document est modifié ou non :

setWindowModified(true);

Modifier l'icône de la fenêtre :

setWindowIcon(QIcon(":/images/icon.png"));

Fenêtres multiples. Delete automatique lorsque l'on ferme la fenêtre :

setAttribute(Qt::WA_DeleteOnClose);

Pour avoir la liste de toutes les fenêtres :

foreach (QWidget *win, QApplication::topLevelWidgets()) {
    if (MainWindow *mainWin = qobject_cast(win))
        mainWin->updateRecentFileActions();
}

SDI : 1 document par fenêter ; MDI : plusieurs documents par fenêtre.

Affichage d'une page d'accueil avec QSplashScreen:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QSplashScreen *splash = new QSplashScreen;
    splash->setPixmap(QPixmap(":/images/splash.png"));
    splash->show();
    splash->showMessage("Message..."), Qt::AlignRight, Qt::white);
    splash->finish(&mainWin);
    delete splash;
    return app.exec();
}

Changer le curseur :

QApplication::setOverrideCursor(Qt::WaitCursor);
QApplication::restoreOverrideCursor();

Clipboard :

QApplication::clipboard()->setText(str);
QString str = QApplication::clipboard()->text();
autres types : image, pixmap, mimeData

2.3.2 Know how to implement a menu

Utilise le concept d'action. Pour créer un menu :

Utilisation de & pour indiqué un raccourci clavier (si possible)

Pour associer un menu à une action :

fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(newAction);

Séparateurs entre 2 items de menu (barre horizontale) ou entre 2 menus (place les menus après le séparateur à droite de la barre de menu ; uniquement pour les styles CDE et Motif) :

separatorAction = fileMenu->addSeparator();
menuBar()->addSeparator();

Liste de fichiers récemment ouverts :

enum { MaxRecentFiles = 5 };                   // taille max
QAction* recentFileActions[MaxRecentFiles];    // tableau d'actions
QAction* separatorAction;                      // séparateur

Création du menu :

for (int i = 0; i < MaxRecentFiles; ++i) {
    recentFileActions[i] = new QAction(this);
    recentFileActions[i]->setVisible(false);
    connect(
        recentFileActions[i], SIGNAL(triggered()),
        this, SLOT(openRecentFile()));
}

Supprimer les fichiers inexistant de la liste :

QMutableStringListIterator i(recentFiles);
while (i.hasNext()) {
    if (!QFile::exists(i.next()))
        i.remove();
}

Mettre à jour le menu :

for (int j = 0; j < MaxRecentFiles; ++j) {
    if (j < recentFiles.count()) {
        QString text = tr("&%1 %2")
            .arg(j + 1)
            .arg(strippedName(recentFiles[j]));
        recentFileActions[j]->setText(text);
        recentFileActions[j]->setData(recentFiles[j]); // conserve le nom      
                                                       // du fichier
        recentFileActions[j]->setVisible(true);        // masque si
                                                       // nécessaire
    } else {
        recentFileActions[j]->setVisible(false);
    }
}
separatorAction->setVisible(!recentFiles.isEmpty());   // masque si
                                                       // nécessaire

Pour ouvrir le fichier :

QAction* action = qobject_cast(sender());
if (action)
    loadFile(action->data().toString());

2.3.3 Be able to use tool bars and status bars

Créer une barre d'outils :

fileToolBar = addToolBar(tr("&File"));
fileToolBar->addAction(saveAction);
fileToolBar->addSeparator();

Créer une barre de statuts. Peut contenir plusieurs widgets :

statusBar()->addWidget(locationLabel); // stretch = 0
statusBar()->addWidget(formulaLabel, 1); // stretch = 1

2.3.4 Understand the concept of Actions

Permet de rassembler dans une seule classe une même fonctionnalité, appelée depuis un menu ou une barre d'outils.

Créer une action :

newAction = new QAction(tr("&New"), this);
newAction->setIcon(QIcon(":/images/new.png"));
newAction->setShortcut(QKeySequence::New);
newAction->setStatusTip(tr("Create a new spreadsheet file"));
connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));

Raccourci clavier : Ctrl + N pour créer un nouveau par exemple

newAction->setShortcut(QKeySequence::New);
exitAction->setShortcut(tr("Ctrl+Q"));

Peut être cheakable :

showGridAction->setCheckable(true);
showGridAction->setChecked(spreadsheet->showGrid());

Pour créer un menu contextuel dans un QWidget :

spreadsheet->addAction(cutAction);
spreadsheet->addAction(copyAction);
spreadsheet->addAction(pasteAction);
spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);

Autre méthode : surcharger QWidget::contextMenuEvent(), créer un QMenu et appeler exec() dessus.

2.3.5 Know how to use QVariant to store data in Actions

QVariant : permet de stocker différents types de données. Par exemple avec recentFile :

recentFileActions[j]->setData(recentFiles[j]);   
loadFile(action->data().toString());

2.3.6 Understand the usage of scrolled areas

2.4 Settings

2.4.1 Know how to store application settings in different formats with the help of QSettings

Plateforme dépendant par défaut : registres sur windows, fichier texte sous linux, les Core Foundation Preferences API sous Mac OS X.

Pour créer un settings :

QSettings settings("Organisation name", "Application name");
settings.setValue("geometry", saveGeometry());
settings.beginGroup("findDialog");
settings.setValue("matchCase", caseCheckBox->isChecked());
settings.endGroup();

Pour les lire :

QSettings settings("Software Inc.", "Spreadsheet");
recentFiles = settings.value("recentFiles").toStringList();

2.4.2 Be aware of and be able to control the storage location of settings on different platforms

QSettings::QSettings(const QString & fileName, Format format, QObject * parent = 0)
QSettings::NativeFormat ou QSettings::IniFormat

2.5 Qt debugging aids

2.5.1 Be able to write debug messages

qDebug() << arg;   // nécessite #include 
qDebug("...", arg);
qDebug()     // QT_NO_DEBUG_OUTPUT 
qWarning()   // QT_NO_WARNING_OUTPUT QT_FATAL_WARNINGS 
qFatal()
qCritical()

qInstallMsgHandler :

void myMessageOutput(QtMsgType type, const char *msg)
 {
     switch (type) {
     case QtDebugMsg:
         fprintf(stderr, "Debug: %s\n", msg);
         break;
     }
 }
qInstallMsgHandler(myMessageOutput);

2.5.2 Understand the usage of asserts

QT_NO_DEBUG
Q_ASSERT(cond)
Q_ASSERT_X(cond, where, what)
Q_CHECK_PTR(ptr)

2.5.3 Be able to use GDB with Qt

2.5.4 Understand why event filters can be helpful for debugging

2.6 Writing your own widgets

2.6.1 Know when it is better to write a custom widget

En général, il faut :

class HexSpinBox : public QSpinBox
{
    Q_OBJECT
public:
    HexSpinBox(QWidget *parent = 0);
};

Contenu statique : pas besoin de redessiné ce qui était déjà visible lors d'un redimenssionnement, seule la nouvelle partie visible est a dessiner :

setAttribute(Qt::WA_StaticContents);

Le widget accepte le focus par clic ou tab

setFocusPolicy(Qt::StrongFocus);

2.6.2 Be able to re-implement event handler methods

2.6.3 Understand when to use signals

2.6.4 Be able to decide which internal variables should be made accessible

Utilisation de la macro Q_PROPERTY pour déclarer des variables et ses accesseurs, permet de rendre visible les propriétés dans Qt Designer :

class IconEditor : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
public:
    void setPenColor(const QColor &newColor);
    QColor penColor() const { return curColor; }
};

2.6.5 Understand the importance of clean constructors

3 Using Dialogs and Handling UI Layouts

3.1 Geometry management

3.1.1 Learn how to manipulate the geometry of a widget

3.1.2 Understand the concepts behind a layout manager in Qt

Taille préférée :

QSize QWidget::sizeHint() const;

Définie la politique pour la taille en fonction de sizeHint :

setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

choix possibles :

Fixed     // taille fixée à sizeHint
Minimum   // sizeHint est un minimum
Maximum   // sizeHint est un maximum
Preferred // sizeHint utilisé de préférence
Expanding // pas de préférence

Mettre à jour les tailles :

QWidget::updateGeometry();

Fixer la taille :

setFixedHeight(sizeHint().height());

QLabel de taille fixe :

locationLabel = new QLabel(" W999 ");
locationLabel->setAlignment(Qt::AlignHCenter);
locationLabel->setMinimumSize(locationLabel->sizeHint());

3.1.3 Know and understand the various layout managers

QVBoxLayout et QHBoxLayout, QGridLayout

Spacer → QSpacer ou addStretch();

QStackedLayout :

stackedLayout = new QStackedLayout;

QSplitter :

QSplitter splitter(Qt::Horizontal); // ou Qt::Vertical

pour sauvegarder les dimensions :

settings.setValue("mainSplitter", mainSplitter->saveState());
mainSplitter->restoreState(settings.value("mainSplitter").toByteArray());

QScrollArea :

QScrollArea scrollArea;

QDockWidget :

QDockWidget *shapesDockWidget = new QDockWidget(tr("Shapes"));
shapesDockWidget->setObjectName("shapesDockWidget");
shapesDockWidget->setWidget(treeWidget);
shapesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
addDockWidget(Qt::RightDockWidgetArea, shapesDockWidget);

QToolBar :

QToolBar *fontToolBar = new QToolBar(tr("Font"));
fontToolBar->setObjectName("fontToolBar");
fontToolBar->addWidget(familyComboBox);
fontToolBar->addAction(underlineAction);
fontToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
addToolBar(fontToolBar);

QMdiArea:

mdiArea = new QMdiArea;
setCentralWidget(mdiArea);

3.1.4 Learn how to use widgets with layout a managers

QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);

3.1.5 Be able to develop your own dialog with layouts

3.2 Standard dialogs

3.2.1 Know the various standard dialog types

Dialogue = permet de proposer aux utilisateurs des options et des choix et mettre de les modifier.

Dialogues standards

3.2.2 Understand the usage of standard dialogs

Fonctionnalités prêtes à l'usage.

3.2.3 Be able to use these dialogs

Création par appel de fonction statique :

int r = QMessageBox::warning(this, "Titre", "Message"),
     QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

Test de la réponse :

if (r == QMessageBox::Yes) { }
if (r == QMessageBox::Cancel) { }

Autres dialogue d'information :

Dialogue pour choisir un nom de fichier à ouvrir :

QString fileName = QFileDialog::getOpenFileName(
    this, 
    "Titre", 
    ".",                // répertoire par défaut
    "Files (*.xls)");   // filtre pour les fichiers

Dialogue pour choisir un nom de fichier à enregistrer :

QString fileName = QFileDialog::getSaveFileName(
    this,
    "Titre", 
    ".",                // répertoire par défaut
    "Files (*.xls)");   // filtre pour les fichiers

Dialogue « A propos » :

QMessageBox::about(this, "Titre", "Message"));

3.2.4 Understand how processing of events works with QProgressDialog

3.2.5 Understand the structure of wizards

QWizardPage *createIntroPage()
{
    QWizardPage *page = new QWizardPage;
    page->setTitle("Introduction");
    return page;
}
QWizard wizard;
wizard.addPage(createIntroPage());
wizard.show();

wizard()->setButtonText(QWizard::CustomButton1, tr("&Print"));
         wizard()->setOption(QWizard::HaveCustomButton1, true);
         connect(wizard(), SIGNAL(customButtonClicked(int)),
                 this, SLOT(printButtonClicked()));

Structure :

    A title.
    A subTitle.
    A set of pixmaps, which may or may not be honored, depending on the wizard's style:
        WatermarkPixmap (used by ClassicStyle and ModernStyle)
        BannerPixmap (used by ModernStyle)
        LogoPixmap (used by ClassicStyle and ModernStyle)
        BackgroundPixmap (used by MacStyle)

registerField("className*", classNameLineEdit);
     registerField("baseClass", baseClassLineEdit);
     registerField("qobjectMacro", qobjectMacroCheckBox);
QString className = field("className").toString();

setPage(Page_Intro, new IntroPage);
     setPage(Page_Evaluate, new EvaluatePage);
     setPage(Page_Register, new RegisterPage);
     setPage(Page_Details, new DetailsPage);
     setPage(Page_Conclusion, new ConclusionPage);

 int IntroPage::nextId() const
 {
     if (evaluateRadioButton->isChecked()) {
         return LicenseWizard::Page_Evaluate;
     } else {
         return LicenseWizard::Page_Register;
     }
 }

hasVisitedPage()
setStartId().

3.2.6 Be able to create your own wizards with pages

3.3 Creating your own (custom) dialogs

3.3.1 Learn how to subclass a QDialog

Dialogues dérivent de QDialog (qui hérite de QWidget)

class FindDialog : public QDialog
{
    Q_OBJECT
public:
    FindDialog(QWidget *parent = 0);
signals:
    void findNext(const QString &str, Qt::CaseSensitivity cs);
    void findPrevious(const QString &str, Qt::CaseSensitivity cs);
private slots:
    void findClicked();
    void enableFindButton(const QString &text);
private:
    QLabel *label;
    QLineEdit *lineEdit;
    QCheckBox *caseCheckBox;
    QCheckBox *backwardCheckBox;
    QPushButton *findButton;
    QPushButton *closeButton;
};

3.3.2 Understand the usage of buttons in a dialog

Boutons :

Conteneurs page unique :

Conteneurs pages multiples :

Vues :

Widgets d'affichage :

Widgets d'édition :

3.3.3 Be able to launch dialogs (not-) modal

Dialogue modal = reste en premier plan tan que affiché ; dialogue non modal : peut passer en second plan.

Pour afficher le dialogue non modal :

if (findDialog->isHidden()) {
    findDialog->show();
} else {
    findDialog->raise();
    findDialog->activateWindow();
}

Pour un dialogue modal :

GoToCellDialog dialog(this);
if (dialog.exec()) {
    QString str = dialog.lineEdit->text().toUpper();
}

La fonction exec() bloque le dialogue jusqu'à sa fermeture.

Connecter le bouton Ok au signal accept() et le bouton Cancel au signal reject() pour retourner QDialog::Accepted (true) ou QDialog::Rejected (false).

3.3.4 Know the deletion options for dialogs

3.3.5 Be able to create your own dialogs with user interactions

Dialogue changeant de forme :

3.4 Using Qt Designer and Qt Creator for UI development

3.4.1 Understand how Qt Designer can help in creating widgets

Créer graphiquement les dialogues et mettre en place les signaux et slots.

Mettre à jour plus facilement une interface utilisateur : on n'a besoin de changer que le fichier ui, le reste du code est mis à jour automatiquement pas qmake

3.4.2 Understand the concept of Qt Designer files

Génèrer un fichier xxx.ui (format xml décrivant l'interface) dans QtDesigner puis utiliser uic (user interface compiler) pour générer un fichier ui_xxx.h (déclaration des éléments de l'interface en C++) qui contient une classe Ui::xxx (propriété objectName du formulaire)

Accès aux widgets en fonction de leurs nom objectName

3.4.3 Be able to load Qt Designer code inside your code

Ajout de la déclaration :

#include "ui_gotocelldialog.h"

Ouvertue du dialogue :

Ui::GoToCellDialog ui;
QDialog *dialog = new QDialog;
ui.setupUi(dialog);
dialog->show();

Ui:: GoToCellDialog contient la déclaration des widgets utilisés plus la fonction setupUi qui initialise ces widgets dans le QWidget passé en paramètre et connecte automatiquement les signaux signalName aux slots on_objectName_signalName()

connect(
    lineEdit, SIGNAL(textChanged(const QString &)),
    this, SLOT(on_lineEdit_textChanged()));

Ajout de ce qui manque par héritage :

#include "ui_gotocelldialog.h"
class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
    Q_OBJECT
public:
    GoToCellDialog::GoToCellDialog(QWidget *parent) : QDialog(parent)
    {
        setupUi(this); // création des widgets
        ...
    }
};

3.4.4 Be able to connect Qt Designer elements with business functions

3.4.5 Know how to manage custom widgets in Qt Designer

Utilisation de la promotion :

Limites : pas accès aux propriétés Q_PROPERTY dans Qt Designer et affiché comme l'objet avant promotion

Utilisation des plugins :

fichier .pro

TEMPLATE     = lib
CONFIG      += designer plugin release
HEADERS      = ../iconeditor/iconeditor.h \
               iconeditorplugin.h
SOURCES      = ../iconeditor/iconeditor.cpp \
               iconeditorplugin.cpp
RESOURCES    = iconeditorplugin.qrc
DESTDIR      = $$[QT_INSTALL_PLUGINS]/designer

fichier .h

#include <QDesignerCustomWidgetInterface>
class IconEditorPlugin : public QObject,
                         public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
    IconEditorPlugin(QObject *parent = 0) : QObject(parent) {}
    QString name() const { return "IconEditor"; }
    QString includeFile() const { return "iconeditor.h"; }
    QString group() const { return tr("Image Manipulation Widgets"); }
    QIcon icon() const { return QIcon(":/images/iconeditor.png"); }
    QString toolTip() const { return tr("An icon editor widget"); }
    QString whatsThis() const { return tr("Tooltips..."); }
    bool isContainer() const { return false; }
    QWidget *createWidget(QWidget *parent) 
        { return new IconEditor(parent); }
};
Q_EXPORT_PLUGIN2(iconeditorplugin, IconEditorPlugin)

3.4.6 Be able to load Qt Designer files in runtime

Dialogue dynamique. Chargement avec QUiLoader. Dans le .pro :

CONFIG += uitools

QUiLoader uiLoader;
QFile file("sortdialog.ui");
QWidget *sortDialog = uiLoader.load(&file);

Accès aux widgets du dialogue :

QComboBox* primaryColumnCombo = 
    sortDialog->findChild("primaryColumnCombo");
if (primaryColumnCombo) {
    ...
}

ou avec la fonction globale qFindChild() pour MSVC 6

3.4.7 Be able to write a dialog using the Qt Designer tool

Hum...

4 Strings, Resources and Help

4.1 Strings, URLs and regular expressions

4.1.1 Learn how to create strings with QString

Création :

QString str = "User: ";
QString str("User: ");

Concaténation. Avec l'opérateur += :

str += userName + "\n";

Avec la fonction append() :

str = "User: ";
str.append(userName);
str.append("\n");

Avec la fonction sprintf, syntaxe identique à std::sprintf :

str.sprintf("%s %.1f%%", "perfect competition", 100.0);

Avec la fonction arg() (method chaining)

str = QString("%1 %2 (%3s-%4s)")
    .arg("permissive").arg("society").arg(1950).arg(1970);

4.1.2 Know how to extract data from strings

Extraction de sous chaîne :

QString str = "polluter pays principle";
qDebug() << str.mid(9, 4);   // affiche "pays"
qDebug() << str.mid(9);      // affiche "pays principle"
qDebug() << str.left(8);     // affiche "polluter"
qDebug() << str.right(9);    // affiche "principle"

Remplacement :

QString str = "a cloudy day";
str.replace(2, 6, "sunny");   // "a sunny day";
str.remove(2, 6);             // "a  day";
str.insert(2, "sunny");       // "a sunny day";
str.replace("&", "&");

QString str = "   BOB \t THE \nDOG \n";
qDebug() << str.trimmed();       // "BOB \t THE \nDOG \n"
qDebug() << str.simplified();    // "BOB THE DOG"

Split() :

QString str = "polluter pays principle";
QStringList words = str.split(" "); // "polluter", "pays" et "principle"
words.sort();
str = words.join("\n");    // "pays\npolluter\nprinciple"

4.1.3 Know how to test strings

Localiser une sous-chaîne. Retourne -1 en cas d'erreur :

QString str = "the middle bit";
int i = str.indexOf("middle");   // retourne 4
url.startsWith("http:")          // teste le début
url.endsWith(".png"))             // teste la fin

Comparaison :

if (fileName == "readme.txt") {}
localeAwareCompare() pour comparer après traduction
toUpper()
toLower()

Test si vide :

str.isEmpty()
str.length() == 0

4.1.4 Know useful utility functions in QString

Fonction arg() permet de remplacer des placeholders par des variables (technique de chaînage) :

QString("%1 - %2").arg(intValue).arg(stringValue);

Convertir en entier :

str.mid(1).toInt()
str[0].unicode() - 'A'

Convertir nombre en QString :

QString::number(10);
QString::number(10, 16); // convesion hexadécimale

Conversion en nombre :

bool ok;
return text.toInt(&ok, 16); // hexadécimal

Conversion en char* :

str += " (1870)"; // automatique
QString::fromAscii()
QString::fromLatin1()
str.toAscii().data()            // str.toAscii() retourne un QByteArray 
str.toAscii().constData ()      // idem macro qPrintable()
str.toLatin1 ().data()
str.toLatin1 ().constData()

QByteArray, similaire à QString, avec des fonctions left(), right(), mid(), toLower(), toUpper(), trimmed() et simplified(). Stockage de données brutes 8 bits.

4.1.5 Know the basics about Qt support of translation of strings into other languages

Prise en charge de l'internationnal :

Utilisation de tr(), lupdate et ltranslate

str[0] = 'A';
str[0] = QChar(0x41);
str[0] = 'Ñ';
str[0] = QChar(0xD1);
str[0] = QChar(0x03A3);    // lettre grec sigma
str[0] = QChar(0x20AC);    // €

Pour entrer du texte dans une autre langue :

QTextCodec::setCodecForTr(QTextCodec::codecForName("EUC-JP"));

QChar :

isPrint(), isPunct(), isSpace(), isMark(), isLetter(), isNumber(), isLetterOrNumber(), isDigit(), isSymbol(), isLower() et isUpper()

Pour la traduction automatique :

TRANSLATIONS = spreadsheet_de.ts spreadsheet_fr.ts

QObject::tr(sourceText, comment)
QCoreApplication::translate(Context, sourceText, comment)

lrelease -verbose spreadsheet.pro

QTranslator appTranslator;
appTranslator.load("myapp_" + QLocale::system().name(), qmPath);
app.installTranslator(&appTranslator);

QLocal permet de récupérer les préférences utilisateurs pour l'encodage :

fr                // français
fr_CA             // français canadien
fr_CA.ISO8859-15  // français canadian avec ISO 8859-15

Pour les classes ne possédant pas tr(), utiliser la macro :

Q_DECLARE_TR_FUNCTIONS()

Avec des arguments :

// WRONG
statusBar()->showMessage(tr("Host " + hostName + " found"));
// OK
statusBar()->showMessage(tr("Host %1 found").arg(hostName));

Avec QT_TR_NOOP macro ou QT_TRANSLATE_NOOP() avec contexte :

static const char * const flowers[] = {
    QT_TR_NOOP("Medium Stem Pink Roses"),
    QT_TR_NOOP("One Dozen Boxed Roses"),
    QT_TR_NOOP("Calypso Orchid"),
    QT_TR_NOOP("Dried Red Rose Bouquet"),
    QT_TR_NOOP("Mixed Peonies Bouquet"),
    0
};
for (int i = 0; flowers[i]; ++i)
    comboBox->addItem(tr(flowers[i]));

Forcer l'utilisation de tr() ou QLatin1String() pour éviter les oublis :

DEFINES += QT_NO_CAST_FROM_ASCII

Pour les langues qui se lisent de droite à gauche (mais le fichier de traduction peut contenir un marqueur LTR qui fait la même chose automatiquement) :

QApplication::setLayoutDirection(Qt::RightToLeft)
QApplication::isRightToLeft()

Egalement possible de mettre les fichiers de traductions dans les ressources :



    translations/myapp_de.qm
    translations/myapp_fr.qm
    translations/myapp_zh.qm
    translations/qt_de.qm
    translations/qt_fr.qm
    translations/qt_zh.qm


RESOURCES += myapp.qrc
QString qmPath = ":/translations" ;

Le fichier ressource peut contenir différentes lanagues :


    italic.png


    cursivo.png


    kursiv.png

Fonctions utiles :

QString::localeAwareCompare()  // pour comparer les chaînes après traduction
toString()                     // pour convertir en chaîne

4.1.6 Understand QUrl and the components of an URL

setScheme(), setUserName(), setPassword(), setHost(), setPort(), setPath(), setEncodedQuery() and setFragment(

4.1.7 Learn how to use QRegExp for regular expression and shell globing

1 lettre majuscule ou minuscule + 1 chiffre enter 1 et 9 + 0 à 2 chiffres entre 0 et 9 :

[A-Za-z][1-9][0-9]{0,2}

Validation hexadécimal (entre 0x00 et 0xFF) :

[0-9A-Fa-f]{1,8}

4.2 Validating Input

4.2.1 Be able to set input masks on line edits

QIntValidator, QDoubleValidator et QRegExpValidator

Validation hexadécimal (entre 0x00 et 0xFF) :

QRegExpValidator *validator;
validator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,8}"), this);

Résulat retourné :

Invalid : le texte ne correspond pas
Intermediate : peut être une partie d'un texte acceptable
Acceptable : le texte correspond

4.2.2 Understand the format for input masks

4.2.3 Know that QCompleter offer pop-up completion

QStringList wordList;
 wordList << "alpha" << "omega" << "omicron" << "zeta";

 QLineEdit *lineEdit = new QLineEdit(this);

 QCompleter *completer = new QCompleter(wordList, this);
 completer->setCaseSensitivity(Qt::CaseInsensitive);
 lineEdit->setCompleter(completer);

QCompleter *completer = new QCompleter(this);
 completer->setModel(new QDirModel(completer));
 lineEdit->setCompleter(completer);

4.3 Resources

4.3.1 Understand the advantage of resource files over ordinary files

Pour ajouter des images dans une application :

4.3.2 Learn how to add resource files to a project

Ajotuer un fichier de ressources dans le .pro :

RESOURCES = spreadsheet.qrc

Le fichier de ressources est un simple fichier XML (qui peut être créé automatiquement par Qt Creator)



    images/icon.png
    ...
    images/gotocell.png

Pour les utiliser :

QImage(":/images/icon.png");

4.3.3 Know the resource XML file structure

4.3.4 Be able to access resources from the application

4.3.5 Know that resource files can be localized

4.3.6 Learn how to load a resource file dynamically

4.4 Help system

4.4.1 Know the different possibilities to provide help

findButton->setToolTip(tr("Find next"));

newAction->setStatusTip(tr("Create a new document"));

dialog->setWhatsThis(tr(""
                        " The meaning of the Source field depends "
                        "on the Type field:"
                        "

"

                        "

  • Books have a Publisher"

                            "

  • Articles have a Journal name with "

                            "volume and issue number"
                            "

  • Theses have an Institution name "

                            "and a Department name"
                            "

    "));

    void MainWindow::help()
    {
        QUrl url(directoryOf("doc").absoluteFilePath("index.html"));
        url.setScheme("file");
        url.setFragment("editing");
        QDesktopServices::openUrl(url);
    }

    CONFIG += assistant

    QAssistantClient* assistant = 0;
    if (!assistant)
        QAssistantClient* assistant = new QAssistantClient("");
    assistant->showPage(path);

    4.4.2 Understand the concept of the system tray icon

    4.4.3 Learn how to support dynamic help

    5 Container and Other non-GUI Classes

    5.1 Container classes

    5.1.1 Understand the concept of containers

    Avantages :

    5.1.2 Know the difference between Java and STL styled APIs

    Iterateurs Java plus facilement utilisable et iterateurs STL plus puissants et compatibles avec les algorithmes de la STL. 2 types à chaque fois : mutable ou non.

    Itérateurs Java :

    QVectorIterator, QLinkedListIterator et QListIterator
    QMutableVectorIterator, QMutableLinkedListIterator et
        QMutableListIterator

    Modifications :

    i.remove();
    i.setValue(10);
    i.insert(10);

    Iterateurs STL

    C::iterator
    C::const_iterator

    Pour éviter la copie implicite, utiliser de préférence at(), constBegin(), constEdn() et const_iterator

    const T & at ( int i ) const
    iterator begin () 
    const_iterator begin () const
    const_iterator constBegin ()
    iterator end () 
    const_iterator end () const
    const_iterator constEnd () const
    T & operator[] ( int i ) 
    const T & operator[] ( int i ) const

    5.1.3 Know the different container types

    Conteneurs séquentiels : QVector, QList, QLinkedList ; conteneurs associatifs : QMap, QHash

    QVector vect(3);
    vect[0] = 1.0;
    vect.append(1.0);
    vect << 1.0 << 0.540302 << -0.416147;

    QLinkedList list;
    list.append("Clash");
    QLinkedList::iterator i = list.find("Ramones");
    list.insert(i, "Tote Hosen");

    QMap : ordonné

    QMap map;
    map.insert("eins", 1);
    map["eins"] = 1;
    int val = map.value("dreiundzwanzig");

    keys() : retourne la QList des clés, values() retourne la QList des valeurs.

    Clés multiples : avec insertMulti() ou QMultiMap :

    QMultiMap multiMap;
    multiMap.insert(1, "one");
    QList vals = multiMap.values(1);

    QHash : associatif et non ordonné. K doit avoir un opérateur == et être supporté par la fonction globale qHash(). Par défaut : les types entiers, les pointeurs, QChar, QString et QByteArray.

    Clés multiples : avec insertMulti() ou QMultiHash.

    QCache et QSet proche de QHash.

    Autres : QPair, QBitArray, QVarLengthArray (version bas level de QVector, avec pré-allocation et sans COW)

    5.1.4 Be able to identify the best suited container type for your needs

    QList :

    5.1.5 Know the requirements for a type to be storable in a container

    T doit être :

    QList > list;

    Pour la clé, il faut en plus que soit définit l'opérateur <

    5.1.6 Be able to iterate of containers

    Itérateur Java :

    QList list;
    QListIterator i(list);
    while (i.hasNext()) {
        do_something(i.next());
    }

    Reverse :

    QListIterator i(list);
    i.toBack();
    while (i.hasPrevious()) {
        do_something(i.previous());
    }

    Itérateurs STL :

    QList::iterator i = list.begin();
    while (i != list.end()) {
        *i = qAbs(*i);
        ++i;
    }

    5.1.7 Know the difference between standard and mutable iterators

    Mutable : permet de modifier les valeurs ; Standard : ne le permet pas

    5.1.8 Be able to use the for each keyword on containers

    Conteneurs séquentiels :

    QLinkedList list;
    foreach (Movie movie, list) {
        if (movie.title() == "Citizen Kane") {
            std::cout << "Found Citizen Kane" << std::endl;
            break;
        }
    }

    Conteneurs associatifs :

    QMultiMap map;
    ...
    foreach (QString key, map.keys()) {
        foreach (int value, map.values(key)) {
            do_something(key, value);
        }
    }

    5.1.9 Know the utility container algorithms offered by Qt

    Algorihms : qSort(), qBinaryFind()

    class SpreadsheetCompare
    {
    public:
        bool operator()(const QStringList &row1,
                        const QStringList &row2) const;
        enum { KeyCount = 3 };
        int keys[KeyCount];
        bool ascending[KeyCount];
    };

    QList rows;
    qStableSort(rows.begin(), rows.end(), compare);

    Conteneur associatif :

    QMapIterator i(map);
    while (i.hasNext()) {
        i.next();
        if (i.value() > largestValue) {
            largestKey = i.key();
            largestValue = i.value();
        }
    }

    qFind(). Complexité linéaire :

    QStringList list;
    list << "Emma" << "Karl" << "James" << "Mariette";
    QStringList::iterator j = qFind(list.begin(), list.end(), "Petra");

    qBinaryFind() : idem que qFind() sur liste triée. Plus rapide que qFind()

    qFill() :

    QLinkedList list(10);
    qFill(list.begin(), list.end(), 1009);

    qCopy() :

    QVector vect(list.count());
    qCopy(list.begin(), list.end(), vect.begin());

    qSort() :

    qSort(list.begin(), list.end());

    Utilise par défaut l'opérateur < (tri croissant). Pour tri décroissant :

    qSort(list.begin(), list.end(), qGreater());

    Avec un opérateur défini par l'utilisateur :

    bool insensitiveLessThan(const QString &str1, const QString &str2)
    {
        return str1.toLower() < str2.toLower();
    }
    qSort(list.begin(), list.end(), insensitiveLessThan);

    qStableSort() : idem que qSort() mais garentie que les éléments égaux (selon le critère de tri) sont conservés dans le même ordre.

    QDeleteAll() : appelle delete sur tous les éléments d'un conteneur :

    qDeleteAll(list);
    list.clear();

    Autres :

    qSwap()
    qMax()
    qMin()
    qCopyBackward()
    qEqual()

    5.1.10 Understand the concept of implicit shared classes

    Utilisation de l'idom COW (copy-on-write), permet de passer un conteneur par copie sans surcoût de copie,

    Lors d'un accès en lecture (fonctions const) : pas de copie, par exemple avec at() ou value()

    Lors d'un accès en écriture (fonctions non const) : copie des données

    Utilisation d'un compteur interne :

    QString str1 = "Humpty";                      // size1 = 1
    QString str2 = str1; // pas de copie cachée   // size1 = 2
    str2[0] = 'D'; // copie lors de l'écriture    // size1 = 1 ; size2 = 1
    str2.truncate(4); // pas de copie             // size1 = 1 ; size2 = 1
    str1 = str2; // suppression de "Humpty"       // size1 = 0 ; size2 = 2

    5.2 QVariant

    5.2.1 Understand the central role of QVariant for many other container classes

    Stockage de données différentes dans une même structure : par conversion en QString/QByteArray ou avec QVariant (plus type safe).

    Structures complexes avec les map, mais peut efficace et lisible :

    QMap pearMap;
    pearMap["Standard"] = 1.95;
    pearMap["Organic"] = 2.25;

    QMap fruitMap;
    fruitMap["Orange"] = 2.10;
    fruitMap["Pineapple"] = 3.85;
    fruitMap["Pear"] = pearMap;

    Avec QtGui, besoin d'utiliser la fonction template :

    QIcon icon("open.png");
    QVariant variant = icon;
    QIcon icon = variant.value();

    5.2.2 Know which types are supported by default and be able to store new data types

    Types par défaut

    Types utilisateurs :

    Q_DECLARE_METATYPE(BusinessCard)

    BusinessCard businessCard;
    QVariant variant = QVariant::fromValue(businessCard);
    ...
    if (variant.canConvert()) {
        BusinessCard card = variant.value();
        ...
    }

    Pour MSVC6 : utiliser qVariantFromValue(), qVariantValue() et qVariantCanConvert()

    Déclaration des opérateurs << et >> pour QDataStream :

    qRegisterMetaTypeStreamOperators("BusinessCard");

    5.3 QSignalMapper

    5.3.1 Understand the concept of QSignalMapper

    5.3.2 Be able to use QSignalMapper

    5.4 QTimer

    5.4.1 Understand the concept of QTimer

    5.4.2 Be able to use QTimer

    5.4.3 Understand the different operation modes of timers

    5.5 Generic IO, files and printing

    QIODevice : abstraction générale pour écrire et lire sur différentes sources (fichier, réseau, buffer, etc.). Classes dérivées : QFile (fichier), QTemporaryFile (fichier temporaire), QBuffer (tableau d'octets), QProcess (communication inter-process), QTcpSocket (réseau TCP), QUdpSocket (réseau UDP), QSslSocket (réseau chiffré). Les 3 premiers sont en accès aléatoire (on peut lire n'importe où) alors que les 4 autres sont séquentiels (on ne peut lire qu'une fois, en partant du premier octet et en lecture séquentielle).

    Lecture directe avec peek() et ungetChar().

    5.5.1 Understand the usage of QFile

    Permet d'ouvrir un fichier en lecture ou écriture, en mode texte ou binaire.

    Ouverture en écriture :

    QFile file(fileName);
     if (!file.open(QIODevice::WriteOnly)) {
    }

    Ouverture en lecture :

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) { 
    }

    5.5.2 Be able to identify the difference between QDataStream and QTextStream

    Classes haut-niveau, qui permet de lire et écrire dans n'importe quelle classe dérivant de QIODevice, en étant indépendant de la plateforme (sérialisation : encodage, endianness). QDataStream permet de lire des données binaires et QTextStream des données textes.

    Pour ouvrir un flux :

    QDataStream out(&file);
    out.setVersion(QDataStream::Qt_4_3); // permet de spécifier la version

    écriture (avec cast d'un int dans un type entier de Qt) :

    out << quint32(MagicNumber);

    lecture :

    in >> magic;

    Pour les types entiers, caster vers un type safe :

    qint8, quint8, qint16, quint16, qint32, quint32, qint64 ou quint64

    Pour la gestion de la version, il est également possible de coder la version en début de message :

    // écriture
    QDataStream out(&file);
    out << quint16(out.version());

    // lecture
    quint16 version;
    QDataStream in(&file);
    in >> version;
    if (version > in.version()) {
        std::cerr << "Version trop récente" << std::endl;
        return false;
    }
    in.setVersion(streamVersion);

    Encodage

    Pour les types définis par l'utilisateur, possibilité de définir les opérateurs << et >> :

    QDataStream &operator<< (QDataStream &out, const T& t)
    {
        out << (...);
        return out;
    }

    QDataStream &operator>> (QDataStream &in, T& t)
    {
        QString x;
        in >> x;
        t = T(x);
        return in;
    }

    En fournissant ces opérateurs, il est alors possible d'utiliser directement les conteneurs :

    QList tt ;
    out << tt;

    QList tt;
    in >> tt;

    Il est possible d'utiliser également qRegisterMetaTypeStreamOperators() pour pouvoir utiliser les types personnalisés avec QVariant et QSettings.

    Qt fournit deux classes supplémentaires pour la gestion des fichiers : QDir pour gérer les répertoires, et QFileInfo pour obtenir des informations sur les fichiers.

    5.5.4 Be able to read/write from/to files using Qt

    Les types de bases (bool, float, double, etc.), de nombreuses classes de Qt (QString, QColor, etc.), les conteneurs de Qt (QVector, QList, etc.) sont utilisable directement avec QDataStream et QTextStream. Le type int n'est pas utilisable directement, puisque sont implémentation est dépendant de la plateforme. A la place, il faut utiliser l'un des types d'entitier de Qt : quint32 (« q » pour Qt, « u » pour unsigned, « 32 » pour la taille en bits).

    Possibiltié de lire ou écrire la totalité d'un fichier avec QFile::write() et QFile::readAll().

    Pour tester si une erreur est survenu : error() retourne QFile::NoError.

    5.5.5 Understand the issue of text encoding and files

    QTextStream par défaut utilise local 8-bits encoding (QTextCodec::codecForLocale())

    QTextStream in(&file);
    in.setCodec("UTF-16");
    in.setGenerateByteOrderMark(true);
    in.setCodec("ISO 8859-1");

    5.5.6 Understand when better to use QDataStream instead of QTextStream

    5.5.7 Be able to print a widget or text document in PDF format using QPrinter

    setOrientation(QPrinter::Portrait ou QPrinter::Landscape)
    setPaperSize(QPrinter::A4, QPrinter::Letter, QPrinter::Custom, etc.)
    setResolution(int dpi)
    setFullPage(bool)
    setCopyCount(int)
    setOutputFormat(QPrinter::NativeFormat, PdfFormat ou PostScriptFormat)

    Exemple&nbsp;:

    QPrinter printer;
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName("/foobar/nonwritable.pdf");
    QPainter painter;
    if (!painter.begin(&printer)) { // failed to open file
         qWarning("failed to open file, is it writable?");
         return 1;
    }
    painter.drawText(10, 10, "Test");
    if (! printer.newPage()) {
         qWarning("failed in flushing page to disk, disk full?");
         return 1;
    }
    painter.drawText(10, 10, "Test 2");
    painter.end();

    6 Références

    6.1 Qt Essentials Curriculum Block

    6.2 Documentation officielle de Qt 4

    6.3 C++ GUI Programming with Qt 4

    6.4 Foundations of Qt Development

    6.5 An Introduction to Design Patterns in C++ with Qt 4

    6.6 The Book of Qt 4: The Art of Building Qt Applications

    6.7 Vidéos

    6.8 Qt Training

    6.9 Qt Developer Network Wiki

    6.10 Tutoriels de la rubrique Qt de Developpez.com