La première partie de ce tutoriel traite de la conception d'une interface graphique (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses.
La première étape dans la création d'applications graphiques est la conception de l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base. Le résultat attendu est illustré par la capture d'écran ci-dessous.
Nous allons avoir besoin de deux objets
QLabel
,
nameLabel
et
addressLabel
, ainsi que deux champs de saisie: un objet
QLineEdit
,
nameLine
, et un objet
QTextEdit
,
addressText
, afin de permettre à l'utilisateur d'entrer le nom d'un contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous.
Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses:
addressbook.h
- le fichier de définition (header) pour la classe
AddressBook
,
addressbook.cpp
- le fichier source, qui comprend l'implémentation de la classe
AddressBook
main.cpp
- le fichier qui contient la méthode
main()
, et une instance de la classe
AddressBook
.
Lorsque l'on écrit des programmes avec Qt, on a généralement recours à l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités. C'est l'un des concepts fondamentaux de la création de widgets personnalisés ou de collections de widgets. Utiliser l'héritage afin de compléter ou modifier le comportement d'un widget présente les avantages suivants:
Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités. La classe
AddressBook
crée dans ce tutoriel peut être réutilisée si on a besoin d'un widget carnet d'adresses basique.
Le fichier
addressbook.h
permet de définir la classe
AddressBook
.
On commence par définir
AddressBook
comme une classe fille de
QWidget
et déclarer un constructeur. On utilise également la macro
Q_OBJECT
pour indiquer que la classe exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que l'internationalisation, bien que nous ne les utilisions pas à ce stade.
class AddressBook : public QWidget { Q_OBJECT public: AddressBook(QWidget *parent = 0); private: QLineEdit *nameLine; QTextEdit *addressText; };
La classe contient les déclarations de
nameLine
et
addressText
, les instances privées de
QLineEdit
et
QTextEdit
mentionnées précédemment. Vous verrez, dans les chapitres à venir que les informations contenues dans
nameLine
et
addressText
sont nécessaires à de nombreuses méthodes du carnet d'adresses.
Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser puisque nous n'aurons pas besoin d'y faire référence après leur création. La façon dont Qt gère la parenté des objets est traitée dans la section suivante.
La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt. Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous permettant d'utiliser les méthodes tr() et connect() .
Nous en avons maintenant terminé avec le fichier
addressbook.h
et allons passer à l'implémentation du fichier
addressbook.cpp
.
Le constructeur de la classe
AddressBook
prend en paramètre un
QWidget
,
parent
. Par convention, on passe ce paramètre au constructeur de la classe mère. Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent, tous ses enfants seront détruits égalament.
AddressBook::AddressBook(QWidget *parent) : QWidget(parent) { QLabel *nameLabel = new QLabel(tr("Name:")); nameLine = new QLineEdit; QLabel *addressLabel = new QLabel(tr("Address:")); addressText = new QTextEdit;
à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux
QLabel
,
nameLabel
et
addressLabel
, de même on instancie
nameLine
et
addressText
. La méthode
tr()
renvoie une version traduite de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie la chaîne elle même. On peut voir cette méthode comme un marqueur
<insérer la traduction ici>
, permettant de repérer les objets
QString
à considérer pour traduire une application. Vous remarquerez, dans les chapitres à venir comme dans les
exemples Qt
, qu'elle est utilisée chaque fois que l'on utilise une chaîne susceptible d'être traduite.
Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les agencements ou layouts. Qt fournit trois classes principales de layouts pour contrôler le placement des widgets: QHBoxLayout , QVBoxLayout et QGridLayout .
On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière structurée. QGridLayout divise l'espace disponible en une grille, et place les widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne. Le diagramme ci-dessus présente les cellules et la position des widgets, et cette organisation est obtenue à l'aide du code suivant:
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
On remarque que le label
AddressLabel
est positionné en utilisant
Qt::AlignTop
comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt, consultez la section
布局管理
.
Afin d'installer l'objet layout dans un widget, il faut appeler la méthode setLayout() du widget en question:
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
Enfin, on initialise le titre du widget à "Simple Address Book"
Un fichier séparé,
main.cpp
, est utilisé pour la méthode
main()
. Dans cette fonction, on crée une instance de
QApplication
,
app
.
QApplication
se charge de des ressources communes à l'ensemble de l'application, tel que les polices de caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements. De ce fait, il y a toujours un objet
QApplication
dans toute application graphique en Qt.
int main(int argc, char *argv[]) { QApplication app(argc, argv); AddressBook addressBook; addressBook.show(); return app.exec(); }
On construit un nouveau widget
AddressBook
sur la pile et on invoque sa méthode
show()
pour l'afficher. Cependant, le widget ne sera pas visible tant que la boucle d'évènements n'aura pas été lancée. On démarre la boucle d'évènements en appelant la méthode
exec()
de l'application; le résultat renvoyé par cette méthode est lui même utilisé comme valeur de retour pour la méthode
main()
. On comprend maintenant pourquoi
AddressBook
a été créé sur la pile: à la fin du programme, l'objet sort du scope de la fonction
main()
et tous ses widgets enfants sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire.
文件: