diff options
author | David Boddie <dboddie@trolltech.com> | 2010-02-09 15:45:28 (GMT) |
---|---|---|
committer | David Boddie <dboddie@trolltech.com> | 2010-02-09 15:45:28 (GMT) |
commit | c908a57a54b7ad63ec06b7dcf7b3c5a4d54dd999 (patch) | |
tree | d313be14b4574a78354ec9dad8dcd1e6fd0c54de | |
parent | 3abc322eb6834aa61cc77d73dbd17c4389accb00 (diff) | |
parent | 4027c52d9fb6ea1bca13e1f3a2bc5ac5032387e0 (diff) | |
download | Qt-c908a57a54b7ad63ec06b7dcf7b3c5a4d54dd999.zip Qt-c908a57a54b7ad63ec06b7dcf7b3c5a4d54dd999.tar.gz Qt-c908a57a54b7ad63ec06b7dcf7b3c5a4d54dd999.tar.bz2 |
Merge branch 'qdoc-i18n'
27 files changed, 1844 insertions, 520 deletions
diff --git a/doc/doc.pri b/doc/doc.pri index 463c447..ccbef1a 100644 --- a/doc/doc.pri +++ b/doc/doc.pri @@ -30,8 +30,14 @@ QT_DOCUMENTATION = ($$QDOC qt-api-only.qdocconf assistant.qdocconf designer.qdoc $$GENERATOR doc-build/html-qmake/qmake.qhp -o doc/qch/qmake.qch \ ) +QT_ZH_CN_DOCUMENTATION = ($$QDOC qt-api-only_zh_CN.qdocconf) && \ + (cd $$QT_BUILD_TREE && \ + $$GENERATOR doc-build/html-qt_zh_CN/qt.qhp -o doc/qch/qt_zh_CN.qch \ + ) + win32-g++:isEmpty(QMAKE_SH) { QT_DOCUMENTATION = $$replace(QT_DOCUMENTATION, "/", "\\\\") + QT_ZH_CN_DOCUMENTATION = $$replace(QT_ZH_CN_DOCUMENTATION, "/", "\\\\") } # Build rules: @@ -42,6 +48,9 @@ qch_docs.depends += sub-tools docs.depends = adp_docs qch_docs +docs_zh_CN.depends = docs +docs_zh_CN.commands = $$QT_ZH_CN_DOCUMENTATION + # Install rules htmldocs.files = $$QT_BUILD_TREE/doc/html htmldocs.path = $$[QT_INSTALL_DOCS] @@ -54,5 +63,5 @@ qchdocs.CONFIG += no_check_exist docimages.files = $$QT_BUILD_TREE/doc/src/images docimages.path = $$[QT_INSTALL_DOCS]/src -QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs +QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs docs_zh_CN INSTALLS += htmldocs qchdocs docimages diff --git a/doc/src/legal/3rdparty.qdoc b/doc/src/legal/3rdparty.qdoc index b710449..bb2effa 100644 --- a/doc/src/legal/3rdparty.qdoc +++ b/doc/src/legal/3rdparty.qdoc @@ -116,9 +116,9 @@ \hr - Copyright (C) 2004,2007 Red Hat, Inc.\br - Copyright (C) 1998-2004 David Turner and Werner Lemberg\br - Copyright (C) 2006 Behdad Esfahbod\br + Copyright (C) 2004,2007  Red Hat, Inc.\br + Copyright (C) 1998-2004  David Turner and Werner Lemberg\br + Copyright (C) 2006  Behdad Esfahbod\br Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) This is part of HarfBuzz, an OpenType Layout engine library. @@ -137,7 +137,7 @@ THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. @@ -323,7 +323,7 @@ duplicated in all such forms and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed - by the University of California, Berkeley. The name of the + by the University of California, Berkeley.  The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR @@ -364,7 +364,7 @@ documentation for such software. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. diff --git a/doc/src/legal/licenses.qdoc b/doc/src/legal/licenses.qdoc index 9e680a6..344ebd4 100644 --- a/doc/src/legal/licenses.qdoc +++ b/doc/src/legal/licenses.qdoc @@ -276,14 +276,14 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\br - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer.\br - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution.\br - * Neither the name of Research In Motion Limited nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +   * Redistributions of source code must retain the above copyright +    notice, this list of conditions and the following disclaimer.\br +   * Redistributions in binary form must reproduce the above copyright +    notice, this list of conditions and the following disclaimer in the +    documentation and/or other materials provided with the distribution.\br +   * Neither the name of Research In Motion Limited nor the +    names of its contributors may be used to endorse or promote products +    derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Research In Motion Limited ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/doc/src/legal/trademarks.qdoc b/doc/src/legal/trademarks.qdoc index a7b5764..23d0cf6 100644 --- a/doc/src/legal/trademarks.qdoc +++ b/doc/src/legal/trademarks.qdoc @@ -47,7 +47,7 @@ \brief Information about trademarks owned by Nokia and other organisations. Nokia, the Nokia logo, Qt, and the Qt logo are trademarks of Nokia - Corporation and/or its subsidiaries in Finland and other countries. +  Corporation and/or its subsidiaries in Finland and other countries. \list \o Intel, Intel Inside (logos), MMX and Pentium are \reg trademarks of diff --git a/doc/src/tutorials/addressbook-fr.qdoc b/doc/src/tutorials/addressbook-fr.qdoc index d3bd1ca..98c44a3 100644 --- a/doc/src/tutorials/addressbook-fr.qdoc +++ b/doc/src/tutorials/addressbook-fr.qdoc @@ -47,47 +47,47 @@ \nextpage {tutorials/addressbook-fr/part1}{Chapitre 1} \title Tutoriel "Carnet d'adresses" - \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt. + \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt. - Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur) - à l'aide des outils fournis par la plateforme multiplate-forme Qt. + Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur) + à l'aide des outils fournis par la plateforme multiplate-forme Qt. \image addressbook-tutorial-screenshot.png - Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies + Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies par Qt, tel que: \list - \o Les Widgets et leur mise en page à l'aide des layouts + \o Les Widgets et leur mise en page à l'aide des layouts \o Les signaux et slots - \o Les structures de données de collections - \o Les entrées/sorties + \o Les structures de données de collections + \o Les entrées/sorties \endlist Si c'est votre premier contact avec Qt, lisez \l{How to Learn Qt}{Comment apprendre Qt} - si ce n'est déjà fait. + si ce n'est déjà fait. - Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook + Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook Les chapitres du tutoriel: \list 1 \o \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur} \o \l{tutorials/addressbook-fr/part2}{Ajouter des adresses} - \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments} - \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses} + \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments} + \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses} \o \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche} \o \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement} - \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées} + \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées} \endlist - La petite application que nous développerons ici ne possède pas tous les éléments + La petite application que nous développerons ici ne possède pas tous les éléments des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base - utilisées dans les applications plus complexes. + utilisées dans les applications plus complexes. - Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple - "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant - les menus et barres d'outils, la barre d'état, etc. + Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple + "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant + les menus et barres d'outils, la barre d'état, etc. */ @@ -98,156 +98,156 @@ \example tutorials/addressbook-fr/part1 \title Carnet d'adresses 1 - Conception de l'interface utilisateur - La première partie de ce tutoriel traite de la conception d'une interface graphique + 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. + 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. \image addressbook-tutorial-part1-screenshot.png Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel, ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet - QTextEdit, \c 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. + QTextEdit, \c 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. \image addressbook-tutorial-part1-labeled-screenshot.png - Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses: + Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses: \list - \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook, - \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe + \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook, + \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe \c AddressBook - \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et + \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et une instance de la classe \c AddressBook. \endlist - \section1 Programmation en Qt - héritage + \section1 Programmation en Qt - héritage - 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: + 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: \list - \o La possibilité d'implémenter des méthodes virtuelles et des méthodes - virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité - d'utiliser l'implémentation de la classe mère si besoin est. + \o La possibilité d'implémenter des méthodes virtuelles et des méthodes + virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité + d'utiliser l'implémentation de la classe mère si besoin est. \o Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe, - afin que les autres parties de l'application n'aient pas à se soucier de chacun des + afin que les autres parties de l'application n'aient pas à se soucier de chacun des widgets qui forment l'interface utilisateur. - \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés - dans une même application ou bibliothèque, et le code de la classe fille peut être - réutilisé dans d'autres projets + \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés + dans une même application ou bibliothèque, et le code de la classe fille peut être + réutilisé dans d'autres projets \endlist 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 \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un + partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités. + La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un widget carnet d'adresses basique. \section1 La classe AddressBook Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de - définir la classe \c AddressBook. + définir la classe \c AddressBook. - On commence par définir \c 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. + On commence par définir \c 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. \snippet tutorials/addressbook-fr/part1/addressbook.h class definition - La classe contient les déclarations de \c nameLine et \c 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 \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes + La classe contient les déclarations de \c nameLine et \c 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 \c nameLine et \c 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. + 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. + 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 \l{QObject::}{tr()} et \l{QObject::}{connect()}. + permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}. - Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons - passer à l'implémentation du fichier \c addressbook.cpp. + Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons + passer à l'implémentation du fichier \c addressbook.cpp. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e 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. + Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e 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. \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields - à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux - QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et - \c addressText. La méthode \l{QObject::tr()}{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 \tt{<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 \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois - que l'on utilise une chaîne susceptible d'être traduite. + à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux + QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et + \c addressText. La méthode \l{QObject::tr()}{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 \tt{<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 \l{Qt Examples}{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. + contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout. \image addressbook-tutorial-part1-labeled-layout.png - 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: + 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: \snippet tutorials/addressbook/part1/addressbook.cpp layout - On remarque que le label \c 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, + On remarque que le label \c 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 \l{Layout Management}. - Afin d'installer l'objet layout dans un widget, il faut appeler la méthode + Afin d'installer l'objet layout dans un widget, il faut appeler la méthode \l{QWidget::setLayout()}{setLayout()} du widget en question: \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout - Enfin, on initialise le titre du widget à "Simple Address Book" + Enfin, on initialise le titre du widget à "Simple Address Book" - \section1 Exécution de l'application + \section1 Exécution de l'application - Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette - fonction, on crée une instance de QApplication, \c 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. + Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette + fonction, on crée une instance de QApplication, \c 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. \snippet tutorials/addressbook/part1/main.cpp main function On construit un nouveau widget \c AddressBook sur la pile et on invoque - sa méthode \l{QWidget::show()}{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 \l{QApplication::}{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 + sa méthode \l{QWidget::show()}{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 \l{QApplication::}{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 \c main(). - On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin + On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants - sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire. + sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire. */ /*! @@ -258,53 +258,53 @@ \example tutorials/addressbook-fr/part2 \title Carnet d'adresses 2 - Ajouter des adresses - La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon - d'interactivité. + La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon + d'interactivité. \image addressbook-tutorial-part2-add-contact.png Nous allons fournir un bouton que l'utilisateur peut - cliquer pour ajouter un nouveau contact. Une structure de données est aussi - nécessaire afin de pouvoir stocker les contacts en mémoire. + cliquer pour ajouter un nouveau contact. Une structure de données est aussi + nécessaire afin de pouvoir stocker les contacts en mémoire. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Maintenant que nous avons mis en place les labels et les champs de saisie, - nous ajoutons les boutons pour compléter le processus d'ajout d'un contact. + nous ajoutons les boutons pour compléter le processus d'ajout d'un contact. Cela veut dire que notre fichier \c addressbook.h a maintenant trois objets QPushButton et trois slots publics correspondant. \snippet tutorials/addressbook/part2/addressbook.h slots - Un slot est une méthode qui répond à un signal. Nous allons - voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}. - Pour une explication détaillée du concept de signal et slot, vous pouvez - vous référer au document \l{Signals and Slots}. + Un slot est une méthode qui répond à un signal. Nous allons + voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}. + Pour une explication détaillée du concept de signal et slot, vous pouvez + vous référer au document \l{Signals and Slots}. Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton - sont maintenant inclus dans la déclaration des variables privées, avec - \c nameLine et \c addressText du chapitre précédent. + sont maintenant inclus dans la déclaration des variables privées, avec + \c nameLine et \c addressText du chapitre précédent. \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration Nous avons besoin d'un conteneur pour stocker les contacts du carnet - d'adresses, de façon à pouvoir les énumérer et les afficher. - Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker - des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact + d'adresses, de façon à pouvoir les énumérer et les afficher. + Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker + des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact est la \e{valeur}. \snippet tutorials/addressbook/part2/addressbook.h remaining private variables - Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress. - Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact - affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables + Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress. + Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact + affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables si l'utilisateur clique sur "Cancel", il est possible de revenir - à l'affichage du dernier contact. + à l'affichage du dernier contact. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans le constructeur de \c AddressBook, \c nameLine et - \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage + \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage mais pas la modification du contact courant. \dots @@ -317,16 +317,16 @@ \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration - Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()} - {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant - \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque - l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact() - décrite plus loin. + Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()} + {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant + \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque + l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact() + décrite plus loin. \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton - au slot qui gèrera l'action. + au slot qui gèrera l'action. L'image ci-dessous illustre ceci: \image addressbook-tutorial-part2-signals-and-slots.png @@ -336,77 +336,77 @@ \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout - La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour - assurer que les boutons ne sont pas répartis uniformément, mais regroupés - dans la partie supperieure du widget. La figure ci-dessous montre la différence - si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas. + La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour + assurer que les boutons ne sont pas répartis uniformément, mais regroupés + dans la partie supperieure du widget. La figure ci-dessous montre la différence + si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas. \image addressbook-tutorial-part2-stretch-effects.png - Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant + Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout. \snippet tutorials/addressbook/part2/addressbook.cpp grid layout - Les coordonnées du layout global ressemblent maintenant à ça: + Les coordonnées du layout global ressemblent maintenant à ça: \image addressbook-tutorial-part2-labeled-layout.png - Dans la méthode \c addContact(), nous stockons les détails du dernier - contact affiché dans \c oldName et \c oldAddress. Ensuite, nous - vidons ces champs de saisie et nous désactivons le mode - lecture seule. Le focus est placé sur \c nameLine et on affiche + Dans la méthode \c addContact(), nous stockons les détails du dernier + contact affiché dans \c oldName et \c oldAddress. Ensuite, nous + vidons ces champs de saisie et nous désactivons le mode + lecture seule. Le focus est placé sur \c nameLine et on affiche \c submitButton et \c cancelButton. \snippet tutorials/addressbook/part2/addressbook.cpp addContact - La méthode \c submitContact() peut être divisée en trois parties: + La méthode \c submitContact() peut être divisée en trois parties: \list 1 - \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText + \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText et les stockons dans des objets QString. Nous les validons pour s'assurer - que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie - vides; sinon un message est affiché avec QMessageBox pour rappeller à - l'utilisateur que les deux champs doivent être complétés. + que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie + vides; sinon un message est affiché avec QMessageBox pour rappeller à + l'utilisateur que les deux champs doivent être complétés. \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1 - \o Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts - existant n'entre en conflit avec le nouveau, nous l'ajoutons à + \o Ensuite, nous vérifions si le contact existe déjà . Si aucun contacts + existant n'entre en conflit avec le nouveau, nous l'ajoutons à \c contacts et nous affichons un QMessageBox pour informer l'utilisateur - que le contact a été ajouté. + que le contact a été ajouté. \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2 - Si le contact existe déjà, nous affichons un QMessageBox pour informer - l'utilisateur du problème. - Notre objet \c contacts est basé sur des paires clé-valeur formés par - le nom et l'adresse, nous voulons nous assurer que la \e clé est unique. + Si le contact existe déjà , nous affichons un QMessageBox pour informer + l'utilisateur du problème. + Notre objet \c contacts est basé sur des paires clé-valeur formés par + le nom et l'adresse, nous voulons nous assurer que la \e clé est unique. - \o Une fois que les deux vérifications précédentes ont été traitées, - nous restaurons les boutons à leur état normal à l'aide du code + \o Une fois que les deux vérifications précédentes ont été traitées, + nous restaurons les boutons à leur état normal à l'aide du code suivant: \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3 \endlist - La capture d'écran ci-dessous montre l'affichage fournit par un objet - QMessageBox, utilisé ici pour afficher un message d'information - à l'utilisateur: + La capture d'écran ci-dessous montre l'affichage fournit par un objet + QMessageBox, utilisé ici pour afficher un message d'information + à l'utilisateur: \image addressbook-tutorial-part2-add-successful.png - La méthode \c cancel() restaure les détails du dernier contact, active + La méthode \c cancel() restaure les détails du dernier contact, active \c addButton, et cache \c submitButton et \c cancelButton. \snippet tutorials/addressbook/part2/addressbook.cpp cancel - L'idée générale pour augmenter la flexibilité lors de l'ajout d'un - contact est de donner la possiblité de cliquer sur "Add" - ou "Cancel" à n'importe quel moment. - L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées + L'idée générale pour augmenter la flexibilité lors de l'ajout d'un + contact est de donner la possiblité de cliquer sur "Add" + ou "Cancel" à n'importe quel moment. + L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées jusqu'ici: \image addressbook-tutorial-part2-add-flowchart.png @@ -418,118 +418,118 @@ \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \nextpage {tutorials/addressbook-fr/part4}{Chapitre 4} \example tutorials/addressbook-fr/part3 - \title Carnet d'adresses 3 - Navigation entre les éléments + \title Carnet d'adresses 3 - Navigation entre les éléments - L'application "Carnet d'adresses" est maintenant à moitié terminée. Il + L'application "Carnet d'adresses" est maintenant à moitié terminée. Il nous faut maintenant ajouter quelques fonctions pour naviguer entre - les contacts. Avant de commencer, il faut se décider sur le type de structure de - données le plus approprié pour stocker les contacts. + les contacts. Avant de commencer, il faut se décider sur le type de structure de + données le plus approprié pour stocker les contacts. - Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur, - avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur. + Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur, + avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur. Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les - entrées, quelques améliorations sont nécessaires. + entrées, quelques améliorations sont nécessaires. - Nous améliorerons le QMap en le faisant ressembler à une structure de données - similaire à une liste liée, où tous les éléments sont connectés, y compris - le premier et le dernier élément. La figure ci-dessous illustre cette structure - de donnée. + Nous améliorerons le QMap en le faisant ressembler à une structure de données + similaire à une liste liée, où tous les éléments sont connectés, y compris + le premier et le dernier élément. La figure ci-dessous illustre cette structure + de donnée. \image addressbook-tutorial-part3-linkedlist.png - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons - besoin de deux slots supplémentaires dans notre classe \c AddressBook: - \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h: + besoin de deux slots supplémentaires dans notre classe \c AddressBook: + \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h: \snippet tutorials/addressbook/part3/addressbook.h navigation functions Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons - donc les variables privées \c nextButton et \c previousButton. + donc les variables privées \c nextButton et \c previousButton. \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous - instancions \c nextButton et \c previousButton et nous les désactivons - par défaut. Nous faisons ceci car la navigation ne doit être activée + A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous + instancions \c nextButton et \c previousButton et nous les désactivons + par défaut. Nous faisons ceci car la navigation ne doit être activée que lorsqu'il y a plus d'un contact dans le carnet d'adresses. \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons - Nous connectons alors ces boutons à leur slots respectifs: + Nous connectons alors ces boutons à leur slots respectifs: \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals - L'image ci-dessous montre l'interface utilisateur que nous allons créer. - Remarquez que cela ressemble de plus en plus à l'interface du programme + L'image ci-dessous montre l'interface utilisateur que nous allons créer. + Remarquez que cela ressemble de plus en plus à l'interface du programme complet. \image addressbook-tutorial-part3-screenshot.png Nous suivons les conventions pour les fonctions \c next() et \c previous() - en plaçant \c nextButton à droite et \c previousButton à gauche. Pour + en plaçant \c nextButton à droite et \c previousButton à gauche. Pour faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour - placer les widgets côte à côte: + placer les widgets côte à côte: \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout - L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout. + L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout. \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout - La figure ci-dessous montre les systèmes de coordonnées pour les widgets du + La figure ci-dessous montre les systèmes de coordonnées pour les widgets du \c mainLayout. \image addressbook-tutorial-part3-labeled-layout.png - Dans notre méthode \c addContact(), nous avons desactivé ces boutons - pour être sûr que l'utilisateur n'utilise pas la navigation lors de + Dans notre méthode \c addContact(), nous avons desactivé ces boutons + pour être sûr que l'utilisateur n'utilise pas la navigation lors de l'ajout d'un contact. \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation - Dans notre méthode \c submitContact(), nous activons les boutons de + Dans notre méthode \c submitContact(), nous activons les boutons de navigation, \c nextButton et \c previousButton, en fonction de la - taille de \c contacts. Commen mentionné plus tôt, la navigation n'est - activée que si il y a plus d'un contact dans le carnet d'adresses. + taille de \c contacts. Commen mentionné plus tôt, la navigation n'est + activée que si il y a plus d'un contact dans le carnet d'adresses. Les lignes suivantes montrent comment faire cela: \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation Nous incluons aussi ces lignes de code dans le bouton \c cancel(). - Souvenez vous que nous voulons émuler une liste-liée ciruculaire à - l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur - sur \c contact dans la méthode \c next(), et ensuite: + Souvenez vous que nous voulons émuler une liste-liée ciruculaire à + l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur + sur \c contact dans la méthode \c next(), et ensuite: \list - \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons - \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position - jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap + \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons + \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position + jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap fonctionne comme une liste circulaire. \endlist \snippet tutorials/addressbook/part3/addressbook.cpp next() function - Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts, + Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts, nous affichons son contenu sur \c nameLine et \c addressText. - De la même façon, pour la méthode \c previous(), nous obtenons un - itérateur sur \c contacts et ensuite: + De la même façon, pour la méthode \c previous(), nous obtenons un + itérateur sur \c contacts et ensuite: \list - \o Si l'itérateur est à la fin de \c contacts, on réinitialise + \o Si l'itérateur est à la fin de \c contacts, on réinitialise l'affichage et on retourne. - \o Si l'itérateur est au début de \c contacts, on change sa - position jusqu'à la fin - \o Ensuite, on décrémente l'itérateur + \o Si l'itérateur est au début de \c contacts, on change sa + position jusqu'à la fin + \o Ensuite, on décrémente l'itérateur \endlist \snippet tutorials/addressbook/part3/addressbook.cpp previous() function - à nouveau, nous affichons le contenu de l'objet courant dans \c contacts. + à nouveau, nous affichons le contenu de l'objet courant dans \c contacts. */ @@ -540,27 +540,27 @@ \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \nextpage {tutorials/addressbook-fr/part5}{Chapitre 5} \example tutorials/addressbook-fr/part4 - \title Carnet d'Adresses 4 - éditer et supprimer des adresses + \title Carnet d'Adresses 4 - éditer et supprimer des adresses - Dans ce chapitre, nous verrons comment modifier les données des contacts + Dans ce chapitre, nous verrons comment modifier les données des contacts contenus dans l'application carnet d'adresses. \image addressbook-tutorial-screenshot.png Nous avons maintenant un carnet d'adresses qui ne se contente pas de - lister des contacts de façon ordonnée, mais permet également la - navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et - supprimer, afin que les détails associés à un contact puissent être - modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère - modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux - modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas - définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les + lister des contacts de façon ordonnée, mais permet également la + navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et + supprimer, afin que les détails associés à un contact puissent être + modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère + modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux + modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas + définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les boutons correspondants manuellement, au prix de multiples redondances dans le code. - Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles. + Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles. \list \o \c{NavigationMode}, @@ -568,22 +568,22 @@ \o \c{EditingMode}. \endlist - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook - Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode : + Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode : \snippet tutorials/addressbook/part4/addressbook.h Mode enum - On ajoute également deux nouveaux slots, \c editContact() et - \c removeContact(), à notre liste de slots publics. + On ajoute également deux nouveaux slots, \c editContact() et + \c removeContact(), à notre liste de slots publics. \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots - Afin de basculer d'un mode à l'autre, on introduit la méthode - \c updateInterface() pour contrôller l'activation et la désactivation de - tous les objets QPushButton. On ajoute également deux nouveaux boutons, - \c editButton et \c removeButton, pour les fonctions d'édition - et de suppression mentionnées plus haut. + Afin de basculer d'un mode à l'autre, on introduit la méthode + \c updateInterface() pour contrôller l'activation et la désactivation de + tous les objets QPushButton. On ajoute également deux nouveaux boutons, + \c editButton et \c removeButton, pour les fonctions d'édition + et de suppression mentionnées plus haut. \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration \dots @@ -591,97 +591,97 @@ \dots \snippet tutorials/addressbook/part4/addressbook.h mode declaration - Enfin, on déclare \c currentMode pour garder une trace du mode - actuellement utilisé. + Enfin, on déclare \c currentMode pour garder une trace du mode + actuellement utilisé. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Il nous faut maintenant implémenter les fonctionnalités de changement de + Il nous faut maintenant implémenter les fonctionnalités de changement de mode de l'application carnet d'adresses. Les boutons \c editButton et - \c removeButton sont instanciés et désactivés par défaut, puisque le - carnet d'adresses démarre sans aucun contact en mémoire. + \c removeButton sont instanciés et désactivés par défaut, puisque le + carnet d'adresses démarre sans aucun contact en mémoire. \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons - Ces boutons sont ensuite connectés à leurs slots respectifs, - \c editContact() et \c removeContact(), avant d'être ajoutés à + Ces boutons sont ensuite connectés à leurs slots respectifs, + \c editContact() et \c removeContact(), avant d'être ajoutés à \c buttonLayout1. \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove \dots \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout - La methode \c editContact() place les anciens détails du contact dans + La methode \c editContact() place les anciens détails du contact dans \c oldName et \c oldAddress, avant de basculer vers le mode \c EditingMode. Dans ce mode, les boutons \c submitButton et - \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent - modifier les détails du contact et cliquer sur l'un de ces deux boutons + \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent + modifier les détails du contact et cliquer sur l'un de ces deux boutons par la suite. \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function - La méthode \c submitContact() a été divisée en deux avec un bloc + La méthode \c submitContact() a été divisée en deux avec un bloc \c{if-else}. On teste \c currentMode pour voir si le mode courant est - \c AddingMode. Si c'est le cas, on procède à l'ajout. + \c AddingMode. Si c'est le cas, on procède à l'ajout. \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning \dots \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1 Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le - cas, on compare \c oldName et \c name. Si le nom a changé, on supprime - l'ancien contact de \c contacts et on insère le contact mis a jour. + cas, on compare \c oldName et \c name. Si le nom a changé, on supprime + l'ancien contact de \c contacts et on insère le contact mis a jour. \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2 - Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à - \c address), on met à jour l'adresse du contact. Enfin on règle - \c currentMode à \c NavigationMode. C'est une étape importante puisque - c'est cela qui réactive tous les boutons désactivés. + Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à + \c address), on met à jour l'adresse du contact. Enfin on règle + \c currentMode à \c NavigationMode. C'est une étape importante puisque + c'est cela qui réactive tous les boutons désactivés. - Afin de retirer un contact du carnet d'adresses, on implémente la méthode - \c removeContact(). Cette méthode vérifie que le contact est présent dans + Afin de retirer un contact du carnet d'adresses, on implémente la méthode + \c removeContact(). Cette méthode vérifie que le contact est présent dans \c contacts. \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function - Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant - confirmation de la suppression à l'utilisateur. Une fois la confirmation - effectuée, on appelle \c previous(), afin de s'assurer que l'interface - utilisateur affiche une autre entrée, et on supprime le contact en - utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un + Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant + confirmation de la suppression à l'utilisateur. Une fois la confirmation + effectuée, on appelle \c previous(), afin de s'assurer que l'interface + utilisateur affiche une autre entrée, et on supprime le contact en + utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un souci pratique, on informe l'utilisateur de la suppression par le biais - d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette - méthode sont représentées ci-dessous. + d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette + méthode sont représentées ci-dessous. \image addressbook-tutorial-part4-remove.png - \section2 Mise à jour de l'Interface utilisateur + \section2 Mise à jour de l'Interface utilisateur - On a évoqué plus haut la méthode \c updateInterface() comme moyen - d'activer et de désactiver les différents boutons de l'interface en - fonction du mode. Cette méthode met à jour le mode courant selon - l'argument \c mode qui lui est passé, en l'assignant à \c currentMode, + On a évoqué plus haut la méthode \c updateInterface() comme moyen + d'activer et de désactiver les différents boutons de l'interface en + fonction du mode. Cette méthode met à jour le mode courant selon + l'argument \c mode qui lui est passé, en l'assignant à \c currentMode, avant de tester sa valeur. - Chacun des boutons est ensuite activé ou désactivé, en fonction du mode. + Chacun des boutons est ensuite activé ou désactivé, en fonction du mode. Le code source pour les cas \c AddingMode et \c EditingMode est visible ci-dessous: \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1 Dans le cas de \c NavigationMode, en revanche, des tests conditionnels - sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de - s'assurer que les boutons \c editButton et \c removeButton ne sont activés + sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de + s'assurer que les boutons \c editButton et \c removeButton ne sont activés que s'il existe au moins un contact dans le carnet d'adresses; - \c nextButton et \c previousButton ne sont activés que lorsqu'il existe + \c nextButton et \c previousButton ne sont activés que lorsqu'il existe plus d'un contact dans le carnet d'adresses. \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2 - En effectuant les opérations de réglage du mode et de mise à jour de - l'interface utilisateur au sein de la même méthode, on est à l'abri de - l'éventualité où l'interface utilisateur se "désynchronise" de l'état + En effectuant les opérations de réglage du mode et de mise à jour de + l'interface utilisateur au sein de la même méthode, on est à l'abri de + l'éventualité où l'interface utilisateur se "désynchronise" de l'état interne de l'application. */ @@ -694,7 +694,7 @@ \example tutorials/addressbook-fr/part5 \title Carnet d'adresse 5 - Ajout d'une fonction de recherche - Dans ce chapitre, nous allons voir les possibilités pour rechercher + Dans ce chapitre, nous allons voir les possibilités pour rechercher des contacts dans le carnet d'adresse. \image addressbook-tutorial-part5-screenshot.png @@ -703,110 +703,110 @@ il devient difficile de naviguer avec les boutons \e Next et \e Previous. Dans ce cas, une fonction de recherche serait plus efficace pour rechercher les contacts. - La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position + La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position dans le paneau de bouton. Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher - une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. + une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour - implémenter la class \c FindDialog. + implémenter la class \c FindDialog. - \section1 Définition de la classe FindDialog + \section1 Définition de la classe FindDialog \image addressbook-tutorial-part5-finddialog.png - Pour sous-classer QDialog, nous commençons par inclure le header de - QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les + Pour sous-classer QDialog, nous commençons par inclure le header de + QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les classes QLineEdit et QPushButton car nous utilisons ces widgets dans notre classe dialogue. Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise - la macro Q_OBJECT et son constructeur est défini de façon à accepter - un QWidget parent, même si cette boîte de dialogue sera affichée dans une - fenêtre séparée. + la macro Q_OBJECT et son constructeur est défini de façon à accepter + un QWidget parent, même si cette boîte de dialogue sera affichée dans une + fenêtre séparée. \snippet tutorials/addressbook/part5/finddialog.h FindDialog header - Nous définissons la méthode publique \c getFindText() pour être utilisée + Nous définissons la méthode publique \c getFindText() pour être utilisée par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir - le texte entré par l'utilisateur. Un slot public, \c findClicked(), est - défini pour prendre en charge le texte lorsque l'utilisateur clique sur + le texte entré par l'utilisateur. Un slot public, \c findClicked(), est + défini pour prendre en charge le texte lorsque l'utilisateur clique sur le bouton \gui Find. - Finalement, nous définissons les variables privées \c findButton, + Finalement, nous définissons les variables privées \c findButton, \c lineEdit et \c findText, qui correspondent respectivement au bouton \gui Find, au champ de texte dans lequel l'utilisateur tape le texte - à rechercher, et à une variable interne stockant le texte pour une - utilisation ultérieure. + à rechercher, et à une variable interne stockant le texte pour une + utilisation ultérieure. - \section1 Implémentation de la classe FindDialog + \section1 Implémentation de la classe FindDialog Dans le constructeur de \c FindDialog, nous instancions les objets des - variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite + variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite un QHBoxLayout pour positionner les widgets. \snippet tutorials/addressbook/part5/finddialog.cpp constructor - Nous mettons en place la mise en page et le titre de la fenêtre, et + Nous mettons en place la mise en page et le titre de la fenêtre, et nous connectons les signaux aux slots. Remarquez que le signal - \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté - à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot + \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté + à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot \l{QDialog::accept()}{accept()} fourni par le QDialog ferme - la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}. - Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe - \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera - expliqué plus loin lorsque nous verrons la méthode \c findContact(). + la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}. + Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe + \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera + expliqué plus loin lorsque nous verrons la méthode \c findContact(). \image addressbook-tutorial-part5-signals-and-slots.png Dans \c findClicked(), nous validons le champ de texte pour nous - assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans - avoir entré un nom de contact. Ensuite, nous stockons le texte du champ - d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le - contenu de \c lineEdit et cachons la boîte de dialogue. + assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans + avoir entré un nom de contact. Ensuite, nous stockons le texte du champ + d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le + contenu de \c lineEdit et cachons la boîte de dialogue. \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function - La variable \c findText a un accesseur publique associé: \c getFindText(). - Étant donné que nous ne modifions \c findText directement que dans le - constructeur et la méthode \c findClicked(), nous ne créons pas - de manipulateurs associé à \c getFindText(). + La variable \c findText a un accesseur publique associé: \c getFindText(). + Étant donné que nous ne modifions \c findText directement que dans le + constructeur et la méthode \c findClicked(), nous ne créons pas + de manipulateurs associé à \c getFindText(). Puisque \c getFindText() est publique, les classes instanciant et - utilisant \c FindDialog peuvent toujours accéder à la chaîne de - caractères que l'utilisateur a entré et accepté. + utilisant \c FindDialog peuvent toujours accéder à la chaîne de + caractères que l'utilisateur a entré et accepté. \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous incluons \c finddialog.h dans le fichier \c addressbook.h. \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header - Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un - QPushButton et un slot correspondant. De la même façon, pour la - fonctionnalité \gui Find, nous avons \c findButton et \c findContact(). + Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un + QPushButton et un slot correspondant. De la même façon, pour la + fonctionnalité \gui Find, nous avons \c findButton et \c findContact(). - Le \c findButton est déclaré comme une variable privée et la - méthode \c findContact() est déclarée comme un slot public. + Le \c findButton est déclaré comme une variable privée et la + méthode \c findContact() est déclarée comme un slot public. \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration \dots \snippet tutorials/addressbook/part5/addressbook.h findButton declaration - Finalement, nous déclarons la variable privée \c dialog que nous allons - utiliser pour accéder à une instance de \c FindDialog. + Finalement, nous déclarons la variable privée \c dialog que nous allons + utiliser pour accéder à une instance de \c FindDialog. \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration - Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser - plus qu'une fois. Utiliser une variable privée nous permet d'y référer - à plus d'un endroit dans la classe. + Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser + plus qu'une fois. Utiliser une variable privée nous permet d'y référer + à plus d'un endroit dans la classe. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Dans le constructeur de \c AddressBook, nous instancions nos objets privés, + Dans le constructeur de \c AddressBook, nous instancions nos objets privés, \c findbutton et \c findDialog: \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton @@ -814,25 +814,25 @@ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de - \c{findButton} à \c findContact(). + \c{findButton} à \c findContact(). \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find - Maintenant, tout ce qui manque est le code de notre méthode \c findContact(): + Maintenant, tout ce qui manque est le code de notre méthode \c findContact(): \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function - Nous commençons par afficher l'instance de \c FindDialog, \c dialog. - L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque - l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est - masquée et le code de retour devient QDialog::Accepted. Ce code de retour + Nous commençons par afficher l'instance de \c FindDialog, \c dialog. + L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque + l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est + masquée et le code de retour devient QDialog::Accepted. Ce code de retour vient remplir la condition du premier if. Ensuite, nous extrayons le texte que nous utiliserons pour la recherche, - il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText() + il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText() de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour - indiquer que la recherche à échouée. + indiquer que la recherche à échouée. \image addressbook-tutorial-part5-notfound.png */ @@ -845,49 +845,49 @@ \example tutorials/addressbook-fr/part6 \title Carnet d'Adresses 6 - Sauvegarde et chargement - Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que - l'on utilise pour écrire les procédures de sauvegarde et chargement pour + Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que + l'on utilise pour écrire les procédures de sauvegarde et chargement pour l'application carnet d'adresses. \image addressbook-tutorial-part6-screenshot.png Bien que la navigation et la recherche de contacts soient des - fonctionnalités importantes, notre carnet d'adresses ne sera pleinement + fonctionnalités importantes, notre carnet d'adresses ne sera pleinement utilisable qu'une fois que l'on pourra sauvegarder les contacts existants - et les charger à nouveau par la suite. - Qt fournit de nombreuses classes pour gérer les \l{Input/Output and - Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une - combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream. + et les charger à nouveau par la suite. + Qt fournit de nombreuses classes pour gérer les \l{Input/Output and + Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une + combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream. - Un objet QFile représente un fichier sur le disque qui peut être lu, et - dans lequel on peut écrire. QFile est une classe fille de la classe plus - générique QIODevice, qui peut représenter différents types de - périphériques. + Un objet QFile représente un fichier sur le disque qui peut être lu, et + dans lequel on peut écrire. QFile est une classe fille de la classe plus + générique QIODevice, qui peut représenter différents types de + périphériques. - Un objet QDataStream est utilisé pour sérialiser des données binaires - dans le but de les passer à un QIODevice pour les récupérer dans le - futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le - flux, avec le périphérique approprié en paramètre, et d'y lire ou - écrire. + Un objet QDataStream est utilisé pour sérialiser des données binaires + dans le but de les passer à un QIODevice pour les récupérer dans le + futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le + flux, avec le périphérique approprié en paramètre, et d'y lire ou + écrire. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook - On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), + On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), ainsi que deux objets QPushButton, \c loadButton et \c saveButton. \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration \dots \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans notre constructeur, on instancie \c loadButton et \c saveButton. - Idéalement, l'interface serait plus conviviale avec des boutons + Idéalement, l'interface serait plus conviviale avec des boutons affichant "Load contacts from a file" et "Save contacts to a file". Mais compte tenu de la dimension des autres boutons, on initialise les labels - des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une - façon simple d'ajouter des info-bulles avec - \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon + des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une + façon simple d'ajouter des info-bulles avec + \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon suivante pour nos boutons: \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1 @@ -895,85 +895,85 @@ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2 Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au - layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et + layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et nous connectons leurs signaux - \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs. + \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs. - Pour la sauvegarde, on commence par récupérer le nom de fichier + Pour la sauvegarde, on commence par récupérer le nom de fichier \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une - méthode pratique fournie par QFileDialog, qui ouvre une boîte de - dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou + méthode pratique fournie par QFileDialog, qui ouvre une boîte de + dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk} - correspondent à l'extension choisie pour la sauvegarde des contacts de + correspondent à l'extension choisie pour la sauvegarde des contacts de notre carnet d'adresses. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1 - La boîte de dialogue affichée est visible sur la capture d'écran ci- + La boîte de dialogue affichée est visible sur la capture d'écran ci- dessous. \image addressbook-tutorial-part6-save.png - Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir - de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de + Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir + de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de QIODevice. - Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au - mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe + Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au + mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe l'utilisateur avec une QMessageBox. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2 Dans le cas contraire, on instancie un objet QDataStream, \c out, afin - d'écrire dans le fichier ouvert. QDataStream nécessite que la même - version de flux soit utilisée pour la lecture et l'écriture. On s'assure - que c'est le cas en spécifiant explicitement d'utiliser la + d'écrire dans le fichier ouvert. QDataStream nécessite que la même + version de flux soit utilisée pour la lecture et l'écriture. On s'assure + que c'est le cas en spécifiant explicitement d'utiliser la \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de - sérialiser les données vers le fichier \c file. + sérialiser les données vers le fichier \c file. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3 - Pour le chargement, on récupère également \c fileName en utilisant - QFileDialog::getOpenFileName(). Cette méthode est l'homologue de - QFileDialog::getSaveFileName() et affiche également une boîte de - dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou + Pour le chargement, on récupère également \c fileName en utilisant + QFileDialog::getOpenFileName(). Cette méthode est l'homologue de + QFileDialog::getSaveFileName() et affiche également une boîte de + dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou de selectionner un fichier \c{.abk} existant, afin de le charger dans le carnet d'adresses. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1 - Sous Windows, par exemple, cette méthode affiche une boîte de dialogue - native pour la sélection de fichier, comme illustré sur la capture - d'écran suivante: + Sous Windows, par exemple, cette méthode affiche une boîte de dialogue + native pour la sélection de fichier, comme illustré sur la capture + d'écran suivante: \image addressbook-tutorial-part6-load.png Si \c fileName n'est pas vide, on utilise une fois de plus un objet QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode - \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre - implémentation de \c saveToFile(), si cette tentative s'avère + \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre + implémentation de \c saveToFile(), si cette tentative s'avère infructueuse, on en informe l'utilisateur par le biais d'une QMessageBox. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2 Dans le cas contraire, on instancie un objet QDataStream, \c in, en - spécifiant la version à utiliser comme précédemment, et on lit les - informations sérialisées vers la structure de données \c contacts. Notez + spécifiant la version à utiliser comme précédemment, et on lit les + informations sérialisées vers la structure de données \c contacts. Notez qu'on purge \c contacts avant d'y mettre les informations lues afin de - simplifier le processus de lecture de fichier. Une façon plus avancée de - procéder serait de lire les contacts dans un objet QMap temporaire, et + simplifier le processus de lecture de fichier. Une façon plus avancée de + procéder serait de lire les contacts dans un objet QMap temporaire, et de copier uniquement les contacts n'existant pas encore dans \c contacts. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3 Pour afficher les contacts lus depuis le fichier, on doit d'abord - valider les données obtenues afin de s'assurer que le fichier lu - contient effectivement des entrées de carnet d'adresses. Si c'est le + valider les données obtenues afin de s'assurer que le fichier lu + contient effectivement des entrées de carnet d'adresses. Si c'est le cas, on affiche le premier contact; sinon on informe l'utilisateur du - problème par une QMessageBox. Enfin, on met à jour l'interface afin - d'activer et de désactiver les boutons de façon appropriée. + problème par une QMessageBox. Enfin, on met à jour l'interface afin + d'activer et de désactiver les boutons de façon appropriée. */ /*! @@ -981,86 +981,86 @@ \previouspage {tutorials/addressbook-fr/part6}{Chapitre 6} \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \example tutorials/addressbook-fr/part7 - \title Carnet d'adresse 7 - Fonctionnalités avancées + \title Carnet d'adresse 7 - Fonctionnalités avancées - Ce chapitre couvre quelques fonctionnalités additionnelles qui + Ce chapitre couvre quelques fonctionnalités additionnelles qui feront de notre carnet d'adresses une application plus pratique pour une utilisation quotidienne. \image addressbook-tutorial-part7-screenshot.png Bien que notre application carnet d'adresses soit utile en tant que telle, - il serait pratique de pouvoir échanger les contacts avec d'autres applications. - Le format vCard est un un format de fichier populaire pour échanger - ce type de données. - Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre + il serait pratique de pouvoir échanger les contacts avec d'autres applications. + Le format vCard est un un format de fichier populaire pour échanger + ce type de données. + Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre d'exporter des contacts dans des fichiers vCard \c{.vcf}. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Nous ajoutons un objet QPushButton, \c exportButton, et un slot - public correspondant, \c exportAsVCard(), à notre classe \c AddressBook + public correspondant, \c exportAsVCard(), à notre classe \c AddressBook dans le fichier \c addressbook.h. \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration \dots \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans le constructeur de \c AddressBook, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot \c exportAsVCard(). - Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable + Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable du groupe de boutons sur la droite. - Dans la méthode \c exportAsVCard(), nous commençons par extraire le - nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et + Dans la méthode \c exportAsVCard(), nous commençons par extraire le + nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et \c nameList. Ensuite, nous cherchons la position du premier espace blanc de \c name. - Si il y a un espace, nous séparons le nom du contact en \c firstName et - \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_"). + Si il y a un espace, nous séparons le nom du contact en \c firstName et + \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_"). Si il n'y a pas d'espace, nous supposons que le contact ne comprend que - le prénom. + le prénom. \snippet tutorials/addressbook/part7/addressbook.cpp export function part1 - Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue - pour donner la possibilité à l'utilisateur de choisir un emplacement pour - le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile - pour y écrire. + Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue + pour donner la possibilité à l'utilisateur de choisir un emplacement pour + le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile + pour y écrire. Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si - cela échoue, nous affichons un QMessageBox pour informer l'utilisateur - à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le - fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que - QDataStream, la classe QTextStream fournit les fonctionnalités pour - lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf} - généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte. + cela échoue, nous affichons un QMessageBox pour informer l'utilisateur + à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le + fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que + QDataStream, la classe QTextStream fournit les fonctionnalités pour + lire et écrire des fichiers de texte. Grâce à celà , le fichier \c{.vcf} + généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte. \snippet tutorials/addressbook/part7/addressbook.cpp export function part2 - Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD}, + Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD}, suivit par \c{VERSION:2.1}. - Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise - \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact - à un nom de famille défini ou non. Si oui, nous utilions les détails de - \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu + Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise + \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact + à un nom de famille défini ou non. Si oui, nous utilions les détails de + \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu de \c firstName. \snippet tutorials/addressbook/part7/addressbook.cpp export function part3 - Nous continuons en écrivant l'adresse du contact. Les points-virgules - dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont - remplacés par des points-virgules, et les vigules sont remplacées par des espaces. - Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse + Nous continuons en écrivant l'adresse du contact. Les points-virgules + dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont + remplacés par des points-virgules, et les vigules sont remplacées par des espaces. + Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse et la balise \c{END:VCARD}. \snippet tutorials/addressbook/part7/addressbook.cpp export function part4 - À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur - que la vCard a été exportée avec succès. + À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur + que la vCard a été exportée avec succès. - \e{vCard est une marque déposée de \l{http://www.imc.org} + \e{vCard est une marque déposée de \l{http://www.imc.org} {Internet Mail Consortium}}. */ diff --git a/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc new file mode 100644 index 0000000..1c2f56b --- /dev/null +++ b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page how-to-learn-qt.html + \title 如何å¦ä¹ Qt + \brief Links to guides and resources for learning Qt. + \nextpage 教程 + + \section1 Getting Started + + 我们å‡å®šæ‚¨å·²äº†è§£ C++, 并将用于 Qt å¼€å‘。有关将 Qt 与其他编程è¯è¨€ä¸€èµ·ä½¿ç”¨çš„更多信æ¯ï¼Œè¯·å‚è§ \l{Qt website}{Qt 网站}。 + + å¦‚æžœä½ æƒ³ä»…ä½¿ç”¨ C++ 编程, ä¸ä½¿ç”¨ä»»ä½•è®¾è®¡å·¥å…·è€Œä»…使用代ç 设计用户界é¢ï¼Œè¯·è§‚看\l{教程}。这些教程是为您了解 Qt 编程é‡èº«å®šåšçš„,并侧é‡äºŽç¼–写å¯ç”¨ä»£ç ,而并éžåŠŸèƒ½ç®€ä»‹ã€‚ + + 如果您想使用设计工具æ¥è®¾è®¡ç”¨æˆ·ç•Œé¢ï¼Œåˆ™è‡³å°‘è¦é˜…读 \l{Qt Designer manual}{Qt 设计者手册}çš„å‰å‡ ç« ã€‚ + + 现在您已ç»ç¼–写了一些å°åž‹å¯ç”¨çš„应用程åºï¼Œå¹¶å¯¹ Qt ç¼–ç¨‹æœ‰æ›´åŠ å¹¿æ³›çš„äº†è§£ã€‚æ‚¨å¯ä»¥ç›´æŽ¥ç€æ‰‹åšè‡ªå·±çš„é¡¹ç›®ï¼Œä½†æˆ‘ä»¬å»ºè®®æ‚¨é˜…è¯»ä»¥ä¸‹ä¸€äº›å…³é”®ç®€ä»‹ä»¥åŠ æ·±æ‚¨å¯¹ Qt 的了解:\l{Qt Object Model}Qt 对象模型}å’Œ\l{Signals and Slots}{ä¿¡å·å’Œæ§½}。 + + \beginfloatleft + \inlineimage qtdemo-small.png + \endfloat + + \section1 了解概况 + + 在这个阶段,我们建议您æµè§ˆä¸€ä¸‹\l{All Overviews and HOWTOs}{简介},然åŽé˜…è¯»ä¸Žæ‚¨é¡¹ç›®ç›¸å…³çš„ç« èŠ‚ã€‚æ‚¨å¯èƒ½è¿˜ä¼šå‘现,æµè§ˆä¸Žæ‚¨é¡¹ç›®ç±»ä¼¼çš„\l{Qt Examples}{示例}çš„æºä»£ç 也会对您有所帮助。由于 Qt æºä»£ç å·²é¢å‘公众开放,您也å¯é˜…读 Qt æºä»£ç 。 + + 如果您è¿è¡Œ\l{Examples and Demos Launcher}{示例和演示å¯åŠ¨ç¨‹åº},您就会看到许多æ£åœ¨ä½¿ç”¨çš„ Qt widget。 + + \l{Qt Widget Gallery} 还按照在ä¸åŒæ”¯æŒå¹³å°ä¸Šçš„ä½¿ç”¨é£Žæ ¼æ供了精选 Qt widget 简介。 + \clearfloat + + \section1 Books and Learning Materials + + Qt 附带大é‡æ–‡æ¡£ï¼Œå¹¶å…¨æ–‡å¸¦æœ‰è¶…文本交å‰å¼•ç”¨ï¼Œå¯è½»æ¾åœ°ç‚¹å‡»äº†è§£è‡ªå·±æƒ³çŸ¥é“的内容。您使用最多的文档å¯èƒ½æ˜¯ \l{index.html}{API 引用}。æ¯ä¸ªé“¾æŽ¥éƒ½æ供了æµè§ˆ API 引用的ä¸åŒæ–¹å¼ï¼Œæ‚¨å¯æ¯ä¸ªéƒ½å°è¯•ä¸€ä¸‹ï¼Œçœ‹å“ªä¸ªæ›´é€‚åˆè‡ªå·±ã€‚您还å¯ä»¥å°è¯• \l{Qt Assistant}ï¼Œè¿™æ˜¯éš Qt 附带的工具,å¯è®¿é—®å…¨éƒ¨ Qt API,并æ供全文本æœç´¢åŠŸèƒ½ã€‚ + + 有大é‡çš„书ç±æ˜¯å…³äºŽ Qt 编程的。有关 Qt 书ç±çš„完整列表。 + We recommend the official Qt book, + \l{http://www.amazon.com/gp/product/0132354160/ref=ase_trolltech/}{C++ + GUI Programming with Qt 4, Second Edition} (ISBN 0-13-235416-0). + 本书从 "Hello Qt" 到高级功能(如多线程ã€2D å’Œ 3D 图形ã€ç½‘络ã€å†…容视图类与 XML),全é¢è¯¦å®žåœ°è¯´æ˜Žäº† Qt 编程。(第一版基于 Qt 4.1,å¯\l{http://www.qtrac.eu/C++-GUI-Programming-with-Qt-4-1st-ed.zip}{在线}获得。) + + 包括ä¸åŒè¯è¨€çš„翻译版本,请å‚è§\l{Books about Qt Programming}{有关 Qt 编程的书ç±}。 + + å¦ä¸€ä¸ªæœ‰å…³å®žä¾‹ä»£ç å’Œ Qt 功能说明的有用资æºå°±æ˜¯å˜æ¡£çš„ \l{Qt Quarterly}{Qt å£è®¯}æ–‡ç« ï¼Œå£è®¯æ˜¯ä¸º Qt 用户æ供的新闻时讯。 + + 有关特定 Qt 模å—和其他指å—的文档,请å‚è§\l{All Overviews and HOWTOs}。 + + \section1 Further Reading + + Qt has an active and helpful user community who communicate using + the \l{Qt Mailing Lists}{qt-interest} mailing list, the \l{Qt Centre} + Web site, and a number of other community Web sites and Weblogs. + In addition, many Qt developers are active members of the + \l{KDE}{KDE community}. + + ç¥æ‚¨å¥½è¿å¹¶ä¸”å¦ä¹ æ„‰å¿«ï¼ +*/ diff --git a/doc/src/zh_CN/getting-started/tutorials.qdoc b/doc/src/zh_CN/getting-started/tutorials.qdoc new file mode 100644 index 0000000..dc371d8 --- /dev/null +++ b/doc/src/zh_CN/getting-started/tutorials.qdoc @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page tutorials.html + \title 教程 + + \contentspage 如何å¦ä¹ Qt + + \brief Tutorials, guides and overviews to help you learn Qt. + + A collection of tutorials and "walkthrough" guides are provided with Qt to + help new users get started with Qt development. These documents cover a + range of topics, from basic use of widgets to step-by-step tutorials that + show how an application is put together. + + \table + \row + \o{2,1} \l{Widgets 教程}{\bold Widgets} + \o{2,1} \l{地å€ç°¿æ•™ç¨‹}{\bold {地å€ç°¿}} + \row + \o \image widget-examples.png Widgets + \o + A beginner's guide to getting started with widgets and layouts to create + GUI applications. + + \o \image addressbook-tutorial.png 地å€ç°¿ + \o + A seven part guide to creating a fully-functioning address book + application. This tutorial is also available with + \l{Tutoriel "Carnet d'adresses"}{French explanation}. + + \row + \o{2,1} \l{A Quick Start to Qt Designer}{\bold{Qt Designer}} + \o{2,1} \l{Qt Linguist Manual: Programmers#Tutorials}{\bold {Qt Linguist}} + \row + \o \image designer-examples.png QtDesigner + \o + A quick guide through \QD showing the basic steps to create a + form with this interactive tool. + + \o \image linguist-examples.png QtLinguist + \o + A guided tour through the translations process, explaining the + tools provided for developers, translators and release managers. + + \row + \o{2,1} \l{QTestLib Tutorial}{\bold QTestLib} + \o{2,1} \l{qmake Tutorial}{\bold qmake} + \row + \o{2,1} + This tutorial gives a short introduction to how to use some of the + features of Qt's unit-testing framework, QTestLib. It is divided into + four chapters. + + \o{2,1} + This tutorial teaches you how to use \c qmake. We recommend that + you read the \l{qmake Manual}{qmake user guide} after completing + this tutorial. + + \endtable +*/ diff --git a/doc/src/zh_CN/tutorials/addressbook.qdoc b/doc/src/zh_CN/tutorials/addressbook.qdoc new file mode 100644 index 0000000..72349af --- /dev/null +++ b/doc/src/zh_CN/tutorials/addressbook.qdoc @@ -0,0 +1,673 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page tutorials-addressbook.html + + \startpage {index.html}{Qt Reference Documentation} + \contentspage 教程 + \nextpage {tutorials/addressbook/part1}{ç¬¬ä¸€ç« } + + \title 地å€ç°¿æ•™ç¨‹ + \brief 本教程介ç»äº†ä½¿ç”¨ Qt 跨平å°æ¡†æž¶çš„ GUI 编程。 + + 本教程介ç»äº†ä½¿ç”¨ Qt 跨平å°æ¡†æž¶çš„ GUI 编程。 + + \image addressbook-tutorial-screenshot.png + + \omit + It doesn't cover everything; the emphasis is on teaching the programming + philosophy of GUI programming, and Qt's features are introduced as needed. + Some commonly used features are never used in this tutorial. + \endomit + + 在å¦ä¹ 过程ä¸ï¼Œæˆ‘们将了解部分 Qt 基本技术,如 + + \list + \o Widget 和布局管ç†å™¨ + \o 容器类 + \o ä¿¡å·å’Œæ§½ + \o 输入和输出设备 + \endlist + + 如果您完全ä¸äº†è§£ Qt,请阅读\l{How to Learn Qt}{如何å¦ä¹ Qt}(如果您还未阅读)。 + + 教程的æºä»£ç ä½äºŽ Qt çš„ \c examples/tutorials/addressbook 目录下。 + + æ•™ç¨‹ç« èŠ‚ï¼š + + \list 1 + \o \l{tutorials/addressbook/part1}{设计用户界é¢} + \o \l{tutorials/addressbook/part2}{æ·»åŠ åœ°å€} + \o \l{tutorials/addressbook/part3}{æµè§ˆåœ°å€ç°¿æ¡ç›®} + \o \l{tutorials/addressbook/part4}{ç¼–è¾‘å’Œåˆ é™¤åœ°å€} + \o \l{tutorials/addressbook/part5}{æ·»åŠ æŸ¥æ‰¾åŠŸèƒ½} + \o \l{tutorials/addressbook/part6}{åŠ è½½å’Œä¿å˜} + \o \l{tutorials/addressbook/part7}{é™„åŠ åŠŸèƒ½} + \endlist + + 虽然这个å°åž‹åº”用程åºçœ‹èµ·æ¥å¹¶ä¸è±¡ä¸€ä¸ªæˆç†Ÿçš„现代 GUI 应用程åºï¼Œä½†å®ƒä½¿ç”¨å¤šç§ç”¨äºŽæ›´å¤æ‚应用程åºçš„基本技术。在您完æˆå¦ä¹ 之åŽï¼Œæˆ‘们建议您查看一下\l{mainwindows/application}{应用程åº}示例,它æ供带有èœå•ã€å·¥å…·æ ã€çŠ¶æ€æ ç‰é¡¹ç›®çš„å°åž‹ GUI 应用程åºã€‚ +*/ + +/*! + \page tutorials-addressbook-part1.html + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part2}{ç¬¬äºŒç« } + \example tutorials/addressbook/part1 + \title 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·ç•Œé¢ + + 本教程的第一部分讲述了用于地å€ç°¿åº”用程åºçš„åŸºæœ¬å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 的设计。 + + 创建 GUI 程åºçš„第一æ¥å°±æ˜¯è®¾è®¡ç”¨æˆ·ç•Œé¢ã€‚åœ¨æœ¬ç« ä¸ï¼Œæˆ‘ä»¬çš„ç›®æ ‡æ˜¯è®¾ç½®åº”ç”¨åŸºæœ¬åœ°å€ç°¿åº”用程åºæ‰€éœ€çš„æ ‡ç¾å’Œè¾“å…¥å—段。下图为期望输出的å±å¹•æˆªå›¾ã€‚ + + \image addressbook-tutorial-part1-screenshot.png + + 我们需è¦ä½¿ç”¨ä¸¤ä¸ª QLabel 对象:\c nameLabel å’Œ \c addressLabel,以åŠä¸¤ä¸ªè¾“å…¥å—段:QLineEdit 对象 \c nameLine å’Œ QTextEdit + 对象 \c addressTextï¼Œè¿™æ ·ç”¨æˆ·æ‰èƒ½è¾“å…¥è”系人的姓å和地å€ã€‚使用的 widget åŠå…¶ä½ç½®å¦‚下图所示。 + + \image addressbook-tutorial-part1-labeled-screenshot.png + + è¦åº”用地å€ç°¿éœ€ä½¿ç”¨ä¸‰ä¸ªæ–‡ä»¶ï¼š + + \list + \o \c{addressbook.h} — AddressBook 类的定义文件, + \o \c{addressbook.cpp} — AddressBook ç±»çš„æ‰§è¡Œæ–‡ä»¶ï¼Œä»¥åŠ + \o \c{main.cpp} — åŒ…å« \c main() 函数并带有 AddressBook 实例的文件。 + \endlist + + \section1 Qt 编程 — 使用åç±» + + 在编写 Qt 程åºæ—¶ï¼Œæˆ‘们通常使用 Qt 对象åç±»æ¥æ·»åŠ 功能。这是创建定制 widget æˆ–æ ‡å‡† widget 集åˆçš„基本概念之一。使用åç±»æ‰©å±•æˆ–æ”¹å˜ widget çš„æ“作具有以下优势: + + \list + \o 我们å¯ä»¥ç¼–写虚函数或纯虚函数应用,以得到我们确切所需的功能,并在需è¦æ—¶å†ä½¿ç”¨åŸºæœ¬çš„类应用。 + \o è¿™æ ·æˆ‘ä»¬å°±å¯ä»¥åœ¨ç±»ä¸å°è£…部分用户界é¢ï¼Œåº”用程åºçš„å…¶ä»–éƒ¨åˆ†ä¹Ÿå°±æ— éœ€äº†è§£ç”¨æˆ·ç•Œé¢ä¸å•ç‹¬ä½¿ç”¨çš„ widget。 + \o å¯ä½¿ç”¨å类在åŒä¸€åº”用程åºæˆ–库ä¸åˆ›å»ºå¤šä¸ªå®šåˆ¶ widgetï¼Œè¿™æ ·å类的代ç å¯åœ¨å…¶ä»–项目é‡å¤ä½¿ç”¨ã€‚ + \endlist + + 由于 Qt 未æ供特定的地å€ç°¿ widgetï¼Œæˆ‘ä»¬åœ¨æ ‡å‡†çš„ Qt widget ç±»ä¸ä½¿ç”¨å类,然åŽæ·»åŠ 功能。我们在本教程ä¸åˆ›å»ºçš„ \c AddressBook 类在需è¦ä½¿ç”¨åŸºæœ¬åœ°å€ç°¿ widget 的情况下å¯é‡å¤ä½¿ç”¨ã€‚ + + \section1 定义 AddressBook ç±» + + \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} 文件用于定义 \c AddressBook 类。 + + 我们从定义 \c AddressBook 为 QWidget åç±»å’Œå£°æ˜Žæž„é€ å™¨å¼€å§‹å…¥æ‰‹ã€‚æˆ‘ä»¬è¿˜ä½¿ç”¨ Q_OBJECT å®è¡¨æ˜Žè¯¥ç±»ä½¿ç”¨å›½é™…化功能与 Qt ä¿¡å·å’Œæ§½åŠŸèƒ½ï¼Œå³ä½¿åœ¨æœ¬é˜¶æ®µä¸ä¼šç”¨åˆ°æ‰€æœ‰è¿™äº›åŠŸèƒ½ã€‚ + + \snippet tutorials/addressbook/part1/addressbook.h class definition + + 该类包å«äº† \c nameLine å’Œ \c addressText 的声明ã€ä¸Šæ–‡æ到的 QLineEdit å’Œ QTextEdit çš„ç§æœ‰å®žä¾‹ã€‚在以åŽç« 节ä¸ï¼Œæ‚¨ä¼šçœ‹åˆ°å‚¨å˜åœ¨ \c nameLine å’Œ \c addressText ä¸çš„æ•°æ®åœ¨åœ°å€ç°¿çš„许多功能ä¸éƒ½ä¼šç”¨åˆ°ã€‚ + + 我们ä¸å¿…包å«è¦ä½¿ç”¨çš„ QLabel å¯¹è±¡çš„å£°æ˜Žï¼Œè¿™æ˜¯å› ä¸ºåœ¨åˆ›å»ºè¿™äº›å¯¹è±¡åŽæˆ‘们ä¸å¿…对其进行引用。在下一部分ä¸ï¼Œæˆ‘们会说明 Qt 记录对象所属关系的方å¼ã€‚ + + Q_OBJECT å®æœ¬èº«åº”用了部分更高级的 Qt 功能。 我们暂时把 Q_OBJECT å®ç†è§£ä¸ºä½¿ç”¨ \l{QObject::}{tr()} å’Œ \l{QObject::}{connect()} 函数的快æ·æ–¹å¼ï¼Œè¿™ç§ç†è§£å¯¹æˆ‘们的å¦ä¹ 更有用。 + + æˆ‘ä»¬çŽ°å·²å®Œæˆ \c addressbook.h 文件,接下æ¥æˆ‘们æ¥æ‰§è¡Œå¯¹åº”çš„ \c addressbook.cpp 文件。 + + \section1 应用 AddressBook ç±» + + \c AddressBook çš„æž„é€ å™¨æŽ¥æ”¶ QWidget å‚æ•° \a parent。按惯例,我们将å‚æ•°ä¼ é€’ç»™åŸºæœ¬ç±»çš„æž„é€ å™¨ã€‚è¿™ç§çˆ¶é¡¹å¯æœ‰ä¸€ä¸ªæˆ–多个å项的所属概念对 Qt ä¸çš„ widget 分组ååˆ†æœ‰ç”¨ã€‚ä¾‹å¦‚ï¼Œå¦‚æžœåˆ é™¤çˆ¶é¡¹ï¼Œä¹Ÿä¼šåˆ é™¤å…¶æ‰€æœ‰å项。 + + \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields + + åœ¨è¯¥æž„é€ å™¨ä¸ï¼Œæˆ‘们声明并通过实例æ¥è¡¨ç¤ºä¸¤ä¸ªå±€éƒ¨ QLabel 对象 \c nameLabel å’Œ \c addressLabelï¼Œä»¥åŠ \c nameLine å’Œ \c addressText。如果å—符串已进行转æ¢ï¼Œåˆ™ \l{QObject::tr()}{tr()} 函数返回已转æ¢çš„å—符串,å¦åˆ™è¿”回å—符串本身。我们å¯ä»¥å°†æ¤å‡½æ•°ç†è§£ \c{<insert translation here>} æ ‡è¯†æ¥æ ‡è®°è¦è¿›è¡Œè½¬æ¢ QString 对象。在以åŽç« 节和 \l{Qt Examples} ä¸ï¼Œæ‚¨ä¼šçœ‹åˆ°åªè¦ä½¿ç”¨äº†å¯è½¬æ¢çš„å—符串就是使用该函数。 + + 使用 Qt 编程时,了解布局是如何起作用的会对您很有帮助。Qt æ供三个主è¦å¸ƒå±€ç±» QHBoxLayoutã€QVBoxLayout å’Œ QGridLayout æ¥å¤„ç† widget çš„ä½ç½®ã€‚ + + \image addressbook-tutorial-part1-labeled-layout.png + + 我们使用 QGridLayout 以结构化的方å¼æ”¾ç½®æ ‡ç¾å’Œè¾“å…¥å—段。QGridLayout å°†å¯ç”¨ç©ºé—´åˆ†ä¸ºç½‘æ ¼ï¼Œå¹¶å°† widget 放置在指定了行列å·çš„å•å…ƒæ ¼ä¸ã€‚上é¢çš„图表显示了布局å•å…ƒæ ¼å’Œ widget çš„ä½ç½®ã€‚我们通过以下代ç 指定这ç§æŽ’列方å¼ï¼š + + \snippet tutorials/addressbook/part1/addressbook.cpp layout + + 请注æ„,\c addressLabel æ˜¯ä½¿ç”¨ä½œä¸ºé™„åŠ å‚æ•°çš„ Qt::AlignTop æ¥æŽ’放ä½ç½®ã€‚è¿™å¯ç¡®ä¿å…¶ä¸ä¼šçºµå‘放置在å•å…ƒæ ¼ (1,0) ä¸å¤®ã€‚有关 Qt 布局的基本简介,请å‚è§\l{Layout Management}{布局类}文档。 + + è¦åœ¨ widget 上安装布局对象,必须调用 widget çš„ \l{QWidget::setLayout()}{setLayout()} 函数: + + \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout + + 最åŽï¼Œæˆ‘们将 widget æ ‡é¢˜è®¾ç½®ä¸ºâ€œç®€å•åœ°å€ç°¿â€ã€‚ + + \section1 è¿è¡Œåº”ç”¨ç¨‹åº + + \c main() 函数使用å•ç‹¬çš„文件 \c main.cpp。在该函数ä¸ï¼Œæˆ‘们实例化了 QApplication 对象 \c app。QApplication 负责管ç†å¤šç§åº”用范围的资æºï¼ˆå¦‚默认å—ä½“å’Œå…‰æ ‡ï¼‰ï¼Œä»¥åŠè¿è¡Œäº‹ä»¶å¾ªçŽ¯ã€‚å› æ¤ï¼Œåœ¨æ¯ä¸ªä½¿ç”¨ Qt çš„ GUI 应用程åºä¸éƒ½ä¼šæœ‰ä¸€ä¸ª QApplication 对象。 + + \snippet tutorials/addressbook/part1/main.cpp main function + + 我们使用 new 关键å—åœ¨å †ä¸æž„é€ ä¸€ä¸ªæ–°çš„ \c AddressBook widget,然åŽè°ƒç”¨ \l{QWidget::show()}{show()} 函数对其进行显示。ä¸è¿‡ï¼Œè¯¥ widget åªæœ‰åœ¨åº”用程åºäº‹ä»¶å¾ªçŽ¯å¼€å§‹æ—¶æ‰ä¼šæ˜¾ç¤ºã€‚我们通过调用应用程åºçš„ \l{QApplication::}{exec()} 函数开始事件循环。该函数返回的结果作为 \c main() 函数的返回值。 +*/ + +/*! + \page tutorials-addressbook-part2.html + \previouspage 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·ç•Œé¢ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part3}{ç¬¬ä¸‰ç« } + \example tutorials/addressbook/part2 + \title 地å€ç°¿ 2 — æ·»åŠ åœ°å€ + + 创建基本地å€ç°¿åº”用程åºçš„下一æ¥æ˜¯æ·»åŠ 少许用户互动æ“作。 + + \image addressbook-tutorial-part2-add-contact.png + + 我们将æ供一个按钮,用户å¯ç‚¹å‡»è¯¥æŒ‰é’®æ¥æ·»åŠ æ–°è”系人。æ¤å¤–,还需è¦å¯¹æ•°æ®ç»“构进行é™å®šï¼Œä»¥ä¾¿æœ‰åºåœ°å‚¨å˜è¿™äº›è”系人。 + + \section1 定义 AddressBook ç±» + + 由于已ç»è®¾ç½®äº†æ ‡ç¾å’Œè¾“å…¥å—段,我们åªéœ€æ·»åŠ 按钮就å¯å®Œæˆæ·»åŠ è”系人这一æ¥éª¤ã€‚也就是说,在 \c addressbook.h 文件ä¸å·²ç»å£°æ˜Žäº†ä¸‰ä¸ª QPushButton 对象和三个对应的公共槽。 + + \snippet tutorials/addressbook/part2/addressbook.h slots + + 槽是对特殊信å·è¿›è¡Œå“应的函数。我们将在应用 \c AddressBook 类时进一æ¥è¯¦ç»†è¯´æ˜Žè¿™ä¸€æ¦‚念。如需有关 Qt ä¿¡å·å’Œæ§½æ¦‚念的简介,请å‚è§\l{Signals and Slots}{ä¿¡å·å’Œæ§½}文档。 + + 三个 QPushButton 对象分别是 \c addButtonã€\c submitButton å’Œ \c cancelButton,已与è¦åœ¨ä¸Šä¸€ç« ä¸è¯´æ˜Žçš„ \c nameLine å’Œ \c addressText 一åŒåŒ…å«åœ¨ç§æœ‰å˜é‡å£°æ˜Žä¸ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration + + 我们需è¦ä¸€ä¸ªå®¹å™¨æ¥å‚¨å˜åœ°å€ç°¿è”ç³»äººï¼Œè¿™æ ·æ‰èƒ½æœç´¢å’Œæ˜¾ç¤ºè”系人。QMap 对象 \c contacts å°±å¯å®žçŽ°æ¤åŠŸèƒ½ï¼Œå› 为其带有一个键-值对:è”系人姓å作为键,而è”系人地å€ä½œä¸º\e{值}。 + + \snippet tutorials/addressbook/part2/addressbook.h remaining private variables + + 我们还会声明两个ç§æœ‰ QString 对象:\c oldName å’Œ \c oldAddress。这些对象用æ¥ä¿ç•™åœ¨ç”¨æˆ·ç‚¹å‡»\gui{æ·»åŠ }时最åŽæ˜¾ç¤ºçš„è”系人姓å和地å€ã€‚è¿™æ ·ï¼Œå½“ç”¨æˆ·ç‚¹å‡»\gui{å–消}时,我们就å¯ä»¥è¿”回至上一个è”系人的详细信æ¯ã€‚ + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook æž„é€ å™¨ä¸ï¼Œæˆ‘们将 \c nameLine å’Œ \c addressText 设置为åªè¯»ï¼Œè¿™æ ·å°±å¯ä»…显示而ä¸å¿…编辑现有è”系人的详细信æ¯ã€‚ + + \dots + \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1 + \dots + \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2 + + 然åŽï¼Œæˆ‘们实例化以下按钮:\c addButtonã€\c submitButton å’Œ \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration + + 显示 \c addButton 是通过调用 \l{QPushButton::show()}{show()} 函数实现的,而éšè— \c submitButton å’Œ \c cancelButton 则需调用 \l{QPushButton::hide()}{hide()}。这两个按钮仅当用户点击\gui{æ·»åŠ }æ—¶æ‰ä¼šæ˜¾ç¤ºï¼Œè€Œæ¤æ“作是通过在下文ä¸è¯´æ˜Žçš„\c addContact() 函数处ç†çš„。 + + \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots + + 我们将按钮的 \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。下é¢çš„图表说明了æ¤è¿‡ç¨‹ã€‚ + + \image addressbook-tutorial-part2-signals-and-slots.png + + 接下æ¥ï¼Œæˆ‘们将按钮整é½çš„排列在地å€ç°¿ widget çš„å³ä¾§ï¼Œä½¿ç”¨ QVBoxLayout 将其进行纵å‘排列。 + + \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout + + \l{QBoxLayout::addStretch()}{addStretch()} 函数用æ¥ç¡®ä¿æŒ‰é’®å¹¶ä¸æ˜¯é‡‡ç”¨å‡åŒ€é—´éš”排列的,而是更é è¿‘ widget 的顶部。下图显示了是å¦ä½¿ç”¨ \l{QBoxLayout::addStretch()}{addStretch()} 的差别。 + + \image addressbook-tutorial-part2-stretch-effects.png + + 然åŽï¼Œæˆ‘们使用 \l{QGridLayout::addLayout()}{addLayout()} å°† \c buttonLayout1 å¢žåŠ è‡³ \c mainLayout。 è¿™æ ·æˆ‘ä»¬å°±æœ‰äº†åµŒå¥—å¸ƒå±€ï¼Œå› ä¸º \c buttonLayout1 现在是 \c mainLayout çš„å项。 + + \snippet tutorials/addressbook/part2/addressbook.cpp grid layout + + 布局åæ ‡æ˜¾ç¤ºå¦‚ä¸‹ï¼š + + \image addressbook-tutorial-part2-labeled-layout.png + + 在 \c addContact() 函数ä¸ï¼Œæˆ‘们使用 \c oldName å’Œ \c oldAddress 储å˜æœ€åŽæ˜¾ç¤ºçš„è”系人详细信æ¯ã€‚然åŽï¼Œæˆ‘们清空这些输入å—段并关é—åªè¯»æ¨¡å¼ã€‚输入焦点设置在 \c nameLine,显示 \c submitButton å’Œ \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp addContact + + \c submitContact() 函数å¯åˆ†ä¸ºä¸‰ä¸ªéƒ¨åˆ†ï¼š + + \list 1 + \o 我们从 \c nameLine å’Œ \c addressText æå–è”系人的详细信æ¯ï¼Œç„¶åŽå°†å…¶å‚¨å˜åœ¨ QString 对象ä¸ã€‚我们还è¦éªŒè¯ç¡®ä¿ç”¨æˆ·æ²¡æœ‰åœ¨è¾“å…¥å—段为空时点击\gui{æ交},å¦åˆ™ï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户输入姓å和地å€ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1 + + \o 我们接ç€ç»§ç»æ£€æŸ¥æ˜¯å¦è”系人已å˜åœ¨ã€‚如果ä¸å˜åœ¨ï¼Œå°†è”ç³»äººæ·»åŠ è‡³ \c contacts,然åŽæ˜¾ç¤º QMessageBox æç¤ºç”¨æˆ·å·²æ·»åŠ è”系人。 + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2 + + 如果è”系人已å˜åœ¨ï¼Œè¿˜æ˜¯ä¼šæ˜¾ç¤º QMessageBox 以æ示用户,以å…æ·»åŠ é‡å¤çš„è”系人。由于 \c contacts 对象是基于姓å地å€çš„é”®-å€¼å¯¹ï¼Œå› æ¤è¦ç¡®ä¿é”®å”¯ä¸€ã€‚ + + \o 在处ç†äº†ä¸Šè¿°ä¸¤ç§æƒ…况åŽï¼Œä½¿ç”¨ä»¥ä¸‹ä»£ç 将按钮æ¢å¤ä¸ºæ£å¸¸çŠ¶æ€ï¼š + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3 + + \endlist + + 下é¢çš„å±å¹•æˆªå›¾æ˜¾ç¤ºäº†ç”¨äºŽå‘用户显示æ示信æ¯çš„ QMessageBox 对象。 + + \image addressbook-tutorial-part2-add-successful.png + + \c cancel() 函数æ¢å¤ä¸Šæ¬¡æ˜¾ç¤ºçš„è”系人详细信æ¯ï¼Œå¹¶å¯ç”¨ \c addButton,还会éšè— \c submitButton å’Œ + \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp cancel + + æ·»åŠ è”系人的总体æ€æƒ³å°±æ˜¯æ高用户æ“作的çµæ´»æ€§ï¼Œå¯åœ¨ä»»ä½•æ—¶å€™ç‚¹å‡»\gui{æ交}或\gui{å–消}。下é¢çš„æµç¨‹å›¾è¯¦ç»†è¯´æ˜Žäº†æ¤æ¦‚念: + + \image addressbook-tutorial-part2-add-flowchart.png +*/ + +/*! + \page tutorials-addressbook-part3.html + \previouspage 地å€ç°¿ 2 — æ·»åŠ åœ°å€ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part4}{ç¬¬å››ç« } + \example tutorials/addressbook/part3 + \title 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›® + + 构建地å€ç°¿åº”用程åºçŽ°å·²è¿›å±•è¿‡åŠã€‚我们需è¦å¢žåŠ 一些函数,以便æµè§ˆè”系人。但首先è¦å†³å®šé‡‡ç”¨ä½•ç§æ•°æ®ç»“æž„æ–¹å¼æ¥å‚¨å˜è¿™äº›è”系人。 + + åœ¨ç¬¬äºŒç« ä¸ï¼Œæˆ‘们使用了 QMap é”®-值对,å³è”系人姓å作为\e{é”®},而è”系人地å€ä½œä¸º\e{值}。这ç§æ–¹å¼å¾ˆé€‚åˆæˆ‘们的实例。ä¸è¿‡ï¼Œè¦æµè§ˆå’Œæ˜¾ç¤ºæ¯ä¸ªæ¡ç›®ï¼Œè¿˜éœ€è¦è¿›è¡Œä¸€äº›æ”¹è¿›ã€‚ + + 我们改进 QMap çš„æ–¹å¼æ˜¯ï¼Œå°†æ•°æ®ç»“构替æ¢ä¸ºç±»ä¼¼å¾ªçŽ¯é“¾æŽ¥çš„列表,其ä¸æ‰€æœ‰å…ƒç´ 都是相互关è”çš„ï¼ŒåŒ…æ‹¬ç¬¬ä¸€ä¸ªå…ƒç´ å’Œæœ€åŽä¸€ä¸ªå…ƒç´ 。下图图解说明了该数æ®ç»“构。 + + \image addressbook-tutorial-part3-linkedlist.png + + \section1 定义 AddressBook ç±» + + è¦ç»™åœ°å€ç°¿åº”用程åºå¢žåŠ æµè§ˆåŠŸèƒ½ï¼Œæˆ‘们需è¦ä¸º \c AddressBook ç±»å†å¢žåŠ 两个函数:\c next() å’Œ \c previous()ã€‚å°†è¿™ä¸¤ä¸ªå‡½æ•°æ·»åŠ åˆ° \c addressbook.h 文件ä¸ï¼š + + \snippet tutorials/addressbook/part3/addressbook.h navigation functions + + 我们还需è¦ä½¿ç”¨å…¶ä»–两个 QPushButton å¯¹è±¡ï¼Œå› æ¤å°† \c nextButton å’Œ \c previousButton 声明为ç§æœ‰å˜é‡ï¼š + + \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook çš„ \c addressbook.cpp æž„é€ å™¨ä¸ï¼Œæˆ‘们实例化 \c nextButton å’Œ \c previousButton,并且这两项默认为ç¦ç”¨ã€‚è¿™æ˜¯å› ä¸ºä»…å½“åœ°å€ç°¿ä¸æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨æµè§ˆåŠŸèƒ½ã€‚ + + \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons + + 然åŽï¼Œæˆ‘们将这两个按钮与其相应的槽关è”: + + \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals + + 下图å³ä¸ºé¢„期的图形用户界é¢ã€‚请注æ„,该用户界é¢å·²å¾ˆæŽ¥è¿‘应用程åºæœ€ç»ˆçš„æ ·å。 + + \image addressbook-tutorial-part3-screenshot.png + + 我们按照 \c next() å’Œ \c previous() 函数的基本规范,将 \c nextButton 放置在å³ä¾§ï¼Œè€Œ \c previousButton æ”¾ç½®åœ¨å·¦ä¾§ã€‚ä¸ºäº†ä½¿å¸ƒå±€æ›´åŠ ç›´è§‚ï¼Œæˆ‘ä»¬ä½¿ç”¨ QHBoxLayout å°† widget 并排放置: + + \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout + + 然åŽï¼Œå°† QHBoxLayout 对象 \c buttonLayout2 å¢žåŠ è‡³ \c mainLayout。 + + \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout + + 下图显示了 widget 在 \c mainLayout ä¸çš„åæ ‡ä½ç½®ã€‚ + + \image addressbook-tutorial-part3-labeled-layout.png + + 在 \c addContact() 函数ä¸ï¼Œæˆ‘们必须ç¦ç”¨è¿™å‡ ä¸ªæŒ‰é’®ï¼Œè¿™æ ·ç”¨æˆ·å°±ä¸ä¼šåœ¨å¢žåŠ è”系人时å°è¯•è¿›è¡Œæµè§ˆã€‚ + + \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation + + æ¤å¤–,在 \c submitContact() 函数ä¸ï¼Œæˆ‘们å¯ç”¨äº†æµè§ˆæŒ‰é’® \c nextButton å’Œ \c previousButton,这å–决于 \c contacts 的多少。如上文所述,æµè§ˆåŠŸèƒ½ä»…在地å€ç°¿ä¸æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨ã€‚以下代ç 行说明了如何实现æ¤åŠŸèƒ½ï¼š + + \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation + + 我们还在 \c cancel() 函数ä¸åŠ å…¥è¿™å‡ è¡Œä»£ç 。 + + 记得我们曾使用 QMap 对象 \c contacts æ¨¡æ‹Ÿäº†ä¸€ä¸ªå¾ªçŽ¯é“¾æŽ¥çš„åˆ—è¡¨ã€‚å› æ¤ï¼Œåœ¨ \c next() 函数ä¸ï¼Œæˆ‘ä»¬èŽ·å– \c contacts çš„è¿ä»£å™¨ï¼Œç„¶åŽæ‰§è¡Œä»¥ä¸‹æ“作: + + \list + \o 如果è¿ä»£å™¨æœªè¾¾åˆ° \c contacts ç»“å°¾ï¼Œå°±ä¼šå¢žåŠ ä¸€ã€‚ + \o 如果è¿ä»£å™¨å·²è¾¾åˆ° \c contacts 的结尾,就移至 \c contacts 的起始ä½ç½®ã€‚这给人感觉 QMap å°±åƒæ˜¯ä¸€ä¸ªå¾ªçŽ¯é“¾æŽ¥çš„列表。 + \endlist + + \snippet tutorials/addressbook/part3/addressbook.cpp next() function + + 一旦在 \c contacts ä¸å¾ªçŽ¯è‡³æ£ç¡®çš„对象,就会通过 \c nameLine å’Œ \c addressText 显示对象的内容。 + + åŒæ ·ï¼Œåœ¨ \c previous() 函数ä¸ï¼Œæˆ‘ä»¬èŽ·å– \c contacts çš„è¿ä»£å™¨ï¼Œç„¶åŽæ‰§è¡Œä»¥ä¸‹æ“作: + + \list + \o 如果è¿ä»£å™¨è¾¾åˆ° \c contacts 的结尾,就清除显示内容,然åŽè¿”回。 + \o 如果è¿ä»£å™¨åœ¨ \c contacts 的起始ä½ç½®ï¼Œå°±å°†å…¶ç§»è‡³ç»“尾。 + \o 然åŽï¼Œå°†è¿ä»£å™¨å‡ä¸€ã€‚ + \endlist + + \snippet tutorials/addressbook/part3/addressbook.cpp previous() function + + 接ç€ï¼Œé‡æ–°æ˜¾ç¤º \c contacts ä¸å½“å‰å¯¹è±¡çš„内容。 +*/ + +/*! + \page tutorials-addressbook-part4.html + \previouspage 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›® + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part5}{ç¬¬äº”ç« } + \example tutorials/addressbook/part4 + \title 地å€ç°¿ 4 — ç¼–è¾‘å’Œåˆ é™¤åœ°å€ + + åœ¨æœ¬ç« ä¸ï¼Œæˆ‘们将了解如何修改储å˜åœ¨åœ°å€ç°¿åº”用程åºä¸çš„è”系人的内容。 + + \image addressbook-tutorial-screenshot.png + + 现有的地å€ç°¿ä¸ä»…å¯ä»¥äº•äº•æœ‰æ¡åœ°å‚¨å˜è”系人,还å¯è¿›è¡Œæµè§ˆã€‚å†æ·»åŠ ä¸Šç¼–è¾‘å’Œåˆ é™¤åŠŸèƒ½ï¼Œä»¥ä¾¿åœ¨éœ€è¦æ—¶æ›´æ”¹è”系人的详细信æ¯ï¼Œè¿™æ ·æ›´æ˜“于使用。ä¸è¿‡ï¼Œè¿˜éœ€ä½¿ç”¨ enum 类型进行一些改进。在å‰å‡ ç« ä¸ï¼Œæˆ‘们使用以下两ç§æ¨¡å¼ï¼š\c{AddingMode} å’Œ \c{NavigationMode}。但是,他们并未定义为 enum。我们是采用手动方å¼å¯ç”¨å’Œç¦ç”¨ç›¸åº”的按钮,这就导致有多行é‡å¤çš„代ç 。 + + åœ¨æœ¬ç« ä¸ï¼Œæˆ‘们定义带有以下三ç§ä¸åŒå€¼çš„ \c{Mode} enum 类型: + + \list + \o \c{NavigationMode}〠+ \o \c{AddingMode} å’Œ + \o \c{EditingMode}。 + \endlist + + \section1 定义 AddressBook ç±» + + \c addressbook.h æ–‡ä»¶å·²æ›´æ–°ä¸ºåŒ…å« Mode \c enum 类型: + + \snippet tutorials/addressbook/part4/addressbook.h Mode enum + + 我们还è¦å‘当å‰çš„å…¬æœ‰æ§½åˆ—è¡¨å¢žåŠ ä¸¤ä¸ªæ–°æ§½ï¼š\c editContact() å’Œ \c removeContact()。 + + \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots + + 为了在模å¼é—´åˆ‡æ¢ï¼Œæˆ‘们引入了 \c updateInterface() 函数æ¥æŽ§åˆ¶æ‰€æœ‰ QPushButton 对象的å¯ç”¨å’Œç¦ç”¨ã€‚è¦å®žçŽ°ä¸Šæ–‡æåŠçš„ç¼–è¾‘å’Œåˆ é™¤åŠŸèƒ½ï¼Œæˆ‘ä»¬è¿˜è¦å¢žåŠ 两个新按钮:\c editButton å’Œ \c removeButton。 + + \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration + \dots + \snippet tutorials/addressbook/part4/addressbook.h buttons declaration + \dots + \snippet tutorials/addressbook/part4/addressbook.h mode declaration + + 最åŽï¼Œæˆ‘们声明 \c currentMode æ¥è·Ÿè¸ª enum 的当å‰æ¨¡å¼ã€‚ + + \section1 应用 AddressBook ç±» + + 我们现在必须应用地å€ç°¿åº”用程åºçš„模å¼æ›´æ”¹åŠŸèƒ½ã€‚\c editButton å’Œ \c removeButton 已实例化并默认为ç¦ç”¨ï¼Œè¿™æ˜¯å› 为地å€ç°¿å¯åŠ¨æ—¶åœ¨å†…å˜ä¸æ²¡æœ‰è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons + + 这些按钮会与其相应的槽 \c editContact() å’Œ \c removeContact() å…³è”,然åŽæˆ‘ä»¬å°†å…¶æ·»åŠ è‡³ \c buttonLayout1。 + + \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove + \dots + \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout + + 在将模å¼åˆ‡æ¢åˆ° \c EditingMode 之å‰ï¼Œ\c editContact() 函数使用 \c oldName å’Œ \c oldAddress 储å˜è”系人旧的详细信æ¯ã€‚ 在该模å¼ä¸‹ï¼Œ\c submitButton å’Œ \c cancelButton å‡å·²å¯ç”¨ï¼Œè¿™æ ·ç”¨æˆ·å°±å¯ä»¥æ›´æ”¹è”系人的详细信æ¯å¹¶å¯ç‚¹å‡»ä»»ä½•ä¸€ä¸ªæŒ‰é’®ã€‚ + + \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function + + \c submitContact() 函数已被 \c{if-else} è¯å¥åˆ†ä¸ºä¸¤éƒ¨åˆ†ã€‚我们查看 \c currentMode 是å¦åœ¨ \c AddingMode 模å¼ä¸‹ã€‚如果是,我们继ç»æ·»åŠ æ“作。 + + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning + \dots + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1 + + å¦åˆ™ï¼Œæˆ‘们查看 \c currentMode 是å¦åœ¨ \c EditingMode 模å¼ä¸‹ã€‚如果是,我们比较 \c oldName å’Œ \c name。如果姓å已更改,我们从 \c contacts ä¸åˆ 除旧的è”系人并æ’入已更新的è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2 + + 如果仅更改了地å€ï¼ˆä¾‹å¦‚ \c oldAddress 与 \c address ä¸åŒï¼‰ï¼Œæˆ‘们就更新è”系人的地å€ã€‚最åŽï¼Œæˆ‘们将 \c currentMode 设置为 \c NavigationMode。这一æ¥è‡³å…³é‡è¦ï¼Œå› 为它会é‡æ–°å¯ç”¨æ‰€æœ‰å·²ç¦ç”¨çš„按钮。 + + è¦ä»Žåœ°å€ç°¿ä¸åˆ 除è”系人,我们采用 \c removeContact() 函数。该函数查看 \c contacts ä¸æ˜¯å¦åŒ…å«è¯¥è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function + + 如果有,我们显示 QMessageBoxï¼Œç¡®è®¤ç”¨æˆ·çš„åˆ é™¤æ“作。一旦用户确认æ“作,我们调用 \c previous() ç¡®ä¿ç”¨æˆ·ç•Œé¢æ˜¾ç¤ºå…¶ä»–è”系人,然åŽæˆ‘们使用 QMap çš„ \l{QMap::remove()}{remove()} å‡½æ•°åˆ é™¤å·²å·²ç¡®è®¤çš„è”系人。出于好æ„,我们会显示 QMessageBox æ示用户。在该函数ä¸ä½¿ç”¨ä¸¤ç§ä¿¡æ¯æ¡†æ˜¾ç¤ºå¦‚下: + + \image addressbook-tutorial-part4-remove.png + + \section2 æ›´æ–°ç”¨æˆ·ç•Œé¢ + + 我们在上文æ到 \c updateInterface() 函数,它å¯æ ¹æ®å½“å‰çš„模å¼å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚è¯¥å‡½æ•°ä¼šæ ¹æ®ä¼ 递给它的 \c mode å‚数更新当å‰çš„模å¼ï¼Œåœ¨æ ¡éªŒå€¼ä¹‹å‰å°†å‚数分é…ç»™ \c currentMode。 + + è¿™æ ·ï¼Œæ¯ä¸ªæŒ‰é’®å°±æ ¹æ®å½“å‰çš„模å¼è¿›è¡Œå¯ç”¨æˆ–ç¦ç”¨ã€‚\c AddingMode å’Œ \c EditingMode 的代ç 显示如下: + + \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1 + + ä¸è¿‡å¯¹äºŽ \c NavigationMode,我们在 QPushButton::setEnabled() 函数的å‚æ•°ä¸åŠ 入了æ¡ä»¶ã€‚è¿™æ ·å¯ç¡®ä¿ \c editButton å’Œ \c removeButton 在地å€ç°¿ä¸è‡³å°‘有一个è”系人的情况下å¯ç”¨ï¼Œè€Œ \c nextButton å’Œ \c previousButton 仅在地å€ç°¿ä¸æœ‰å¤šä¸ªè”系人时æ‰å¯ç”¨ã€‚ + + \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2 + + 通过在åŒä¸€å‡½æ•°ä¸è®¾ç½®æ¨¡å¼å’Œæ›´æ–°ç”¨æˆ·ç•Œé¢ï¼Œæˆ‘们å¯ä»¥é¿å…用户界é¢ä¸Žåº”用程åºå†…部状æ€ä¸åŒæ¥çš„å¯èƒ½æ€§ã€‚ +*/ + +/*! + \page tutorials-addressbook-part5.html + \previouspage 地å€ç°¿ 4 — ç¼–è¾‘å’Œåˆ é™¤åœ°å€ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part6}{第å…ç« } + \example tutorials/addressbook/part5 + \title 地å€ç°¿ 5 — æ·»åŠ æŸ¥æ‰¾åŠŸèƒ½ + + åœ¨æœ¬ç« ä¸ï¼Œæˆ‘们将了解如何在地å€ç°¿åº”用程åºä¸å®šä½è”系人和地å€ã€‚ + + \image addressbook-tutorial-part5-screenshot.png + + éšç€æˆ‘们ä¸æ–为地å€ç°¿åº”用程åºæ·»åŠ è”系人,使用下一个和上一个按钮æµè§ˆè”系人就会å˜å¾—很ç¹ç。在这ç§æƒ…况下,使用查找函数查找è”ç³»äººå°±ä¼šæ›´åŠ æœ‰æ•ˆã€‚ä¸Šé¢çš„å±å¹•æˆªå›¾æ˜¾ç¤ºäº†æŸ¥æ‰¾æŒ‰é’®åŠå…¶åœ¨æŒ‰é’®é¢æ¿ä¸Šçš„ä½ç½®ã€‚ + + 当用户点击查找按钮时,有必è¦æ˜¾ç¤ºä¸€ä¸ªå¯¹è¯æ¡†ï¼Œç”¨æˆ·å¯åœ¨å…¶ä¸è¾“å…¥è”系人的姓å。Qt æ供了 QDialogï¼ˆæˆ‘ä»¬ä¼šåœ¨æœ¬ç« ä¸å°†å…¶ç”¨ä½œå类),å¯ä½¿ç”¨ \c FindDialog 类。 + + \section1 定义 FindDialog ç±» + + \image addressbook-tutorial-part5-finddialog.png + + è¦ä½¿ç”¨ QDialog çš„å类,我们首先è¦åœ¨ \c finddialog.h 文件ä¸å£°æ˜Ž QDialog 的头信æ¯ã€‚æ¤å¤–,我们还使用å‘å‰ (forward) 声明æ¥å£°æ˜Ž QLineEdit å’Œ QPushButtonï¼Œè¿™æ ·æˆ‘ä»¬å°±èƒ½åœ¨å¯¹è¯æ¡†ç±»ä¸ä½¿ç”¨è¿™äº› widget。 + + å› ä¸ºåœ¨ \c AddressBook ç±»ä¸ï¼Œ\c FindDialog 类包å«äº† Q_OBJECT å®ï¼Œå¹¶ä¸”å…¶æž„é€ å™¨å·²å®šä¹‰ä¸ºæŽ¥æ”¶çˆ¶çº§ QWidget,å³ä½¿å¯¹è¯æ¡†ä»¥å•ç‹¬çš„窗å£æ–¹å¼æ‰“开。 + + \snippet tutorials/addressbook/part5/finddialog.h FindDialog header + + 我们定义了公有函数 \c getFindText(),供实例化 \c FindDialog çš„ç±»ä½¿ç”¨ï¼Œè¿™æ ·è¿™äº›ç±»å¯ä»¥èŽ·å–用户输入的文本。公有槽 \c findClicked() 定义为在用户点击\gui{查找}按钮时处ç†æœç´¢å—符串。 + + 最åŽï¼Œæˆ‘们定义ç§æœ‰å˜é‡ \c findButtonã€\c lineEdit å’Œ \c findText,分别对应\gui{查找}按钮ã€ç”¨æˆ·è¾“å…¥æœç´¢å—符串的行编辑框和储å˜æœç´¢å—符串供ç¨åŽä½¿ç”¨çš„内部å—符串。 + + \section1 应用 FindDialog ç±» + + 在 \c FindDialog çš„æž„é€ å™¨ä¸ï¼Œæˆ‘们设置ç§æœ‰å˜é‡ \c lineEditã€\c findButton å’Œ \c findText。使用 QHBoxLayout 放置 widget。 + + \snippet tutorials/addressbook/part5/finddialog.cpp constructor + + 我们设定布局和窗å£æ ‡é¢˜ï¼Œå¹¶å°†ä¿¡å·ä¸Žå…¶å„自的槽关è”。请注æ„,\c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·å·²ä¸Ž \c findClicked() å’Œ \l{QDialog::accept()}{accept()} å…³è”。QDialog æ供的 \l{QDialog::accept()}{accept()} 槽会éšè—对è¯æ¡†å¹¶å°†ç»“果代ç 设置为 \l{QDialog::}{Accepted}。我们使用该函数有助于 \c AddressBook çš„ \c findContact() 函数知晓 \c FindDialog 对象关é—的时间。我们在讨论 \c findContact() 函数时将对该函数åšè¿›ä¸€æ¥è¯´æ˜Žã€‚ + + \image addressbook-tutorial-part5-signals-and-slots.png + + 在 \c findClicked() ä¸ï¼Œæˆ‘ä»¬éªŒè¯ \c lineEdit 以确ä¿ç”¨æˆ·æ²¡æœ‰åœ¨å°šæœªè¾“å…¥è”系人姓å时就点击\gui{查找}按钮。然åŽï¼Œæˆ‘们将 \c findText 设置为从 \c lineEdit æå–çš„æœç´¢å—符串。之åŽï¼Œæˆ‘们清空 \c lineEdit 的内容并éšè—对è¯æ¡†ã€‚ + + \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function + + \c findText å˜é‡å·²æœ‰å…¬æœ‰ getter 函数 \c getFindText() 与其相关è”ã€‚æ—¢ç„¶æˆ‘ä»¬ä»…åœ¨æž„é€ å™¨å’Œ \c findClicked() 函数ä¸ç›´æŽ¥è®¾å®šäº† \c findText, 我们就ä¸åœ¨åˆ›å»º \c getFindText() çš„åŒæ—¶å†åˆ›å»º setter 函数。由于 \c getFindText() 是公有的,实例化和使用 \c FindDialog çš„ç±»å¯å§‹ç»ˆè¯»å–用户已输入并确认的æœç´¢å—符串。 + + \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function + + \section1 定义 AddressBook ç±» + + è¦ç¡®ä¿æˆ‘们å¯ä½¿ç”¨ \c AddressBook ç±»ä¸çš„ \c FindDialog,我们è¦åœ¨ \c addressbook.h 文件ä¸åŒ…å« \c finddialog.h。 + + \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header + + 至æ¤ï¼Œæ‰€æœ‰åœ°å€ç°¿åŠŸèƒ½éƒ½æœ‰äº† QPushButton 和对应的槽。åŒæ ·ï¼Œ\gui{Find} 功能有 \c findButton å’Œ \c findContact()。 + + \c findButton 声明为ç§æœ‰å˜é‡ï¼Œè€Œ \c findContact() 函数声明为公有槽。 + + \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration + \dots + \snippet tutorials/addressbook/part5/addressbook.h findButton declaration + + 最åŽï¼Œæˆ‘们声明ç§æœ‰å˜é‡ \c dialog,用于引用 \c FindDialog 的实例。 + + \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration + + 在实例化对è¯æ¡†åŽï¼Œæˆ‘们å¯èƒ½ä¼šå¯¹å…¶è¿›è¡Œå¤šæ¬¡ä½¿ç”¨ã€‚使用ç§æœ‰å˜é‡å¯åœ¨ç±»ä¸ä¸åŒä½ç½®å¯¹å…¶è¿›è¡Œå¤šæ¬¡å¼•ç”¨ã€‚ + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook ç±»çš„æž„é€ å™¨ä¸ï¼Œå®žä¾‹åŒ–ç§æœ‰å¯¹è±¡ \c findButton å’Œ \c findDialog: + + \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton + \dots + \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog + + 接下æ¥ï¼Œå°† \c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Ž \c findContact() å…³è”。 + + \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find + + 现在唯一è¦å®Œæˆçš„就是 \c findContact() 函数的编ç : + + \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function + + 我们从显示 \c FindDialog 的实例 \c dialog 开始入手。这时用户开始输入è”系人姓å进行查找。用户点击对è¯æ¡†çš„ \c findButton åŽï¼Œå¯¹è¯æ¡†ä¼šéšè—,并且结果代ç 设置为 QDialog::Accepted.è¿™æ ·å°±ç¡®ä¿äº† \c if è¯å¥å§‹ç»ˆä¸ºçœŸã€‚ + + 然åŽï¼Œæˆ‘们就开始使用 \c FindDialog çš„ \c getFindText() 函数æå–æœç´¢å—符串,这个å—符串也就是本例ä¸çš„ \c contactName。如果地å€ç°¿ä¸æœ‰è”系人,就立å³æ˜¾ç¤ºè¯¥è”系人。å¦åˆ™ï¼Œæ˜¾ç¤ºå¦‚下所示的 QMessageBox 表明æœç´¢å¤±è´¥ã€‚ + + \image addressbook-tutorial-part5-notfound.png +*/ + +/*! + \page tutorials-addressbook-part6.html + \previouspage 地å€ç°¿ 5 — æ·»åŠ æŸ¥æ‰¾åŠŸèƒ½ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part7}{ç¬¬ä¸ƒç« } + \example tutorials/addressbook/part6 + \title 地å€ç°¿ 6 — åŠ è½½å’Œä¿å˜ + + æœ¬ç« æ述了用于编写地å€ç°¿åº”用程åºçš„åŠ è½½å’Œä¿å˜ç¨‹åºæ‰€ä½¿ç”¨çš„ Qt 文件处ç†åŠŸèƒ½ã€‚ + + \image addressbook-tutorial-part6-screenshot.png + + 虽然æµè§ˆå’Œæœç´¢è”系人是éžå¸¸å®žç”¨çš„功能,但åªæœ‰åœ¨å¯ä»¥ä¿å˜çŽ°æœ‰è”系人并å¯ä»¥åœ¨ä»¥åŽåŠ 载的å‰æ下地å€ç°¿æ‰çœŸæ£å®Œå…¨å¯ç”¨ã€‚Qt æ供大é‡ç”¨äºŽ\l{Input/Output and Networking}{输入和输出}的类,但我们åªé€‰æ‹©ä¸¤ä¸ªæ˜“于åˆå¹¶ä½¿ç”¨çš„类:QFile å’Œ QDataStream。 + + QFile 对象表示ç£ç›˜ä¸Šå¯è¯»å–和写入的文件。QFile 是代表多ç§ä¸åŒè®¾å¤‡ä¸”应用更广的 QIODevice 类的å类。 + + QDataStream 对象用于按顺åºæŽ’列二进制数æ®ï¼Œä»¥ä¾¿å‚¨å˜åœ¨ QIODevice ä¸å¹¶ä¾›ä»¥åŽæ£€ç´¢ã€‚读å–或写入 QIODevice 就如åŒæ‰“开数æ®æµï¼Œç„¶åŽè¯»å–æˆ–å†™å…¥ä¸€æ ·ç®€å•ï¼Œåªæ˜¯å‚数为ä¸åŒçš„设备。 + + + \section1 定义 AddressBook ç±» + + 我们声明两个公有槽 \c saveToFile() å’Œ \c loadFromFile(),以åŠä¸¤ä¸ª QPushButton 对象 \c loadButton å’Œ \c saveButton。 + + \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration + \dots + \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration + + \section1 应用 AddressBook ç±» + + åœ¨æž„é€ å™¨ä¸ï¼Œæˆ‘们实例化 \c loadButton å’Œ \c saveButton。ç†æƒ³æƒ…å†µä¸‹ï¼Œå°†æŒ‰é’®æ ‡ç¾è®¾ç½®ä¸ºâ€œä»Žæ–‡ä»¶åŠ è½½è”系人â€å’Œâ€œå°†è”系人ä¿å˜è‡³æ–‡ä»¶â€ä¼šæ›´æ–¹ä¾¿ç”¨æˆ·ä½¿ç”¨ã€‚ä¸è¿‡ï¼Œç”±äºŽå…¶ä»–按钮的大å°é™åˆ¶ï¼Œæˆ‘ä»¬å°†æ ‡ç¾è®¾ç½®ä¸º\gui{åŠ è½½...}å’Œ\gui{ä¿å˜...}。幸è¿çš„是,Qt æ供了使用 \l{QWidget::setToolTip()}{setToolTip()} æ¥è®¾ç½®å·¥å…·æ示的简å•æ–¹å¼ï¼Œæˆ‘们å¯é€šè¿‡å¦‚下方å¼å°†å…¶ç”¨äºŽæŒ‰é’®ï¼š + + \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1 + \dots + \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2 + + 虽然æ¤å¤„æ²¡æœ‰æ˜¾ç¤ºï¼Œä½†ä¸Žå…¶ä»–åº”ç”¨çš„åŠŸèƒ½ä¸€æ ·ï¼Œæˆ‘ä»¬åœ¨å³ä¾§çš„布局é¢æ¿ \c button1Layout ä¸Šæ·»åŠ æŒ‰é’®ï¼Œç„¶åŽå°†æŒ‰é’®çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。 + + 至于ä¿å˜åŠŸèƒ½ï¼Œæˆ‘们首先使用 QFileDialog::getSaveFileName() èŽ·å– \c fileName。 这是 QFileDialog æ供的一个便æ·åŠŸèƒ½ï¼Œå¯å¼¹å‡ºæ ·å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…许用户输入文件å或选择现有的 \c{.abk} 文件。\c{.abk} 文件是ä¿å˜è”系人时创建的地å€ç°¿æ‰©å±•å。 + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1 + + 弹出的文件对è¯æ¡†å±å¹•æˆªå›¾æ˜¾ç¤ºå¦‚下: + + \image addressbook-tutorial-part6-save.png + + 如果 \c fileName ä¸ä¸ºç©ºï¼Œæˆ‘们就使用 \c fileName 创建 QFile 对象 \c file。 QFile 与 QDataStream 一åŒä½¿ç”¨ï¼Œè¿™æ˜¯å› 为QFile 是 QIODevice。 + + 接下æ¥ï¼Œæˆ‘们å°è¯•ä»¥ \l{QIODevice::}{WriteOnly} 模å¼æ‰“开文件。如果未能打开,会显示 QMessageBox æ示用户。 + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2 + + å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c out,以写入打开的文件。QDataStream è¦æ±‚读写æ“作需使用相åŒç‰ˆæœ¬çš„æ•°æ®æµã€‚在将数æ®æŒ‰é¡ºåºå†™å…¥ \c file 之å‰ï¼Œå°†ä½¿ç”¨çš„版本设置为\l{QDataStream::Qt_4_5}{采用 Qt 4.5 的版本}å°±å¯ç¡®ä¿ç‰ˆæœ¬ç›¸åŒã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3 + + è‡³äºŽåŠ è½½åŠŸèƒ½ï¼Œæˆ‘ä»¬ä¹Ÿæ˜¯ä½¿ç”¨ QFileDialog::getOpenFileName() èŽ·å– \c fileName。该函数与 QFileDialog::getSaveFileName() ç›¸å¯¹åº”ï¼Œä¹Ÿæ˜¯å¼¹å‡ºæ ·å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…许用户输入文件å或选择现有的 \c{.abk} æ–‡ä»¶åŠ è½½åˆ°åœ°å€ç°¿ä¸ã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1 + + 例如,在 Windows 上,该函数弹出本地文件对è¯æ¡†ï¼Œå¦‚以下å±å¹•æˆªå›¾æ‰€ç¤ºã€‚ + + \image addressbook-tutorial-part6-load.png + + 如果 \c fileName ä¸ä¸ºç©ºï¼Œè¿˜æ˜¯ä½¿ç”¨ QFile 对象 \c file,然åŽå°è¯•åœ¨ \l{QIODevice::}{ReadOnly} 模å¼ä¸‹æ‰“开文件。与 \c saveToFile() 的应用方å¼ç±»ä¼¼ï¼Œå¦‚æžœå°è¯•å¤±è´¥ï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户。 + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2 + + å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c in,按上文所述设置其版本,然åŽå°†æŒ‰é¡ºåºæŽ’列的数æ®è¯»å…¥ \c contacts æ•°æ®ç»“构。请注æ„,在将数æ®è¯»å…¥ä¹‹å‰æ¸…空 \c contacts å¯ç®€åŒ–文件读å–过程。更高级的方法是将è”系人读å–至临时 QMap 对象,然åŽä»…å¤åˆ¶ \c contacts ä¸ä¸å˜åœ¨çš„è”系人。 + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3 + + è¦æ˜¾ç¤ºä»Žæ–‡ä»¶ä¸è¯»å–çš„è”系人,必须è¦å…ˆéªŒè¯èŽ·å–çš„æ•°æ®ï¼Œä»¥ç¡®ä¿è¯»å–的文件实际包å«åœ°å€ç°¿è”系人。如果为真,显示第一个è”系人,å¦åˆ™æ˜¾ç¤º QMessageBox æ示出现问题。最åŽï¼Œæˆ‘们更新界é¢ä»¥ç›¸åº”地å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚ +*/ + +/*! + \page tutorials-addressbook-part7.html + \previouspage 地å€ç°¿ 6 — åŠ è½½å’Œä¿å˜ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \example tutorials/addressbook/part7 + \title 地å€ç°¿ 7 — é™„åŠ åŠŸèƒ½ + + æœ¬ç« è®²è¿°äº†éƒ¨åˆ†å¯ä½¿åœ°å€ç°¿åº”用程åºæ—¥å¸¸ä½¿ç”¨æ›´åŠ 便æ·çš„é™„åŠ åŠŸèƒ½ã€‚ + + \image addressbook-tutorial-part7-screenshot.png + + 虽然地å€ç°¿åº”用程åºå…¶è‡ªèº«åŠŸèƒ½å·²ç»å¾ˆå®žç”¨ï¼Œä½†æ˜¯å¦‚æžœå¯å’Œå…¶ä»–应用程åºäº’æ¢è”系人数æ®å°±ä¼šæ›´åŠ 有益。vCard æ ¼å¼æ˜¯ä¸€ç§æµè¡Œçš„æ–‡ä»¶æ ¼å¼ï¼Œå°±å¯ç”¨äºŽæ¤ç›®çš„ã€‚åœ¨æœ¬ç« ä¸ï¼Œæˆ‘们会扩展地å€ç°¿å®¢æˆ·ç«¯ï¼Œå¯å°†è”系人导出到 vCard \c{.vcf} 文件ä¸ã€‚ + + \section1 定义 AddressBook ç±» + + 我们在 \c addressbook.h 文件的 \c AddressBook ç±»ä¸æ·»åŠ QPushButton 对象 \c exportButton 以åŠå¯¹åº”的公有槽 \c exportAsVCard()。 + + \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration + \dots + \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook æž„é€ å™¨ä¸ï¼Œæˆ‘们将 \c exportButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·è¿žæŽ¥è‡³ \c exportAsVCard()ã€‚æˆ‘ä»¬è¿˜ä¼šå°†è¯¥æŒ‰é’®æ·»åŠ è‡³ \c buttonLayout1,它是负责å³ä¾§æŒ‰é’®é¢æ¿çš„布局类。 + + 在 \c exportAsVCard() 函数ä¸ï¼Œæˆ‘们从æå– \c name ä¸è”系人姓å开始入手。我们声明 \c firstNameã€\c lastName å’Œ \c nameList。接下æ¥ï¼Œæˆ‘们查找 \c name ä¸ç¬¬ä¸€å¤„空白的索引。如果有空白,就将è”系人的姓å分隔为 \c firstName å’Œ lastName。然åŽï¼Œå°†ç©ºç™½æ›¿æ¢ä¸ºä¸‹åˆ’线 ("_")。或者,如果没有空白,就认定è”系人åªæœ‰åå—。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part1 + + 至于 \c saveToFile() 函数,会打开文件对è¯æ¡†ï¼Œè®©ç”¨æˆ·é€‰æ‹©æ–‡ä»¶çš„ä½ç½®ã€‚通过选择的文件å称,我们创建è¦å†™å…¥çš„ QFile 实例。 + + 我们å°è¯•ä»¥ \l{QIODevice::}{WriteOnly} 模å¼æ‰“开文件。如果æ“作失败,会显示 QMessageBox æ示用户出现问题并返回。å¦åˆ™ï¼Œå°†æ–‡ä»¶ä½œä¸ºå‚æ•°ä¼ é€’ç»™ QTextStream 对象 \c out。与 QDataStream 类似,QTextStream ç±»æ供了读å–çº¯æ–‡æœ¬å’Œå°†å…¶å†™å…¥åˆ°æ–‡ä»¶çš„åŠŸèƒ½ã€‚å› æ¤ï¼Œæ‰€ç”Ÿæˆçš„ \c{.vcf} 文件å¯ä»¥åœ¨æ–‡æœ¬ç¼–辑器ä¸æ‰“开进行编辑。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part2 + + 然åŽï¼Œæˆ‘们写出ä¾æ¬¡å¸¦æœ‰ \c{BEGIN:VCARD} å’Œ \c{VERSION:2.1} æ ‡è®°çš„ vCard 文件。è”系人的姓å使用 \c{N:} æ ‡è®°å†™å…¥ã€‚è‡³äºŽå†™å…¥ vCard “File asâ€å±žæ€§çš„ FN: æ ‡è®°ï¼Œæˆ‘ä»¬å¿…é¡»è¦æŸ¥çœ‹æ˜¯å¦è”系人带有姓。如果è”系人有姓,就使用 \c nameList ä¸çš„详细信æ¯å¡«å…¥è¯¥æ ‡è®°ã€‚å¦åˆ™ï¼Œä»…写入 \c firstName。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part3 + + 我们继ç»å†™å…¥è”系人的地å€ã€‚地å€ä¸çš„分å·ä½¿ç”¨ "\\" 进行转义,新行使用分å·è¿›è¡Œæ›¿æ¢ï¼Œè€Œé€—å·ä½¿ç”¨ç©ºç™½è¿›è¡Œæ›¿æ¢ã€‚最åŽï¼Œæˆ‘们ä¾æ¬¡å†™å…¥ \c{ADR;HOME:;}ã€\c address å’Œ \c{END:VCARD} æ ‡è®°ã€‚ + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part4 + + 最åŽï¼Œä¼šæ˜¾ç¤º QMessageBox æ示用户已æˆåŠŸå¯¼å‡º vCard。 + + \e{vCard 是 \l{http://www.imc.org}{Internet Mail Consortium} çš„å•†æ ‡}。 +*/ diff --git a/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc new file mode 100644 index 0000000..90ef4f3 --- /dev/null +++ b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page widgets-tutorial.html + \title Widgets 教程 + \brief This tutorial covers basic usage of widgets and layouts, showing how + they are used to build GUI applications. + + \startpage {index.html}{Qt Reference Documentation} + \contentspage 教程 + \nextpage {Widgets 教程 — 创建窗å£} + + + \section1 简介 + + Widget 是使用 Qt ç¼–å†™çš„å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 应用程åºçš„基本生æˆå—。æ¯ä¸ª GUI 组件,如按钮ã€æ ‡ç¾æˆ–文本编辑器,都是一个 widget ,并å¯ä»¥æ”¾ç½®åœ¨çŽ°æœ‰çš„用户界é¢ä¸æˆ–作为å•ç‹¬çš„窗å£æ˜¾ç¤ºã€‚æ¯ç§ç±»åž‹çš„组件都是由 QWidget 的特殊åç±»æ供的,而 QWidget 自身åˆæ˜¯ QObject çš„å类。 + + QWidget ä¸æ˜¯ä¸€ä¸ªæŠ½è±¡ç±»ï¼›å®ƒå¯ç”¨ä½œå…¶ä»– widget 的容器,并很容易作为å类使用æ¥åˆ›å»ºå®šåˆ¶ widget。它ç»å¸¸ç”¨æ¥åˆ›å»ºæ”¾ç½®å…¶ä»– widget 的窗å£ã€‚ + + 至于 QObject,å¯ä½¿ç”¨çˆ¶å¯¹è±¡åˆ›å»º widget 以表明其所属关系,这å¯ç¡®ä¿åˆ 除ä¸å†ä½¿ç”¨çš„对象。使用 widget,这些父å关系就有了更多的æ„义:æ¯ä¸ªå类都显示在其父级所拥有的å±å¹•åŒºåŸŸå†…ã€‚ä¹Ÿå°±æ˜¯è¯´ï¼Œå½“åˆ é™¤çª—å£æ—¶ï¼Œå…¶åŒ…å«çš„所有 widget ä¹Ÿéƒ½è‡ªåŠ¨åˆ é™¤ã€‚ + + \section1 Writing a main Function + + Many of the GUI examples in Qt follow the pattern of having a \c{main.cpp} + file containing code to initialize the application, and a number of other + source and header files containing the application logic and custom GUI + components. + + A typical \c main() function, written in \c{main.cpp}, looks like this: + + \snippet doc/src/snippets/widgets-tutorial/template.cpp main.cpp body + + We first construct a QApplication object which is configured using any + arguments passed in from the command line. After any widgets have been + created and shown, we call QApplication::exec() to start Qt's event loop. + Control passes to Qt until this function returns, at which point we return + the value we obtain from this function. + + In each part of this tutorial, we provide an example that is written + entirely within a \c main() function. In more sophisticated examples, the + code to set up widgets and layouts is written in other parts of the + example. For example, the GUI for a main window may be set up in the + constructor of a QMainWindow subclass. + + The \l{Widgets examples} are a good place to look for + more complex and complete examples and applications. + + \section1 Building Examples and Tutorials + + If you obtained a binary package of Qt or compiled it yourself, the + examples described in this tutorial should already be ready to run. + However, if you may wish to modify them and recompile them, you need to + perform the following steps: + + \list 1 + \o At the command line, enter the directory containing the example you + wish to recompile. + \o Type \c qmake and press \key{Return}. If this doesn't work, make sure + that the executable is on your path, or enter its full location. + \o On Linux/Unix and Mac OS X, type \c make and press \key{Return}; + on Windows with Visual Studio, type \c nmake and press \key{Return}. + \endlist + + An executable file should have been created within the current directory. + On Windows, this file may be located within a \c debug or \c release + subdirectory. You can run this file to see the example code at work. +*/ + +/*! + \page widgets-tutorial-toplevel.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程} + \nextpage {Widgets 教程 — Child Widgets} + \example tutorials/widgets/toplevel + \title Widgets 教程 — åˆ›å»ºçª—å£ + + 如果 widget 未使用父级进行创建,则在显示时视为窗å£æˆ–\e{顶层 widget}。由于顶层 widget 没有父级对象类æ¥ç¡®ä¿åœ¨å…¶ä¸å†ä½¿ç”¨æ—¶å°±åˆ é™¤ï¼Œå› æ¤éœ€è¦å¼€å‘人员在应用程åºä¸å¯¹å…¶è¿›è¡Œè·Ÿè¸ªã€‚ + + 在下例ä¸ï¼Œæˆ‘们使用 QWidget 创建和显示具有默认大å°çš„窗å£ï¼š + + \raw HTML + <table align="left" width="100%"> + <tr class="qt-code"><td> + \endraw + \snippet tutorials/widgets/toplevel/main.cpp main program + \raw HTML + </td><td align="right"> + \endraw + \inlineimage widgets-tutorial-toplevel.png + \raw HTML + </td></tr> + </table> + \endraw + + To create a real GUI, we need to place widgets inside the window. To do + this, we pass a QWidget instance to a widget's constructor, as we will + demonstrate in the next part of this tutorial. +*/ + +/*! + \page widgets-tutorial-childwidget.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — 创建窗å£} + \nextpage {Widgets 教程 — 使用布局} + \example tutorials/widgets/childwidget + \title Widgets 教程 — Child Widgets + + 我们å¯ä»¥é€šè¿‡å°† \c window ä½œä¸ºçˆ¶çº§ä¼ é€’ç»™å…¶æž„é€ å™¨æ¥å‘窗å£æ·»åŠ å widget。在这ç§æƒ…况下,我们å‘窗å£æ·»åŠ 按钮并将其放置在特定ä½ç½®ï¼š + + \raw HTML + <table align="left" width="100%"> + <tr class="qt-code"><td> + \endraw + \snippet tutorials/widgets/childwidget/main.cpp main program + \raw HTML + </td><td align="right"> + \endraw + \inlineimage widgets-tutorial-childwidget.png + \raw HTML + </td></tr> + </table> + \endraw + + 该按钮现在为窗å£çš„åé¡¹ï¼Œå¹¶åœ¨åˆ é™¤çª—å£æ—¶ä¸€åŒåˆ 除。请注æ„,éšè—或关é—窗å£ä¸ä¼šè‡ªåŠ¨åˆ 除该按钮。 +*/ + +/*! + \page widgets-tutorial-windowlayout.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — Child Widgets} + \nextpage {Widgets 教程 — Nested Layouts} + \example tutorials/widgets/windowlayout + \title Widgets 教程 — 使用布局 + + 通常,å widget 是通过使用布局对象在窗å£ä¸è¿›è¡ŒæŽ’列,而ä¸æ˜¯é€šè¿‡æŒ‡å®šä½ç½®å’Œå¤§å°è¿›è¡ŒæŽ’列。在æ¤å¤„ï¼Œæˆ‘ä»¬æž„é€ è¦å¹¶æŽ’æŽ’åˆ—çš„æ ‡ç¾å’Œè¡Œç¼–辑框 widget。 + + \raw HTML + <table align="left" width="100%"> + <tr class="qt-code"><td> + \endraw + \snippet tutorials/widgets/windowlayout/main.cpp main program + \raw HTML + </td><td align="right"> + \endraw + \inlineimage widgets-tutorial-windowlayout.png + \raw HTML + </td></tr> + </table> + \endraw + + æˆ‘ä»¬æž„é€ çš„å¸ƒå±€å¯¹è±¡ç®¡ç†é€šè¿‡ \l{QHBoxLayout::}{addWidget()} 函数æ供的 widget çš„ä½ç½®å’Œå¤§å°ã€‚布局本身是通过调用 \l{QWidget::}{setLayout()} æ供给窗å£çš„。布局仅å¯é€šè¿‡å…¶å¯¹æ‰€ç®¡ç†çš„ widget(和其他布局)的效果æ‰å¯æ˜¾ç¤ºã€‚ + + 在上文示例ä¸ï¼Œæ¯ä¸ª widget 的所属关系并ä¸æ˜Žæ˜¾ã€‚ç”±äºŽæˆ‘ä»¬æœªä½¿ç”¨çˆ¶çº§å¯¹è±¡æž„é€ widget 和布局,我们会看到一个空窗å£å’Œä¸¤ä¸ªåŒ…å«äº†æ ‡ç¾ä¸Žè¡Œç¼–辑框的窗å£ã€‚ä¸è¿‡ï¼Œå¦‚果我们告知布局æ¥ç®¡ç†æ ‡ç¾å’Œè¡Œç¼–辑框,并在窗å£ä¸è®¾ç½®å¸ƒå±€ï¼Œä¸¤ä¸ª widget 与布局本身就都会æˆä¸ºçª—å£çš„å项。 +*/ + +/*! + \page widgets-tutorial-nestedlayouts.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — 使用布局} + \example tutorials/widgets/nestedlayouts + \title Widgets 教程 — Nested Layouts + + 由于 widget å¯åŒ…å«å…¶ä»– widget,布局å¯ç”¨æ¥æ供按ä¸åŒå±‚次分组的 widget。这里,我们è¦åœ¨æ˜¾ç¤ºæŸ¥è¯¢ç»“果的表视图上方ã€çª—å£é¡¶éƒ¨çš„行编辑框æ—ï¼Œæ˜¾ç¤ºä¸€ä¸ªæ ‡ç¾ã€‚ + + We achieve this by creating two layouts: \c{queryLayout} is a QHBoxLayout + that contains QLabel and QLineEdit widgets placed side-by-side; + \c{mainLayout} is a QVBoxLayout that contains \c{queryLayout} and a + QTableView arranged vertically. + + \raw HTML + <table align="left" width="100%"> + <tr class="qt-code"><td> + \endraw + \snippet tutorials/widgets/nestedlayouts/main.cpp first part + \snippet tutorials/widgets/nestedlayouts/main.cpp last part + \raw HTML + </td><td align="right"> + \endraw + \inlineimage widgets-tutorial-nestedlayouts.png + \raw HTML + </td></tr> + </table> + \endraw + + Note that we call the \c{mainLayout}'s \l{QBoxLayout::}{addLayout()} + function to insert the \c{queryLayout} above the \c{resultView} table. + + We have omitted the code that sets up the model containing the data shown + by the QTableView widget, \c resultView. For completeness, we show this below. + + 除了 QHBoxLayout å’Œ QVBoxLayout,Qt 还æ供了 QGridLayout å’Œ QFormLayout ç±»æ¥å助实现更å¤æ‚的用户界é¢ã€‚ + These can be seen if you run \l{Qt Designer}. + + \section1 Setting up the Model + + In the code above, we did not show where the table's data came from + because we wanted to concentrate on the use of layouts. Here, we see + that the model holds a number of items corresponding to rows, each of + which is set up to contain data for two columns. + + \snippet tutorials/widgets/nestedlayouts/main.cpp set up the model + + The use of models and views is covered in the + \l{Item Views Examples} and in the \l{Model/View Programming} overview. +*/ diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index f62ec24..acb1576 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -671,7 +671,9 @@ void Config::load(Location location, const QString& fileName) location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString())); } - QString text = fin.readAll(); + QTextStream stream(&fin); + stream.setCodec("UTF-8"); + QString text = stream.readAll(); text += QLatin1String("\n\n"); text += QChar('\0'); fin.close(); diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 5e7e6f1..6f23469 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,8 +140,10 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_NATURALLANGUAGE "naturallanguage" #define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" +#define CONFIG_OUTPUTENCODING "outputencoding" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_PROJECT "project" @@ -150,6 +152,7 @@ class Config #define CONFIG_SLOW "slow" #define CONFIG_SHOWINTERNAL "showinternal" #define CONFIG_SOURCEDIRS "sourcedirs" +#define CONFIG_SOURCEENCODING "sourceencoding" #define CONFIG_SOURCES "sources" #define CONFIG_SPURIOUS "spurious" #define CONFIG_STYLESHEETS "stylesheets" diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 7d08c77..c8655a4 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -281,8 +281,8 @@ void CppCodeParser::parseHeaderFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ header file '%1'").arg(filePath)); return; } @@ -295,7 +295,7 @@ void CppCodeParser::parseHeaderFile(const Location& location, matchDeclList(tree->root()); if (!fileTokenizer.version().isEmpty()) tree->setVersion(fileTokenizer.version()); - fclose(in); + in.close(); if (fileLocation.fileName() == "qiterator.h") parseQiteratorDotH(location, filePath); @@ -312,8 +312,8 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno))); return; } @@ -325,7 +325,7 @@ void CppCodeParser::parseSourceFile(const Location& location, readToken(); usedNamespaces.clear(); matchDocsAndStuff(); - fclose(in); + in.close(); } /*! diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index 17a6efd..ad4cdde 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -3056,7 +3056,8 @@ QString Doc::canonicalTitle(const QString &title) slurping = true; } else { - // !alnum && slurping -> nothin + result += title[i]; + lastAlnum = result.size(); } } result.truncate(lastAlnum); diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 15386f1..15afd7d 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -54,6 +54,7 @@ #include <qdebug.h> #include <qlist.h> #include <qiterator.h> +#include <qtextcodec.h> QT_BEGIN_NAMESPACE @@ -266,6 +267,15 @@ void HtmlGenerator::initializeGenerator(const Config &config) projectUrl = config.getString(CONFIG_URL); + outputEncoding = config.getString(CONFIG_OUTPUTENCODING); + if (outputEncoding.isEmpty()) + outputEncoding = QLatin1String("ISO-8859-1"); + outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit()); + + naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE); + if (naturalLanguage.isEmpty()) + naturalLanguage = QLatin1String("en"); + QSet<QString> editionNames = config.subVars(CONFIG_EDITION); QSet<QString>::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { @@ -431,11 +441,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, endLink(); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::BaseName: @@ -483,7 +493,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::C: out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE]; if (inLink) { - out() << protect(plainCode(atom->string())); + out() << protectEnc(plainCode(atom->string())); } else { out() << highlightedCode(atom->string(), marker, relative); @@ -516,7 +526,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) + << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string())))) << "</font></pre>\n"; break; case Atom::FootnoteLeft: @@ -768,7 +778,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<a name=\"" << Doc::canonicalTitle((*s).name) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + out() << "<h3>" << protectEnc((*s).name) << "</h3>\n"; if (idx == Class) generateCompactList(0, marker, ncmap.value(), QString("Q")); else if (idx == MemberFunction) { @@ -792,7 +802,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, << linkForNode(pmap.key(), 0) << "\">"; QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); - out() << protect(pieces.last()); + out() << protectEnc(pieces.last()); out() << "</a>" << ":</p>\n"; generateSection(nlist, 0, marker, CodeMarker::Summary); @@ -820,12 +830,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<p align=\"center\">"; if (fileName.isEmpty()) { out() << "<font color=\"red\">[Missing image " - << protect(atom->string()) << "]</font>"; + << protectEnc(atom->string()) << "]</font>"; } else { - out() << "<img src=\"" << protect(fileName) << "\""; + out() << "<img src=\"" << protectEnc(fileName) << "\""; if (!text.isEmpty()) - out() << " alt=\"" << protect(text) << "\""; + out() << " alt=\"" << protectEnc(text) << "\""; out() << " />"; helpProjectWriter->addExtraFile(fileName); } @@ -923,7 +933,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // ### Trenton out() << "<tr><td valign=\"top\"><tt>" - << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(), + << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), relative))) << "</tt></td><td align=\"center\" valign=\"top\">"; @@ -936,7 +946,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (itemValue.isEmpty()) out() << "?"; else - out() << "<tt>" << protect(itemValue) << "</tt>"; + out() << "<tt>" << protectEnc(itemValue) << "</tt>"; skipAhead = 1; } @@ -1052,7 +1062,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateLink(atom, relative, marker); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::TableLeft: @@ -1166,7 +1176,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<font color=\"red\"><b><Missing HTML></b></font>"; break; case Atom::UnknownCommand: - out() << "<font color=\"red\"><b><code>\\" << protect(atom->string()) + out() << "<font color=\"red\"><b><code>\\" << protectEnc(atom->string()) << "</code></b></font>"; break; #ifdef QDOC_QML @@ -1295,7 +1305,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateSection(s->members, inner, marker, CodeMarker::Summary); } if (!s->reimpMembers.isEmpty()) { @@ -1304,7 +1314,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<a name=\"" << registerRef(name.toLower()) << "\"></a>\n"; - out() << "<h2>" << protect(name) << "</h2>\n"; + out() << "<h2>" << protectEnc(name) << "</h2>\n"; generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); } @@ -1343,7 +1353,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, s = sections.begin(); while (s != sections.end()) { out() << "<hr />\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1518,7 +1528,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateQmlSummary(*s,fake,marker); ++s; } @@ -1534,7 +1544,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); s = sections.begin(); while (s != sections.end()) { - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { generateDetailedQmlMember(*m, fake, marker); @@ -1554,7 +1564,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } @@ -1583,7 +1593,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "<hr />\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1629,11 +1639,11 @@ void HtmlGenerator::generateHeader(const QString& title, CodeMarker *marker, bool mainPage) { - out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; + out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding); out() << "<!DOCTYPE html\n" - " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" - "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"; + " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"; + out() << QString("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%1\" lang=\"%1\">\n").arg(naturalLanguage); QString shortVersion; if ((project != "Qtopia") && (project != "Qt Extended")) { @@ -1653,7 +1663,9 @@ void HtmlGenerator::generateHeader(const QString& title, } out() << "<head>\n" - " <title>" << shortVersion << protect(title) << "</title>\n"; + " <title>" << shortVersion << protectEnc(title) << "</title>\n"; + out() << QString("<meta http-equiv=\"Content-type\" content=\"text/html; charset=%1\" />").arg(outputEncoding); + if (!style.isEmpty()) out() << " <style type=\"text/css\">" << style << "</style>\n"; @@ -1662,8 +1674,8 @@ void HtmlGenerator::generateHeader(const QString& title, QMapIterator<QString, QString> i(metaMap); while (i.hasNext()) { i.next(); - out() << " <meta name=\"" << protect(i.key()) << "\" contents=\"" - << protect(i.value()) << "\" />\n"; + out() << " <meta name=\"" << protectEnc(i.key()) << "\" contents=\"" + << protectEnc(i.value()) << "\" />\n"; } } @@ -1687,9 +1699,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::ContentsLink)) { @@ -1705,9 +1717,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[<a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::NextLink)) { @@ -1723,9 +1735,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::IndexLink)) { @@ -1776,7 +1788,7 @@ void HtmlGenerator::generateTitle(const QString& title, const Node *relative, CodeMarker *marker) { - out() << "<h1 class=\"title\">" << protect(title); + out() << "<h1 class=\"title\">" << protectEnc(title); if (!subTitle.isEmpty()) { out() << "<br />"; if (subTitleSize == SmallSubTitle) @@ -2014,18 +2026,18 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" - << protect(inner->name()) + << protectEnc(inner->name()) << " class reference</a></li></ul></p>\n"; for (i = 0; i < sections.size(); ++i) { - out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; + out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } sections = marker->sections(inner, CodeMarker::Detailed, status); for (i = 0; i < sections.size(); ++i) { out() << "<hr />\n"; - out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; + out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; NodeList::ConstIterator m = sections.at(i).members.begin(); while (m != sections.at(i).members.end()) { @@ -2118,7 +2130,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, } else { out() << "<td>"; - out() << protect(node->doc().briefText().toString()); + out() << protectEnc(node->doc().briefText().toString()); out() << "</td>"; } out() << "</tr>\n"; @@ -2320,7 +2332,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, << linkForNode(it.value(), relative) << "\">"; QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); + out() << protectEnc(pieces.last()); out() << "</a>"; if (pieces.size() > 1) { out() << " ("; @@ -2362,7 +2374,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, #else out() << "<p>"; #endif - out() << protect(f.key()) << ":"; + out() << protectEnc(f.key()) << ":"; currentLetter = f.key()[0].unicode(); while (islower(currentLetter) && currentLetter >= nextLetter) { @@ -2416,7 +2428,7 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2455,7 +2467,7 @@ void HtmlGenerator::generateQmlItem(const Node *node, QString marked = marker->markedUpQmlItem(node,summary); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2561,7 +2573,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m const FakeNode *groupNode = groupTitlesMap[groupTitle]; out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg( linkForNode(groupNode, relative)).arg( - protect(groupNode->fullTitle())); + protectEnc(groupNode->fullTitle())); if (fakeNodeMap[groupNode].count() == 0) continue; @@ -2573,7 +2585,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" - << protect(title) << "</a></li>\n"; + << protectEnc(title) << "</a></li>\n"; } out() << "</ul>\n"; } @@ -2587,7 +2599,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" - << protect(title) << "</a></li>\n"; + << protectEnc(title) << "</a></li>\n"; } out() << "</ul>\n"; } @@ -2750,7 +2762,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from <a href=\"" << fileName((*p).first) << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "</a></li>\n"; ++p; } @@ -2765,7 +2777,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -3034,7 +3046,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from <a href=\"" << fileName((*p).first) << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "</a></li>\n"; ++p; } @@ -3048,7 +3060,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -3246,7 +3258,7 @@ void HtmlGenerator::generateLink(const Atom* atom, if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { // hack for C++: move () outside of link int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); + out() << protectEnc(atom->string().left(k)); if (link.isEmpty()) { if (showBrokenLinks) out() << "</i>"; @@ -3254,7 +3266,7 @@ void HtmlGenerator::generateLink(const Atom* atom, out() << "</a>"; } inLink = false; - out() << protect(atom->string().mid(k)); + out() << protectEnc(atom->string().mid(k)); } else if (marker->recognizeLanguage("Java")) { // hack for Java: remove () and use <tt> when appropriate bool func = atom->string().endsWith("()"); @@ -3262,13 +3274,13 @@ void HtmlGenerator::generateLink(const Atom* atom, if (tt) out() << "<tt>"; if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); + out() << protectEnc(atom->string().left(atom->string().length() - 2)); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } out() << "</tt>"; } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } @@ -3342,7 +3354,12 @@ QString HtmlGenerator::registerRef(const QString& ref) return clean; } -QString HtmlGenerator::protect(const QString& string) +QString HtmlGenerator::protectEnc(const QString &string) +{ + return protect(string, outputEncoding); +} + +QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding) { #define APPEND(x) \ if (html.isEmpty()) { \ @@ -3365,7 +3382,7 @@ QString HtmlGenerator::protect(const QString& string) APPEND(">"); } else if (ch == QLatin1Char('"')) { APPEND("""); - } else if (ch.unicode() > 0x007F + } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F) || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator @@ -3495,7 +3512,7 @@ QString HtmlGenerator::refForNode(const Node *node) ref = node->name() + "-var"; break; case Node::Target: - return protect(node->name()); + return protectEnc(node->name()); } return registerRef(ref); } @@ -3569,7 +3586,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, } } out() << "\">"; - out() << protect(fullName(apparentNode, relative, marker)); + out() << protectEnc(fullName(apparentNode, relative, marker)); out() << "</a>"; } @@ -3630,12 +3647,12 @@ void HtmlGenerator::generateDetailedMember(const Node *node, else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast<const EnumNode *>(node); if (enume->flagsType()) { - out() << "<p>The " << protect(enume->flagsType()->name()) + out() << "<p>The " << protectEnc(enume->flagsType()->name()) << " type is a typedef for " << "<a href=\"qflags.html\">QFlags</a><" - << protect(enume->name()) + << protectEnc(enume->name()) << ">. It stores an OR combination of " - << protect(enume->name()) + << protectEnc(enume->name()) << " values.</p>\n"; } } diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 19a7c78..5ed26e0 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -104,7 +104,8 @@ class HtmlGenerator : public PageGenerator virtual QString format(); virtual void generateTree(const Tree *tree, CodeMarker *marker); - static QString protect(const QString& string); + QString protectEnc(const QString &string); + static QString protect(const QString &string, const QString &encoding = "ISO-8859-1"); static QString cleanRef(const QString& ref); static QString sinceTitle(int i) { return sinceTitles[i]; } diff --git a/tools/qdoc3/linguistgenerator.cpp b/tools/qdoc3/linguistgenerator.cpp index d1bd22d..21678e0 100644 --- a/tools/qdoc3/linguistgenerator.cpp +++ b/tools/qdoc3/linguistgenerator.cpp @@ -89,7 +89,7 @@ QString LinguistGenerator::fileExtension(const Node * /* node */) void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker *marker) { - out().setCodec("utf-8"); + out().setCodec("UTF-8"); QDomDocument document("TS"); QDomElement documentElement = document.createElement("TS"); @@ -100,7 +100,7 @@ void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker documentElement.appendChild(element); QDomProcessingInstruction process = document.createProcessingInstruction( - "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("utf-8")); + "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("UTF-8")); document.appendChild(process); document.appendChild(documentElement); diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index 07edcc4..bc73eb0 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -177,7 +177,7 @@ void PageGenerator::beginSubPage(const Location& location, location.fatal(tr("Cannot open output file '%1'") .arg(outFile->fileName())); QTextStream *out = new QTextStream(outFile); - out->setCodec("ISO-8859-1"); + out->setCodec(outputCodec); outStreamStack.push(out); } diff --git a/tools/qdoc3/pagegenerator.h b/tools/qdoc3/pagegenerator.h index db24edd..20a6c3c 100644 --- a/tools/qdoc3/pagegenerator.h +++ b/tools/qdoc3/pagegenerator.h @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE +class QTextCodec; + class ClassNode; class InnerNode; class NamespaceNode; @@ -76,6 +78,10 @@ class PageGenerator : public Generator virtual void generateInnerNode(const InnerNode *node, CodeMarker *marker); QTextStream& out(); + QString naturalLanguage; + QString outputEncoding; + QTextCodec *outputCodec; + private: QStack<QTextStream *> outStreamStack; }; diff --git a/tools/qdoc3/qsakernelparser.cpp b/tools/qdoc3/qsakernelparser.cpp index 9320a17..8f12eda 100644 --- a/tools/qdoc3/qsakernelparser.cpp +++ b/tools/qdoc3/qsakernelparser.cpp @@ -70,8 +70,8 @@ void QsaKernelParser::parseSourceFile( const Location& location, const QString& filePath, Tree * /* tree */ ) { - FILE *in = fopen( QFile::encodeName(filePath), "r" ); - if ( in == 0 ) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error( tr("Cannot open QSA kernel file '%1'").arg(filePath) ); return; } @@ -171,7 +171,7 @@ void QsaKernelParser::parseSourceFile( const Location& location, readToken(); } } - fclose( in ); + in.close(); } void QsaKernelParser::doneParsingSourceFiles( Tree * /* tree */ ) diff --git a/tools/qdoc3/qscodeparser.cpp b/tools/qdoc3/qscodeparser.cpp index 8b3bc98..3b8bc1a 100644 --- a/tools/qdoc3/qscodeparser.cpp +++ b/tools/qdoc3/qscodeparser.cpp @@ -151,8 +151,8 @@ void QsCodeParser::parseHeaderFile(const Location& location, { qsTre = tree; - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (in == 0) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open Qt Script class list '%1'") .arg(filePath)); return; @@ -175,7 +175,7 @@ void QsCodeParser::parseHeaderFile(const Location& location, } tok = fileTokenizer.getToken(); } - fclose(in); + in.close(); } void QsCodeParser::parseSourceFile(const Location& location, diff --git a/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf new file mode 100644 index 0000000..c722ee8 --- /dev/null +++ b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf @@ -0,0 +1,30 @@ +include(qt-build-docs_zh_CN.qdocconf) + +# Ensures that the generated index contains a URL that can be used by the +# tools documentation (assistant.qdocconf, designer.qdocconf, linguist.qdocconf, +# qmake.qdocconf). + +url = ./ + +# Ensures that the documentation for the tools is not included in the generated +# .qhp file. + +qhp.Qt.excluded += $QT_SOURCE_TREE/doc/src/development/assistant-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/simpletextviewer.qdoc \ + $QT_SOURCE_TREE/doc/src/development/designer-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorform.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/customwidgetplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/taskmenuextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/containerextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/internationalization/linguist-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/hellotr.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/arrowpad.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/trollprint.qdoc \ + $QT_SOURCE_TREE/doc/src/development/qmake-manual.qdoc + +outputdir = $QT_BUILD_TREE/doc-build/html-qt_zh_CN +tagfile = $QT_BUILD_TREE/doc-build/html-qt_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc-build/html-qt_zh_CN diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index e8595f6..4f1ae5d 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -8,9 +8,13 @@ project = Qt description = Qt Reference Documentation url = http://qt.nokia.com/doc/4.7 -edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ - QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ - QtDesigner QtAssistant QAxContainer Phonon \ +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US + +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ + QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ QAxServer QtUiTools QtTest QtDBus edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest @@ -90,11 +94,13 @@ excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ $QT_SOURCE_TREE/src/3rdparty/wintab \ $QT_SOURCE_TREE/src/3rdparty/zlib \ - $QT_SOURCE_TREE/doc/src/snippets \ $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ - $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf new file mode 100644 index 0000000..18b72a1 --- /dev/null +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -0,0 +1,92 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates_zh_CN.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/zh_CN/4.7 + +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = zh-Hans + +indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index + +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ + QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus + +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.470 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.title = 教程 +qhp.Qt.indexTitle = 教程 +qhp.Qt.selectors = fake:example + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +language = Cpp + +sourcedirs = $QT_SOURCE_TREE/doc/src/zh_CN + +excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ + $QT_SOURCE_TREE/src/3rdparty/des \ + $QT_SOURCE_TREE/src/3rdparty/freetype \ + $QT_SOURCE_TREE/src/3rdparty/harfbuzz \ + $QT_SOURCE_TREE/src/3rdparty/kdebase \ + $QT_SOURCE_TREE/src/3rdparty/libjpeg \ + $QT_SOURCE_TREE/src/3rdparty/libmng \ + $QT_SOURCE_TREE/src/3rdparty/libpng \ + $QT_SOURCE_TREE/src/3rdparty/libtiff \ + $QT_SOURCE_TREE/src/3rdparty/md4 \ + $QT_SOURCE_TREE/src/3rdparty/md5 \ + $QT_SOURCE_TREE/src/3rdparty/patches \ + $QT_SOURCE_TREE/src/3rdparty/sha1 \ + $QT_SOURCE_TREE/src/3rdparty/sqlite \ + $QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ + $QT_SOURCE_TREE/src/3rdparty/wintab \ + $QT_SOURCE_TREE/src/3rdparty/zlib \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ + $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.imageextensions = "*.png" + +exampledirs = $QT_SOURCE_TREE/doc/src \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/examples/tutorials \ + $QT_SOURCE_TREE \ + $QT_SOURCE_TREE/qmake/examples \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/examples +outputdir = $QT_BUILD_TREE/doc/html_zh_CN +tagfile = $QT_BUILD_TREE/doc/html_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc/html_zh_CN + +HTML.generatemacrefs = "true" diff --git a/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf new file mode 100644 index 0000000..5fb68cf --- /dev/null +++ b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf @@ -0,0 +1,25 @@ +HTML.stylesheets = classic.css +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\" width=\"32\">" \ + "<a href=\"http://qt.nokia.com/\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \ + "</td>\n" \ + "<td width=\"1\"> </td>" \ + "<td class=\"postheader\" valign=\"center\">" \ + "<a href=\"http://qt.nokia.com/doc/4.7/index.html\">" \ + "<font color=\"#004faf\">主页</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/classes.html\">" \ + "<font color=\"#004faf\">所有类</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/functions.html\">" \ + "<font color=\"#004faf\">所有函数</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/overviews.html\">" \ + "<font color=\"#004faf\">简介</font></a>" \ + "</td>" \ + "</tr></table>" + +HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ + "<td width=\"40%\" align=\"left\">版æƒæ‰€æœ‰ © 2010 诺基亚公å¸å’Œ/或其åå…¬å¸</td>\n" \ + "<td width=\"20%\" align=\"center\"><a href=\"trademarks.html\">å•†æ ‡</a></td>\n" \ + "<td width=\"40%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \ + "</tr></table></div></address>" diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index a066021..1039c18 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -10,9 +10,13 @@ version = %VERSION% description = Qt Reference Documentation url = http://qt.nokia.com/doc/4.7 +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US + edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ - Qt3Support QtHelp QtDesigner QAxContainer Phonon \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ QAxServer QtUiTools QtTest QtDBus edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest edition.DesktopLight.groups = -graphicsview-api @@ -91,12 +95,13 @@ excludedirs = $QTDIR/src/3rdparty/clucene \ $QTDIR/src/3rdparty/webkit/WebCore \ $QTDIR/src/3rdparty/wintab \ $QTDIR/src/3rdparty/zlib \ - $QTDIR/doc/src/snippets \ $QTDIR/src/3rdparty/phonon/gstreamer \ $QTDIR/src/3rdparty/phonon/ds9 \ $QTDIR/src/3rdparty/phonon/qt7 \ $QTDIR/src/3rdparty/phonon/mmf \ - $QTDIR/src/3rdparty/phonon/waveout + $QTDIR/src/3rdparty/phonon/waveout \ + $QTDIR/doc/src/snippets \ + $QTDIR/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" diff --git a/tools/qdoc3/tokenizer.cpp b/tools/qdoc3/tokenizer.cpp index b391759..7c10de6 100644 --- a/tools/qdoc3/tokenizer.cpp +++ b/tools/qdoc3/tokenizer.cpp @@ -47,6 +47,7 @@ #include <qhash.h> #include <qregexp.h> #include <qstring.h> +#include <qtextcodec.h> #include <ctype.h> #include <string.h> @@ -97,6 +98,8 @@ static QRegExp *definedX = 0; static QRegExp *defines = 0; static QRegExp *falsehoods = 0; +static QTextCodec *sourceCodec = 0; + /* This function is a perfect hash function for the 37 keywords of C99 (with a hash table size of 512). It should perform well on our @@ -118,13 +121,10 @@ static void insertKwordIntoHash(const char *s, int number) kwordHashTable[k] = number; } -Tokenizer::Tokenizer(const Location& loc, FILE *in) +Tokenizer::Tokenizer(const Location& loc, QFile &in) { init(); - QFile file; - file.open(in, QIODevice::ReadOnly); - yyIn = file.readAll(); - file.close(); + yyIn = in.readAll(); yyPos = 0; start(loc); } @@ -483,6 +483,11 @@ void Tokenizer::initialize(const Config &config) { QString versionSym = config.getString(CONFIG_VERSIONSYM); + QString sourceEncoding = config.getString(CONFIG_SOURCEENCODING); + if (sourceEncoding.isEmpty()) + sourceEncoding = QLatin1String("ISO-8859-1"); + sourceCodec = QTextCodec::codecForName(sourceEncoding.toLocal8Bit()); + comment = new QRegExp("/(?:\\*.*\\*/|/.*\n|/[^\n]*$)"); comment->setMinimal(true); versionX = new QRegExp("$cannot possibly match^"); @@ -750,4 +755,14 @@ bool Tokenizer::isTrue(const QString &condition) return !falsehoods->exactMatch(t); } +QString Tokenizer::lexeme() const +{ + return sourceCodec->toUnicode(yyLex); +} + +QString Tokenizer::previousLexeme() const +{ + return sourceCodec->toUnicode(yyPrevLex); +} + QT_END_NAMESPACE diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h index 519cffb..f55d2ef 100644 --- a/tools/qdoc3/tokenizer.h +++ b/tools/qdoc3/tokenizer.h @@ -46,11 +46,10 @@ #ifndef TOKENIZER_H #define TOKENIZER_H +#include <qfile.h> #include <qstack.h> #include <qstring.h> -#include <stdio.h> - #include "location.h" QT_BEGIN_NAMESPACE @@ -99,7 +98,7 @@ class Tokenizer { public: Tokenizer(const Location& loc, const QByteArray &in); - Tokenizer(const Location& loc, FILE *in); + Tokenizer(const Location& loc, QFile &file); ~Tokenizer(); @@ -108,8 +107,8 @@ class Tokenizer bool parsingFnOrMacro() const { return parsingMacro; } const Location &location() const { return yyTokLoc; } - QString previousLexeme() const { return QString(yyPrevLex); } - QString lexeme() const { return QString(yyLex); } + QString previousLexeme() const; + QString lexeme() const; QString version() const { return yyVersion; } int braceDepth() const { return yyBraceDepth; } int parenDepth() const { return yyParenDepth; } |