Introduction à Qt (Prononcer «cute») I. INSTALLATION... 3 1. SOUS WINDOWS... 3 Avec Visual Studio 2013... 4 2. SOUS MAC OSX... 7 II. RAPIDE PRESENTATION DE QT CREATOR ET ASTUCES... 8 1. INTERFACE ET BARRES D OUTILS... 8 2. LA DOCUMENTATION QT... 12 3. *.PRO ET QMAKE... 12 4. STRUCTURE D UN PROJET AVEC QT CREATOR... 13 5. AUTRES ASTUCES... 13 III. BASES... 14 1. TYPES... 14 2. VARIABLE... 14 3. TABLEAU... 14 4. CONTENEUR... 14 5. STRUCTURES DE CONTROLE... 15 6. FONCTIONS... 15 7. POINTEUR... 16 8. STRUCTURE... 16 9. ORIENTE OBJET... 17 a. Header (*.h)... 18 b. Implémentation (*.cpp)... 18 c. Utilisation... 19 d. Static... 20 e. Héritage... 20 f. Virtual... 20 g. Namespaces... 21 10. SIGNALS/SLOTS... 21 a. Avec Qt Designer... 22 b. Aller au slot (génération de code)... 23 c. Par code... 24 11. EDITEUR D ACTIONS... 26 12. BASES DE DONNEES (QTSQL MODULE)... 27 a. Connexion... 27 b. Requête simple... 27 c. Avec paramètre... 28 d. Transactions... 28 13. LISTE BASEE SUR UN MODEL OU ITEM... 28 14. LAYOUTS... 29 15. FICHIER DE RESSOURCES... 29 16. CREER DES WIDGETS... 30 a. Widget... 30 b. Dialog /boite de dialogue personnalisée... 31 17. DIALOG... 32 18. FEUILLE DE STYLE... 32 19. LINGUIST TRANSLATIONS... 33
IV. QT QUICK... 34 1. CRÉATION D UN PROJET QT QUICK... 34
http://qt-project.org/ La documentation Qt Qt est un Framework de développement d UI Cross-platform Plateformes supportées Development tools QtModules : o o o o o o o o o o o Core Gui WebKit Scripting QML Qt Quick Multimedia Database XML Networking Unit testing On peut utiliser Qt Widgets ou Qt Quick pour créer des interfaces utilisateur Comparaison Qt Widgets : - Mature - Uniquement C++ - Native look and feel Qt Quick : - Meilleure séparation logic/view - Data binding - Animations Ce document focus Qt, il ne traite donc pas de toutes les bases C++. C est avant tout un aidemémoire qui s enrichira petit à petit. I. Installation Il existe une version open source (Community) et des versions payantes de Qt. http://www.qt.io/download/ 1. Sous Windows Plusieurs versions disponibles : «Online», 32-bit, 64-bit, compilé avec MinGW, ou Visual Studio (il faudra alors installer Debugging Tools for Windows). On développera ses programmes avec Qt Creator. Il existe également un addin pour Visual Studio 2013 (et 2012).
Avec Visual Studio 2013 Télécharger l add-in pour Visual Studio Configurer «Qt Versions» Menu Qt5 QT Options Rechercher le dossier de qmake.exe et donner un nom de version.
Templates disponibles dans l onglet «Qt5 Projects» Attention de bien configurer la cible si besoin. Et donner une «Qt version» au projet (clic droit sur projet > Qt Project settings)
On peut définir les modules utilisés dans le projet à la création du projet ou depuis Qt Project Settings Utilisation de QT Designer avec Visual Studio Ajouter un include au fichier généré avec le designer (Ex #include "ui_mainwindow.h") dans le header (Ex mainwindow.h) s il n est pas présent pour avoir accès aux widgets ajoutés.
Structure d un projet avec Visual Studio Formulaires éditables avec Qt Designer, on peut également les ouvrir avec un éditeur XML Fichiers générés. On peut voir également un fichier généré avec Qt Designer (ui_mainwindow.h) Headers (*.h) Fichiers de Ressources Fichiers *.cpp et main du projet 2. Sous MAC OSX Il faut installer XCode dans un premier temps.
II. Rapide Présentation de Qt Creator et Astuces 1. Interface et barres d outils On peut switch facilement entre les boutons avec les raccourcis Ctrl+1, Ctrl+2 Ctrl+7 Le bouton accueil permet d ouvrir ou créer un projet Qt mais également des exemples de code. Il y a également un onglet tutoriels (vidéo). Le bouton Editer permet de basculer vers le projet. Affiche également le XML d un formulaire (QMainWindow par ex) si celui-ci était ouvert avec QT Designer.
Le bouton Design correspond à la vue permettant d éditer un formulaire avec Qt Designer Le bouton Debug permettant de switch vers une interface adaptée au débogage. Le bouton Projets permet de régler les différents propriétés du ou des projets ouverts.
Le bouton Analyse permet de profiler l application Le bouton Help affiche la documentation (Qt Creator Manual) Menu Outils > Options Plugins installés Menu Aide > A propos des plug-ins
- Le premier bouton permet de sélectionner le projet actif ainsi que le mode debug ou release - Les boutons ensuite servent à : exécuter l application, déboguer, compiler. Il faut d abord compiler l application avant de l exécuter. Raccourcis Build : Ctrl + B Debug : F5.. pas à pas F10, F11 Run : Ctrl + R - Premier bouton pour éditer le formulaire, les widgets - Second bouton pour éditer les signals et slots - Puis édition buddies, édition tab index - Les boutons suivants permettent de disposer verticalement, horizontalement, espacer, positionner dans une grille, redimensionner des widgets sélectionnés
On peut également mettre en page les widgets sélectionnés depuis le menu contextuel 2. La documentation Qt Il suffit de presser F1 sur un mot-clé pour afficher la documentation directement dans l éditeur. 3. *.pro et qmake Il faudra parfois éditer le fichier *.pro du projet (c est indiqué dans la documentation) Ex : si on a besoin d ajouter QT += widgets Il faudra ensuite «Exécuter qmake» avant de recompiler son application
4. Structure d un projet avec Qt Creator Le fichier *.pro du projet.il faudra exécuter qmake après édition Headers (*.h) Fichiers *.cpp et main du projet Formulaires éditables avec Qt Designer 5. Autres astuces Indenter le code sélectionné Ctrl+i Mettre en commentaire le texte sélectionné : Ctrl + / du pavé numérique Scinder les fenêtres (verticalement, horizontalement) ou menu Fenêtre Split/ Split side by side. Très utile par exemple pour avoir le header et l implémentation ouverts en même temps
III. 1. Types bool char Short int Unisgned int long float double Bases un entier positif QString (au lieu de std ::string) Privilégier les classes de Qt 2. Variable Initialisation TYPE nom(valeur) ; Affectation Nom = valeur Constante Ex : int const maconstante (10); Cast / Conversion TYPE nom = (TYPE) variable ; Ex conversion d un int en QString QString result = QString::number(i) Cycle de vie et gestion de la mémoire «Automatique» (dans un bloc de code), dynamique (utilisation de new et delete), statique (static) 3. Tableau Initialisation TYPE nom [taille] ; Ex : Int montableau[9] ; Affectation Nom[position] = valeur Ex : montableau[0] = 10 ; 4. Conteneur Vector (privilégier QVector avec Qt) (Faire un include de QVector) Initialisation QVector<TYPE> nom (taille) ; Ex : QVector<Int> monvector[9] ; Ajout Il existe plusieurs méthodes pour ajouter, insérer, etc. des éléments monvector.push_back(100) ;
+ QList/QLinkedList, QStack/QQueue,QMap (dictionnaires)/qmultimap, etc. Documentation 5. Structures de contrôle if if (mavariable == 0) else if (mavariable == 1) Else switch switch (nbenfants) case 0: // break; default: break; while while (mavariable < 0) for for (int i(0) ; i< 10 ; i++) Sorte de «foreach» For(Type item :items) Ex : for(category category : categories) 6. fonctions Méthode Function Void mamethode() Int mafonction() return 1 ; Prototype Sert à déclarer une fonction (sans son corps) pour qu elle puisse être utilisée avant qu elle soit définie. Ex : #include <QCoreApplication> //prototype de fonction void mafonction(); int main(int argc, char *argv[]) QCoreApplication a(argc, argv); //utilisation mafonction(); return a.exec(); //la fonction void mafonction()
Passage de paramètres : - «normal» les paramètres reçus sont des copies, seules les copies sont modifiées. int mafonction(int monparametre); Avec valeur par défaut pour paramètres int mafonction(int monparametre=0); - En tant que pointeur. Ex : Void mamethode(int *monparametre) - Par référence (pour reporter les changements apportés). Ex : Void mamethode(int &monparametre) 7. Pointeur Obtenir l adresse mémoire d une variable Le pointeur est de type int * peut être placé indifféremment à côté de int, de la variable ou entre les deux & pour obtenir l adresse (un int) de la variable Afficher l adresse mémoire Afficher la valeur correspondante de la variable de base à partir du pointeur Exemple int *monpointeur = &nomvariable ; monpointeur *monpointeur #include <QCoreApplication> #include <iostream> using namespace std; int main(int argc, char *argv[]) QCoreApplication a(argc, argv); int age = 20; int *address = &age; cout << "age : " << age << endl; // 20 cout << "address : " << address << endl; // addresse mêmoire cout << "*address : " << *address << endl; // 20 return a.exec(); 8. Structure Les membres d une structure sont par défaut public // définition struct Etudiant QString Name; void SayHello(); ; // implémentation void Etudiant::SayHello()
Utilisation (dans main) Etudiant etudiant; etudiant.name = "Patrick"; etudiant.sayhello(); 9. Orienté Objet On a une définition de la classe (dans un header *.h) et une implémentation (des constructeurs, méthodes, etc.). L implémentation n est pas nécessairement dans un fichier séparé mais le sera souvent (dans un fichier *.cpp avec un include vers le fichier *.h implémenté) Pour utiliser la classe on fera un include du header (*.h), quasiment jamais d un fichier *.cpp. Ajout d une classe... créera un fichier *h et le fichier *.cpp correspondant (Sur la solution Ajouter nouveau C++ class) Exemple création d une classe Person
a. Header (*.h) Plusieurs choses à observer - Pour éviter d avoir des doublons de la classe lorsque l on inclut celle-ci dans plusieurs fichiers du projet #ifndef PERSON_H #define PERSON_H #endif // PERSON_H Avec Visual C++ on peut utiliser Pragma (mais pas portable) - On utilise #include pour inclure des classes utilisées - On a différentes portées possibles pour les membres (public, private, protected) - Le constructeur est déclaré avec le nom de la classe (sans type). On peut surcharger le constructeur, on peut se dispenser de donner un nom aux variables dans la déclaration. Il est possible également de donner des valeurs par défaut Ex : Person(int id=0,qstring name=""); - Le destructeur est déclaré avec ~ - On n initialise pas les variables, celles-ci le seront dans le constructeur Fichier *.h (person.h) #ifndef PERSON_H #define PERSON_H #include <QString> class Person public: Person(); Person(int,QString); ~Person(); void SayHello(); private: int Id; QString Name; ; #endif // PERSON_H b. Implémentation (*.cpp) Fichier *.cpp (person.cpp) - On inclut le header que l on implémente #include "person.h" - On inclut également les classes utilisées (exemple ici isostream pour la méthode cout, on fait également un using namespace ici pour éviter d avoir à taper std ::cout) - Les classes incluses dans le header n ont pas besoin d être répétées - Constructeur : on définit les valeurs Person::Person():Id(0),Name("")
Autre usage on peut utiliser this pour pointer précisément les membres de la classe - Enfin dans la méthode on convertit la variable qui est de type QString pour qu elle puisse être affichée (string) #include "person.h" #include <iostream> using namespace std; // constructeurs Person::Person():Id(0),Name("") Person::Person(int id, QString name) this->id=id; this->name=name; // destructeur Person::~Person() // méthodes void Person::SayHello() cout << "Hello " << Name.toStdString() << endl; Note : (un peu comme pour les prototypes de fonction) on peut déclarer une classe avant qu elle soit définie. Ex : class Person ; c. Utilisation main.cpp - Il n y a qu une seule méthode main dans un programme C++ c est la méthode exécutée au lancement du programme. - On inclut le header de la classe (ici person.h) pour pouvoir l utiliser - On initialise alors une personne et appelle la méthode SayHello #include <QCoreApplication> #include "person.h" int main(int argc, char *argv[]) QCoreApplication a(argc, argv); Person marie(1,"marie"); marie.sayhello(); return a.exec();
d. Static Dans le header class Person public: static void MethodeStatic(); ; Dans l implémentation Ne pas répéter «static» void Person::MethodeStatic() Utilisation (dans main) Person::MethodeStatic(); e. Héritage class Etudiant : public Person ; L héritage multiple est possible. On peut utiliser la portée protected dans la classe de base pour les membres accessibles. f. Virtual Utiliser le mot clé virtual devant une méthode de classe de base qui devra être définie par les classes dérivées (Code allégé pour la clarté) Classe de base class Person public: virtual void MethodeVirtual(); ;
Classe dérivée On retire le mot virtual class Etudiant : public Person public: void MethodeVirtual(); ; Implémentation de la classe dérivée #include "etudiant.h" void Person::MethodeVirtual() g. Namespaces Création d un Namespace // création d un namespace namespace MonNamespace class MaClasse; // définition de la classe class MaClasse public: void DoSomething(); ; // implémentation void MaClasse::DoSomething() 10. Signals/Slots Signal et slot Signal : événement (Ex : clic sur bouton) Slot : fonction appelée La méthode connect (prend 4 arguments) : Objet qui émet l évènement Evénement (Signal) à intercepter Objet contenant le slot receveur (ce paramètre est facultatif s il est le même que l émetteur) Méthode (slot) qui doit s exécuter Plusieurs façons de connecter : avec Qt Designer, avec le menu «Aller au slot», en code.
a. Avec Qt Designer 1. bouton «Edit Signal/Slot» (raccourci F4) 2. sélectionner le widget désiré et glisser le curseur vers la cible (ici c est le formulaire, cela pourrait être n importe quel widget) 3. dans la boite de dialogue qui s est ouverte sélectionner : - à gauche l événement du widget (exemple ici ce sera clicked sur le bouton nommé okbutton) - à droite la méthode appelée de la cible Dans cet exemple la fenêtre MainWIndow se fermera quand on cliquera sur le bouton okbutton La vue du formulaire se met à jour Le code de mainwindow.ui se met à jour avec l ajout d une connection.
Autre possibilité avec le panneau signals & slots Editor (Celui ci se met à jour également automatiquement) b. Aller au slot (génération de code) Depuis le menu contextuel sur un Widget (dans la vue design) on sélectionne le signal
le code du slot est alors généré. Il suffit ensuite de remplir le code de la méthode void MainView::on_btnDemo_clicked() c. Par code Création d un slot Header On définit un slot dans le header #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui class MainWindow; class MainWindow : public QMainWindow Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void OnSayHello(); private: Ui::MainWindow *ui; ; #endif // MAINWINDOW_H Implémentation
Implémentation de la méthode et connect #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) ui->setupui(this); //connect(ui->okbutton,signal(clicked()),this, SLOT(OnSayHello())); // ou connect(ui->okbutton,signal(clicked()),slot(onsayhello())); MainWindow::~MainWindow() delete ui; void MainWindow::OnSayHello() Création d un Signal et d un Slot et connexion Dans le Header (*.h) signals: void NotifyMessage(const QString& message); private slots: void OnNotifyMessage(const QString& message); Dans le fichier *.cpp On implémente les slots Par Ex void MainView::OnNotifyMessage(const QString& message) QMessageBox messagebox; messagebox.settext(message); messagebox.exec(); Pour déclencher un signal en code on utilise emit emit NotifyMessage(tr("Ok!!")); Connexion du signal et du slot connect(this,signal(notifymessage(qstring)),slot(onnotifymessage(qstring)));
En résumé dans l exemple : Quand le signal NotifyMessage est déclenché (avec emit) le slot OnNotifyMessage est appelé. On utilisera Disconnect pour se désabonner 11. Editeur d actions Il est possible de créer des actions dans le panneau d action et ensuite les glisser sur le widget Menu et toolbar par exemple. Menu Le signe & permet d ajouter dans l éditeur d actions Depuis l action on ouvrir un menu contextuel et demander à «aller au slot». Le code est alors généré. Ex pour le signal triggered : void MainView::on_action_Quitter_triggered() // logiquement on demande à quitter l'application QApplication::quit(); Toolbar Glisser une action sur la toolbar. On peut régler le «toolbuttonstyle» pour afficher seulement l icône, le texte, les deux, etc.
12. Bases de données (QtSql Module) a. Connexion On ouvre la connexion puis on exécute une requête. QDB2 QIBASE QMYSQL QOCI QODBC QPSQL QSLITE IBM DB2 Borland InterBase MySQL Oracle SQL Server entre autres PostgreSQL SQLite Ex : avec SQL Server Express, connexion à la base Northwind L intérêt ici serait de créer une classe «Service» permettant de se connecter, lire et écrire dans la base. Ne pas oublier #include <QtSql/QSqlDatabase> QSqlDatabase db = QSqlDatabase::addDatabase("QODBC"); db.setdatabasename("driver=sql Server;Server=DONJR\\SQLEXPRESS;Database=Northwind;Uid=romagny;Pwd=abc12 3"); bool result = db.open(); Je définis ici tous les paramètres de connexion dans la chaine de connexion. Il serait possible de passer par les méthodes de QSqlDatabase pour définir par exemple l utilisateur et son mot de passe (setusername et setpassword). On peut utiliser la méthode close() pour fermer la connexion. b. Requête simple QVector<Category> SqlServerService::GetAll() // la liste de catégories renvoyée en résultat QVector<Category> categories; // On crée la requête QSqlQuery query; query.exec("select CategoryId,CategoryName FROM Categories"); // exécution de la requête // lecture des données while (query.next()) // récupération int id = query.value(0).toint(); QString name = query.value(1).tostring(); // ajout d'une catégorie à la liste résultat categories.push_back(category(id, name)); return categories;
c. Avec paramètre - bindvalue sert à définir les paramètres de la requête - Dans le cas d une requête n ayant pas de paramètre nommé (avec?) on peut utiliser addbindvalue(valeur ) Category SqlServerService::GetOne(int id) Category category; QSqlQuery query; query.prepare("select CategoryId,CategoryName FROM Categories WHERE CategoryId =:id"); query.bindvalue(":id",id); query.exec(); while (query.next()) category.id = query.value(0).toint(); category.name = query.value(1).tostring(); return category; La démarche est la même pour requête de mise à jour de la base : - On ouvre la connexion - On définit la requête (QSqlQuery), on définit le texte de la requête avec la méthode prepare, on ajoute les paramètres avec avec bindvalue ou AddBindValue (pour?) - On exécute la requête d. Transactions QSqlDatabase::database().transaction(); QSqlQuery query; query.prepare("insert INTO Categories(CategoryName) values(?)"); query.addbindvalue("fruits"); query.exec(); QSqlDatabase::database().commit(); 13. Liste basée sur un model ou item Item Views (Model Based) On définit le model de la QListView (nommée lscategories) QStringListModel *model = new QStringListModel(); QStringList list;
for(category category : categories) list.append(category.name); model->setstringlist(list); ui->lscategories->setmodel( model); QAbstractItemModel Item Widget (Item based) On remplit une QListWidget (nommée categorieslist) avec la méthode additem(qstring) for(category category : categories) ui->categorieslist->additem(category.name); 14. Layouts Positionnement manuel, automatique (vertical, horizontal, grid), splitter Documentation 15. Fichier de Ressources Ajout d un fichier de ressources au projet Ajouter Nouveau Qt Resource File donner un nom au fichier de ressource Le fichier de ressource apparait dans un dossier ressources Ajout de préfixes
Puis de fichiers (icônes, fichier texte, json, etc.) (Il est préférable de copier les fichiers dans un répertoire dans le projet) Utilisation d une ressource Ex changement de l icône du formulaire principal 16. Créer des Widgets a. Widget C est un peu comme un contrôle utilisateur en C# que l on pourra ajouter ensuite aux formulaires. Ajouter Nouveau Onglet Qt > classe d interface graphique Qt Designer Widget Donner un nom de classe
Définir l interface du Widget Avec Qt Designer, Ajout du Widget à un formulaire Par exemple dans le formulaire Principal (QMainWindow), on ajoute un Layout ici renommé mainlayout (VerticalLayout,etc.) qui va permettre de contenir le Widget #include "mainview.h" #include "ui_mainview.h" #include "categorydetailswidget.h" MainView::MainView(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainView) ui->setupui(this); // Ajout du Widget auto catwidget = new CategoryDetailsWidget(this); ui->mainlayout->addwidget(catwidget); MainView::~MainView() delete ui; Exécuter qmake puis build. b. Dialog /boite de dialogue personnalisée De la même manière on pourrait créer des boîtes de dialogue Ajouter Nouveau Onglet Qt > classe d interface graphique Qt Designer
Pour l utiliser ne pas oublier l include (Ex #include "mydialogbox.h") void MainView::on_pushButton_clicked() MyDialogBox dialog; dialog.show(); int result = dialog.exec(); Le clic sur OK renvoie 1, le clic sur Cancel renvoie 0. 17. Dialog QDialog, QFileDialog, QFontDialog, QMessageBox, QDialog Ex avec QMessageBox Par défaut il n y a qu un bouton Ok si on n indique pas setstandardbuttons QMessageBox messagebox; messagebox.settext("un message"); messagebox.setstandardbuttons(qmessagebox::ok QMessageBox::Cancel); messagebox.exec(); 18. Feuille de style Depuis le menu contextuel d un Widget (Modiler la feuille de style ) ou la propriété stylesheet. Il est possible d éditer, d ajouter de nouveaux styles à appliquer. Exemple un dégradé.
19. Linguist Translations Documentation
IV. Qt Quick Utilisation du QML (Qt Markup Language) pour définir l interface utilisateur. 1. Création d un projet Qt Quick Sélectionner Qt Quick Application Structure du projet généré : Le fichier *.pro de l application Formulaire principal de l application (ApplicationWindow) Permet d éditer le formulaire en mode Design. Celui-ci est intégré dans le QML de main avec MainForm Le mode Design pour éditer les formulaires (de base le formulaire est généré avec un exemple de code)