IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PyQt Python Discussion :

utilisation de KeyPressEvent dans un QText Edit [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2009
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 22
    Par défaut utilisation de KeyPressEvent dans un QText Edit
    Bonjour,

    J'ai un souci avec un QTextEdit et l'appui sur la touche Entrée.
    Je souhaite, lorsque le focus et dans celui ci que l'action sur un bouton envoyer soit déclenché.
    J'ai pas mal regardé sur le web, mais je ne trouve pas de solution à mon pb.
    J'ai regardé la solution ici qui prend très bien mon appui sur la touche entré, mais je n'arrive pas a appelé ma fonction qui gère le click sur le bouton.

    Voici le code de ma fenêtre généré par QtDesigner
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    from PyQt5 import QtCore, QtGui, QtWidgets
     
    class Ui_f_client(object):
        def setupUi(self, f_client):
            f_client.setObjectName("f_client")
            f_client.resize(800, 600)
            self.te_msg_send = QtWidgets.QTextEdit(self.centralwidget)
            self.te_msg_send.setGeometry(QtCore.QRect(130, 490, 621, 101))
            self.te_msg_send.setObjectName("te_msg_send")
            self.b_send = QtWidgets.QPushButton(self.centralwidget)
            self.b_send.setGeometry(QtCore.QRect(755, 510, 41, 61))
            self.b_send.setObjectName("b_send")
            f_client.setCentralWidget(self.centralwidget)
     
            self.retranslateUi(f_client)
            QtCore.QMetaObject.connectSlotsByName(f_client)
     
        def retranslateUi(self, f_client):
            _translate = QtCore.QCoreApplication.translate
            f_client.setWindowTitle(_translate("f_client", "Home Chat"))
            self.b_connect.setText(_translate("f_client", "Connect"))
            self.lbl_connect_to.setText(_translate("f_client", "Connect to :"))
            self.b_send.setText(_translate("f_client", "Send"))
            self.lbl_name.setText(_translate("f_client", "Name :"))
            self.b_stop.setText(_translate("f_client", "Stop"))
    et le code de l'appli
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    class FenPrincipal(QtWidgets.QMainWindow, Vue.vclient.Ui_f_client):
        def __init__(self, parent=None):
            super(FenPrincipal, self).__init__(parent)
            self.setupUi(self)
            self.b_send.clicked.connect(self.Send)
            self.te_msg_send.__class__ = MonTextEdit
     
        def Send(self, val="a"):
            #Envoi du message
            if self.leThread.is_alive():
                self.leThread.messagetosend(self.te_msg_send.toPlainText())
            #vide la zone de saisie
            self.te_dialogue.appendPlainText(self.te_msg_send.toPlainText())
            self.te_msg_send.setText("")
     
    class MonTextEdit(QtWidgets.QTextEdit):
        def keyPressEvent(self, event):
            if event.key() == QtCore.Qt.Key_Enter or event.key() == QtCore.Qt.Key_Return:
                #FenPrincipal.Send()
                pass
            else:
                return super().keyPressEvent(event)
     
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = FenPrincipal()
        MainWindow.show()
        sys.exit(app.exec_())
    la référence au thread fonction. Quand je clique sur le bouton send, le comportement est ok.
    Mon problème ce trouve lorsque je veux faire le raccourci entre la touche entré et le clic sur le bouton.

    Merci pour vos retour
    eskehnach

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je ne suis pas sûr d'avoir bien compris le " faire le raccourci entre la touche entré et le clic sur le bouton", mais je vais essayer quand même.

    J'ai revu le fil du forum signalé (https://www.developpez.net/forums/d1...event-widgets/) qui date de 2014, et ça m'a rappelé des trucs . Depuis, j'utilise de plus en plus la méthode suivante. Par exemple:
    - je crée un QTextEdit sous QtDesigner
    - je crée un autre QTextEdit dans le programme principal, et il se substitue à celui du QtDesigner.

    Voilà un code de test qui fait ça.

    - Sous QtDesigner: un QTextEdit et un QPushButton à mettre dans un QMainWindow
    - Dans le programme principal, une classe QMainWindow et une classe QTextEdit

    Lors de l'initialisation du QMainWindow, les 2 lignes suivantes font que le QTextEdit du programme principal prend la place du QTextEdit du QtDesigner:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            self.ui.textEdit.__class__ = TextEdit
            self.ui.textEdit.configuration()
    La méthode "configuration" permet de configurer le nouveau QTextEdit.

    Le fichier issu de QtDesigner (après traitement par pyuic5) et appelé ici "programme_ui.py":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    # -*- coding: utf-8 -*-
     
    # Form implementation generated from reading ui file 'programme_ui.ui'
    #
    # Created by: PyQt5 UI code generator 5.15.2
    #
    # WARNING: Any manual changes made to this file will be lost when pyuic5 is
    # run again.  Do not edit this file unless you know what you are doing.
     
     
    from PyQt5 import QtCore, QtGui, QtWidgets
     
     
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(800, 600)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
            self.gridLayout_2.setObjectName("gridLayout_2")
            self.gridLayout = QtWidgets.QGridLayout()
            self.gridLayout.setObjectName("gridLayout")
            self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
            self.textEdit.setObjectName("textEdit")
            self.gridLayout.addWidget(self.textEdit, 0, 0, 1, 1)
            self.pushButton = QtWidgets.QPushButton(self.centralwidget)
            self.pushButton.setObjectName("pushButton")
            self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
            self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
     
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
     
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
            self.pushButton.setText(_translate("MainWindow", "PushButton"))
    Et le programme principal appelé ici "programme.py":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    # -*- coding: utf-8 -*-
     
    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets 
    from programme_ui import Ui_MainWindow
     
    ##############################################################################
    class TextEdit(QtWidgets.QTextEdit):
     
        # nouveau signal personnalisé
        returnButton = QtCore.pyqtSignal()
     
        #=========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.configuration()
     
        #=========================================================================
        def configuration(self):
     
            pass
     
        #=========================================================================
        def keyPressEvent(self, event):
            """permet de lancer des fonctions au clavier
            """
            #---------------------------------------------------------------------
            if event.key() in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter]:
                # touche return (ou enter du clavier numérique)
     
                print("Touche return")
     
                # émission du signal personnalisé
                self.returnButton.emit()
     
                event.accept()
                # la touche doit continuer à faire son boulot normal!
                super().keyPressEvent(event) 
     
            #---------------------------------------------------------------------
            elif event.key()==QtCore.Qt.Key_X and (event.modifiers() and QtCore.Qt.Key_Alt):
                # Appel par Alt-X
     
                print("Touche Alt-X tapée")
     
                event.accept()
     
            #---------------------------------------------------------------------
            else:
                # autres cas: transmet l'évènement clavier à l'ancêtre
                event.ignore()
                super().keyPressEvent(event)
     
    ##############################################################################
    class FenPrincipale(QtWidgets.QMainWindow):
     
        #=========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
     
            # la classe "TextEdit" prendra la place du QTextEdit de QtDesigner"
            self.ui.textEdit.__class__ = TextEdit
            self.ui.textEdit.configuration()
     
            # le clic sur le bouton lancera la méthode "clic"
            self.ui.pushButton.clicked.connect(self.clic)
     
            # la réception du signal returnButton lancera la même méthode que le bouton lui-même
            self.ui.textEdit.returnButton.connect(self.clic)
     
        #=========================================================================
        def clic(self):
     
            print("Clic sur le bouton!")
     
    ##############################################################################
    if __name__ == '__main__':
     
        app = QtWidgets.QApplication(sys.argv)
     
        fen = FenPrincipale()
        fen.show()
     
        sys.exit(app.exec_())
    Quand je clique sur le bouton, la console affiche "Clic sur le bouton". Et quand je tape "return" sur le QTextEdit, cela affiche deux lignes: "touche return", et "Clic sur le bouton". Cela parce que l'appui sur la touche return, grâce au signal "returnButton", lance la même méthode que le clic sur le bouton.

  3. #3
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2009
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 22
    Par défaut Merci!!!
    Bonjour Tyrtamos.
    Merci, c'est exactement ce que je cherchai, et désolé de ne pas avoir été trop clair. Mais tu as parfaitement compris ma demande.
    En tout cas, je m’aperçoit que je manque encore de pratique de Python et Qt pour penser à ce principe de réimplémenté la classe.

    Le fait de générer un nouveau signal et capter par l’élément graphique est ce que je voulais faire.
    Bonne continuation.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par tyrtamos Voir le message
    Quand je clique sur le bouton, la console affiche "Clic sur le bouton". Et quand je tape "return" sur le QTextEdit, cela affiche deux lignes: "touche return", et "Clic sur le bouton". Cela parce que l'appui sur la touche return, grâce au signal "returnButton", lance la même méthode que le clic sur le bouton.
    Pardon de poser une question. Ce code fonctionne évidemment, mais quel est l'action des event.accept() et/ou event.ignore() dans le keyPressEvent? J'ai tenté de les supprimer et ça fonctionne tout pareil...
    Pour moi, le event.accept() n'a d'utilité que pour le closeEvent afin d'accepter ou refuser la fermeture d'une QMainWindow. Enfin c'est là que je les utilise. De même l'appel à super().keyPressEvent() me semble dans tous les cas obligatoire, style "ok je surcharge une fonction mais je veux quand-même que la fonction d'origine fasse aussi son boulot"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour Sve@r,

    Citation Envoyé par Sve@r Voir le message
    Pardon de poser une question. Ce code fonctionne évidemment, mais quel est l'action des event.accept() et/ou event.ignore() dans le keyPressEvent? J'ai tenté de les supprimer et ça fonctionne tout pareil...
    Pour moi, le event.accept() n'a d'utilité que pour le closeEvent afin d'accepter ou refuser la fermeture d'une QMainWindow. Enfin c'est là que je les utilise. De même l'appel à super().keyPressEvent() me semble dans tous les cas obligatoire, style "ok je surcharge une fonction mais je veux quand-même que la fonction d'origine fasse aussi son boulot"...
    Entièrement d'accord! J'utilise systématiquement les "accept" et "ignore" avec les méthodes déclenchées par évènement, mais j'ai remarqué la même chose.

    Si on regarde la doc de Qt5 pour QEvent (https://doc.qt.io/qt-5/qevent.html), on lit (traduction):
    Le QEvent de base contient uniquement un paramètre de type d'événement et un indicateur "accept". L'indicateur d'acceptation défini avec accept () et effacé avec ignore (). Il est défini par défaut, mais ne comptez pas sur cela car les sous-classes peuvent choisir de l'effacer dans leur constructeur.
    Si maintenant, on regarde à QKeyEvent (https://doc.qt.io/qt-5/qkeyevent.html) qui hérite de QEvent , on lit (traduction):
    Un événement clé contient un indicateur d'acceptation spécial qui indique si le récepteur gérera l'événement clé. Cet indicateur est défini par défaut pour QEvent :: KeyPress et QEvent :: KeyRelease, il n'est donc pas nécessaire d'appeler accept () lors d'une action sur un événement clé. Pour QEvent :: ShortcutOverride, le récepteur doit accepter explicitement l'événement pour déclencher le remplacement. L'appel de ignore () sur un événement clé le propagera au widget parent. L'événement est propagé le long de la chaîne de widgets parent jusqu'à ce qu'un widget l'accepte ou qu'un filtre d'événement l'utilise.
    Ce qui confirme plus ou moins ce que nous avons constaté, mais ce qui n'interdit pas ce que je fais.

    Dans la doc de QCloseEvent (https://doc.qt.io/qt-5/qcloseevent.html) qui hérite aussi de QEvent, on lit (traduction):
    La fonction isAccepted () renvoie true si le récepteur de l'événement a accepté de fermer le widget; appelez accept () pour accepter de fermer le widget et appelez ignore () si le récepteur de cet événement ne veut pas que le widget soit fermé.
    Ce qui est plus clair, et justifie ce qu'on connait déjà...

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Entièrement d'accord!...Ce qui est plus clair, et justifie ce qu'on connait déjà...
    Et concernant l'appel à super().keyPressEvent() que je fais systématiquement tu en penses quoi?

    Voici par exemple comment j'ai réécrit ta fonction
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    def keyPressEvent(self, event):
    	"""permet de lancer des fonctions au clavier
            """
    	#---------------------------------------------------------------------
    	if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
    		# touche return (ou enter du clavier numérique)
    		print("Touche return")
     
    		# émission du signal personnalisé
    		self.returnButton.emit()
     
    	#---------------------------------------------------------------------
    	elif event.key() == QtCore.Qt.Key_X and (event.modifiers() and QtCore.Qt.Key_Alt):
    		# Appel par Alt-X
    		print("Touche Alt-X tapée")
    	# if (j'aime bien montrer la fin des blocs)
     
    	# la fonction originelle doit aussi faire son boulot..
    	super().keyPressEvent(event)
    # keyPressEvent()
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonsoir Sve@r

    Citation Envoyé par Sve@r Voir le message
    Et concernant l'appel à super().keyPressEvent() que je fais systématiquement tu en penses quoi?
    C'est simple: l'appel à super().keyPressEvent() n'est nécessaire que pour laisser passer les touches qui remplissent une fonction dans le widget qui a le focus.

    Par exemple, dans le code précédent:

    - la touche return a une fonction dans le QTextEdit, il faut donc la laisser passer (sinon, il n'y aurait pas de "passage à la ligne").

    - par contre, le "Alt-X" n'ayant aucune fonction dans ce widget, il n'est pas nécessaire de le laisser passer. Mais bien sûr, dans la mesure où ce Alt-X n'est pas interprété par le QTextEdit, on peut le laisser passer sans qu'il ne se passe quoique que ce soit. Il faut seulement en être sûr, et ce n'est pas évident pour des widgets complexes. C'est pour ça que je préfère ne pas le transmettre dans ce cas.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Utiliser les touches flèche dans un controle Edit
    Par Henri dans le forum Windows
    Réponses: 6
    Dernier message: 26/05/2006, 22h32
  2. utilisation du contenu d'un champ edit dans une requete sql
    Par amri2006 dans le forum C++Builder
    Réponses: 2
    Dernier message: 23/01/2006, 16h05
  3. Utilisation de MAX dans une requête SQL
    Par Evil onE dans le forum Langage SQL
    Réponses: 7
    Dernier message: 15/06/2004, 18h38
  4. impossible d'utiliser ma fonction dans un insert
    Par caramel dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 10/04/2003, 15h04
  5. Utilisation de Pointeurs dans API windows
    Par Drooxy dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 13/03/2003, 22h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo