Le focus clavier en QMLLorsqu'une touche est appuyée ou relâchée, un évènement clavier est généré et transmis à l'élément Item QML ayant le focus. Pour faciliter la construction de composants réutilisables et pour traiter certains cas propres aux interfaces utilisateur fluides, les éléments QML ajoutent une extension basée sur les portées au modèle de focus clavier traditionnel de Qt. Aperçu de la gestion des touchesLorsque l'utilisateur appuie sur une touche ou la relâche, il se passe les choses suivantes :
Voir aussi les propriétés-clés attachées et propriétés KeyNavigation attachées. Connaître l'élément possédant le focusLa propriété Item::activeFocus permet de savoir si un élément possède le focus ou non. Voici un exemple où le texte d'un élément Text est déterminé selon que l'élément possède le focus ou non. Text { text: activeFocus ? "J'ai le focus !" : "Je n'ai pas le focus" } Acquérir le focus et les portées de focusUn élément Item demande le focus en définissant la propriété focus à true. Pour les cas très simples, la définition de la propriété focus est suffisante. En exécutant l'exemple suivant avec le QML Viewer, on voit que l'élément keyHandler possède le focus et l'appui sur les touches A, B ou C modifie le texte selon la touche. Rectangle { color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } Item { id: keyHandler focus: true Keys.onPressed: { if (event.key == Qt.Key_A) myText.text = 'Key A was pressed' else if (event.key == Qt.Key_B) myText.text = 'Key B was pressed' else if (event.key == Qt.Key_C) myText.text = 'Key C was pressed' } } } Par contre, lorsque l'exemple ci-dessus doit être utilisé sous forme d'un composant importé ou réutilisé, la simple utilisation de la propriété focus ne suffit plus. Pour présenter ce cas, on crée deux instances du composant défini précédemment et on donne le focus au premier. Le but est que, lorsque l'une des touches A, B ou C est appuyée, le premier des deux composants reçoive l'évènement et réponde de façon appropriée. Le code qui importe et crée les deux instances de MyWidget est le suivant : // code de la fenêtre qui importe MyWidget Rectangle { id: window color: "white"; width: 240; height: 150 Column { anchors.centerIn: parent; spacing: 15 MyWidget { focus: true // Donne le focus à ce MyWidget color: "lightblue" } MyWidget { color: "palegreen" } } } Voici le code de MyWidget : // code de MyWidget Rectangle { id: widget color: "lightsteelblue"; width: 175; height: 25; radius: 10; smooth: true Text { id: label; anchors.centerIn: parent} focus: true Keys.onPressed: { if (event.key == Qt.Key_A) label.text = 'Key A was pressed' else if (event.key == Qt.Key_B) label.text = 'Key B was pressed' else if (event.key == Qt.Key_C) label.text = 'Key C was pressed' } } On aimerait donner le focus au premier objet MyWidget en définissant la propriété focus à true. Cependant, en exécutant le code, on constate que c'est second widget qui reçoit le focus. En observant le code de MyWidget et celui de la fenêtre window, le problème est évident - il y a trois éléments qui définissent la propriété focus à true. Les deux MyWidget définissent le focus à true et le composant fenêtre window également. En définitive, un seul élément peut posséder le focus clavier et le système doit décider quel élément recevra l'évènement. Lorsque le second MyWidget est créé, il reçoit le focus car c'est le dernier élément à définir la propriété focus à true. Ce problème est dû à la visibilité. Le composant MyWidget aimerait avoir le focus mais il ne peut pas contrôler le focus lorsqu'il est importé ou réutilisé. Pareillement, le composant fenêtre window n'a pas la capacité de savoir si ses composants importés demandent le focus. Pour résoudre ce problème, le QML introduit un concept connu sous le nom de portée de focus (focus scope). Pour les utilisateurs de Qt, une portée de focus ressemble à un proxy automatique pour le focus. La portée est créée en déclarant l'élément FocusScope. Dans l'exemple suivant, un élément FocusScope est ajouté au composant. FocusScope { // Le FocusScope doit se lier aux propriétés visuelles du Rectangle property alias color: rectangle.color x: rectangle.x; y: rectangle.y width: rectangle.width; height: rectangle.height Rectangle { id: rectangle anchors.centerIn: parent color: "lightsteelblue"; width: 175; height: 25; radius: 10; smooth: true Text { id: label; anchors.centerIn: parent } focus: true Keys.onPressed: { if (event.key == Qt.Key_A) label.text = 'Key A was pressed' else if (event.key == Qt.Key_B) label.text = 'Key B was pressed' else if (event.key == Qt.Key_C) label.text = 'Key C was pressed' } } } Voici le résultat visuel : Conceptuellement, les portées de focus sont très simples.
Notez que, comme l'élément FocusScope n'est pas un élément visuel, les propriétés de ses enfants doivent être exposées à l'élément parent du FocusScope. Les dispositions et les éléments de positionnement utiliseront ces propriétés visuelles et de styles pour déterminer le positionnement. Dans notre exemple, l'élément Column ne peut afficher les deux widgets correctement car le FocusScope ne possède pas de propriétés visuelles. Le composant MyWidget se lie directement aux propriétés de rectangle pour permettre à l'élément Column de créer la disposition contenant l'enfant du FocusScope. Jusqu'ici, l'exemple activait statiquement le focus sur le second composant. Il est maintenant trivial d'étendre ce composant pour le rendre cliquable, et de l'ajouter à l'application d'origine. On attribue toujours le focus initial à l'un des widgets. Maintenant, un clic sur l'un des MyClickableWidget lui donnera le focus et l'autre widget le perdra. Voici le code qui importe et crée les deux instances de MyClickableWidget : Rectangle { id: window color: "white"; width: 240; height: 150 Column { anchors.centerIn: parent; spacing: 15 MyClickableWidget { focus: true // donne le focus à ce MyWidget color: "lightblue" } MyClickableWidget { color: "palegreen" } } } Voici le code de MyClickableWidget : FocusScope { id: scope // Le FocusScope doit se lier aux propriétés visuelles de l'enfant property alias color: rectangle.color x: rectangle.x; y: rectangle.y width: rectangle.width; height: rectangle.height Rectangle { id: rectangle anchors.centerIn: parent color: "lightsteelblue"; width: 175; height: 25; radius: 10; smooth: true Text { id: label; anchors.centerIn: parent } focus: true Keys.onPressed: { if (event.key == Qt.Key_A) label.text = 'Key A was pressed' else if (event.key == Qt.Key_B) label.text = 'Key B was pressed' else if (event.key == Qt.Key_C) label.text = 'Key C was pressed' } } MouseArea { anchors.fill: parent; onClicked: { scope.focus = true } } } Lorsqu'un élément abandonne explicitement le focus (en affectant la valeur false à sa propriété focus lorsqu'il possède le focus), le système ne transmet pas automatiquement le focus à un autre élément. À ce moment, il est possible qu'aucun élément ne possède le focus. Voir l'exemple de focus clavier pour une démonstration d'un focus clavier passant entre différentes zones en utilisant les éléments FocusScope. Utilisation avancée des portées de focusLes portées de focus permettent de facilement partitionner l'allocation du focus. Plusieurs éléments QML l'utilisent dans ce but. Par exemple, ListView est elle-même une portée de focus. Généralement, cela ne se remarque pas car ListView ne possède habituellement pas d'enfants visuels ajoutés manuellement. Étant une portée de focus, la ListView peut donner le focus à l'élément courant de la liste sans se soucier des effets sur le reste de l'application. Cela permet au délégué de l'élément courant de réagir aux touches du clavier. Cet exemple artificiel montre comment cela fonctionne. L'appui sur la touche Entrée affichera le nom de l'élément courant de la liste. Rectangle { color: "lightsteelblue"; width: 100; height: 50 ListView { anchors.fill: parent focus: true model: ListModel { ListElement { name: "Bob" } ListElement { name: "John" } ListElement { name: "Michael" } } delegate: FocusScope { width: childrenRect.width; height: childrenRect.height x:childrenRect.x; y: childrenRect.y TextInput { focus: true text: name Keys.onReturnPressed: console.log(name) } } } } Bien que l'exemple soit simple, beaucoup de choses se déroulent en coulisse. Chaque fois que l'élément courant change, la ListView active la propriété Item::focus du délégué. Comme le ListView est une portée de focus, cela n'affecte pas le reste de l'application. Par contre, si la ListView possède le focus, le délégué lui-même recevra le focus. Dans cet exemple, l'élément racine du délégué est aussi une portée de focus, qui donne le focus à l'élément Text qui effectue le travail de gestion de la touche Entrée. Toutes les classes vues de QML, telles que PathView et GridView, se comportent de manière similaire et permettent la gestion des touches dans leurs délégués respectifs. RemerciementsMerci à Alexandre Laurent pour la traduction ainsi qu'à Ilya Diallo, Jonathan Courtois, Thibaut Cuvelier et Claude Leloup pour leur relecture ! |
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt 4.7 | |
Copyright © 2024 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |