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 :

QWebView et le clic droit


Sujet :

PyQt Python

  1. #1
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut QWebView et le clic droit
    Bonsoir,

    j'utilise un QWebView pour afficher une image depuis le web.

    Ca marche parfaitement mais il subsiste un petit truc...

    Si je fais un clic droit sur l'image, le menu me propose :
    - la copie de l'image (marche bien)
    - la copie de l'url (marche bien)
    - Ouvrir l'image
    - Sauvegarder l'image

    Mais les 2 dernieres options ne fonctionnent pas, il ne se passe rien.

    Est-il possible de modifier leurs actions ?

    Est-il possible de bloquer l'affichage du menu ?

    merci à vous !

  2. #2
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 303
    Par défaut
    Salut,

    Bloquer le menu, c'est simple, il suffit de réimplémenter le QWebView.contextMenuEvent.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    def contextMenuEvent(self, event):
        pass
    Par contre pour le menu existant, il n'existe aucune doc qui en explique l'usage et il semble à l'usage plus simple de créer son menu soi-même.
    Ce qui n'a rien de chinois.

  3. #3
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Ouais j'avais cherché dans la doc aussi avant de poster.

    Je vais essayer de virer le clic droit déjà

    Je reviens dire si c'est bon.

  4. #4
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Bon bah en effet ça marche très bien, et on peut remplacer simplement le menu par une version perso.

    merci bien, je n'y avais pas pensé.

  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,

    Grâce à ton message, je viens aussi de m'apercevoir que l'enregistrement des images lancé par le popup menu ne marchait pas, alors que j'utilise QWebView depuis déjà pas mal de temps...

    Alors, j'ai essayé aussi sur un exemple livré avec PyQt4 (fancybrowser.pyw), et... ça ne marche pas non plus! Serait-ce un bug???

    Toujours est-il que j'ai trouvé une solution, mais c'est loin d'être simple!

    On pourrait, bien sûr, remplacer le menu popup complètement, mais c'est beaucoup trop compliqué, parce qu'il faudrait le remplacer pour tous les objets html pour lesquels il y a un tel menu: on voit bien que le clic droit ne donne pas le même menu selon qu'on est sur un hyperlien ou sur une image par exemple. J'ai donc choisi de seulement corriger le menu qui concerne l'image.

    Pour la suite je suppose qu'on a une fenêtre QWidget ou QMainWindow avec un QWebView dedans qui s'appelle self.vuehtml.

    On commence par corriger le menu popup du QWebView

    Pendant l'initialisation de la fenêtre (__init__), il faut lancer le menu personnalisé du QWebView:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            self.vuehtml.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
            self.vuehtml.customContextMenuRequested.connect(self.popupmenuvuehtml)
    La méthode popupmenuvuehtml de la fenêtre sera donc exécutée à chaque clic droit sur le QWebView. Elle reçoit comme argument la position (QPoint) de la flèche de la souris lors du clic droit.

    Regardons maintenant le contenu de cette méthode:

    Il faut initialiser une variable QMenu, mais si on fait simplement popupmenu=QtGui.QMenu(self.vuehtml), on remplace tout le menu popup du QWebView, et c'est ce qu'on ne veut surtout pas faire.

    Alors, on va appeler le menu par défaut:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            page = self.vuehtml.page()
            popupmenu = page.createStandardContextMenu()
    Maintenant, il va falloir limiter nos corrections du menu standard à celui qui concerne l'image. Voilà comment:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            tagname = unicode(page.mainFrame().hitTestContent(position).element().tagName()).lower()
            if tagname == "img":
                # ici la correction du menu popup de l'image
    Maintenant, il va falloir neutraliser l'item standard "enregistrer l'image" qui ne marche pas, avant de le remplacer par autre chose. Voilà comment on fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                actionSaveImage = page.action(QtWebKit.QWebPage.DownloadImageToDisk)
                actionSaveImage.setEnabled(False)
                actionSaveImage.setVisible(False)
    D'ailleurs, en cherchant dans la doc du QWebPage, on peut voir tous les paramètres de type "DownloadImageToDisk", et on peut donc faire toutes les autres corrections nécessaires (affichage de l'image par exemple)

    Maintenant que l'item standard est neutralisé et invisible, on va créer un nouvel item:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
                imageurl =  page.mainFrame().hitTestContent(position).imageUrl() 
     
                # ajoute un séparateur des items du menu
                popupmenu.addSeparator()
     
                # ajoute un item supplémentaire
                actionTest = popupmenu.addAction(u"Enregistre l'image")
                actionTest.triggered.connect(partial(self.telecharge, imageurl))
    Donc, le nouvel item du popup menu (au dessus d'une image), lancera la méthode self.telecharge en lui passant, grâce à partial, l'url de l'image à télécharger.

    La méthode popupmenuvuehtml qui contient le code du popupmenu corrigé devra se finir par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            popupmenu.exec_(self.vuehtml.mapToGlobal(position))
    Récapitulation:

    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
        def popupmenuvuehtml(self, position):
            """menu popup du QWebView"""
     
            page = self.vuehtml.page()
     
            # récupération du menu popup standard du QWebView
            popupmenu = page.createStandardContextMenu()
     
            # calcul du tag html à la position de la souris
            tagname = unicode(page.mainFrame().hitTestContent(position).element().tagName()).lower()
            if tagname == "img":
                # ici, la souris est au dessus d'une image
     
                # calcule l'url de l'image à la position de la souris
                imageurl =  page.mainFrame().hitTestContent(position).imageUrl() 
     
                # neutralise l'item standard 
                actionSaveImage = page.action(QtWebKit.QWebPage.DownloadImageToDisk)
                actionSaveImage.setEnabled(False)
                actionSaveImage.setVisible(False)
     
                # ajoute un séparateur des items du menu
                popupmenu.addSeparator()
     
                # ajoute un item supplémentaire au menu popup
                actionTest = popupmenu.addAction(u"Enregistrer l'image")
                actionTest.triggered.connect(partial(self.telecharge, imageurl))
     
            # exécute le menu popup
            popupmenu.exec_(self.vuehtml.mapToGlobal(position))
    Maintenant que le code du menu popup est corrigé, il faut coder ce qui se passe quand on sélectionne l'item "Enregistrer l'image" => lance la méthode "self.telecharge(url)"

    Voilà ce que j'ai mis en place (il faudra compléter le filtrage des noms de fichiers pour les images: png, jpg, etc...):

    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
        @QtCore.pyqtSlot("QUrl")
        def telecharge(self, url):
            """télécharge l'url et l'enregistre sur disque"""        
     
            fichier = unicode(QtGui.QFileDialog.getSaveFileName (self, 
                                u"Nom du fichier disque", 
                                u".",
                                u"*.png"))
            if fichier==u"":
                return
            nfc = os.path.abspath(fichier)
     
            # lance le téléchargement et l'enregistrement sur disque
            self.telech = Telecharge(url, nfc)
            # assure la récupération du signal de fin de l'opération
            self.telech.fintelecharge.connect(self.telecharge_ok)
    On voit que cette méthode utilise Telecharge et se connecte à une autre méthode self.telecharge_ok à la réception du signal "fintelecharge". Voilà à quoi ça correspond:

    On fabrique une nouvelle classe "Telecharge", héritant de QtNetwork.QNetworkAccessManager:

    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
    class Telecharge(QtNetwork.QNetworkAccessManager):
     
        # nouveau signal pour indiquer la fin de l'opération à l'appelant
        fintelecharge = QtCore.pyqtSignal(bool)
     
        #==========================================================================
        def __init__(self, url, nfc):
            QtNetwork.QNetworkAccessManager.__init__(self)
     
            # stocke le nom du fichier à créer sur disque
            self.nfc = nfc
            # initialise le buffer de téléchargement
            self.messageBuffer = QtCore.QByteArray()
            # lance le téléchargement
            self.reply = self.get(QtNetwork.QNetworkRequest(url))    
            # branchement des signaux pour le téléchargement
            self.reply.readyRead.connect(self.readData)
            self.reply.finished.connect(self.finished)
     
        #==========================================================================
        @QtCore.pyqtSlot()
        def readData(self):
            """appelé à chaque fois que la lecture suivante est possible"""
            self.messageBuffer += self.reply.readAll()
     
        #==========================================================================
        @QtCore.pyqtSlot()
        def finished(self):
            """appelé à la fin du téléchargement: il ne reste plus qu'à enregistrer sur disque"""
            imageFile = QtCore.QFile(self.nfc)
            if(imageFile.open(QtCore.QIODevice.WriteOnly)):
                imageFile.write(self.messageBuffer)
                imageFile.close()      
                self.fintelecharge.emit(True)# émission signal de fin avec réussite
            else:
                self.fintelecharge.emit(False)# émission signal de fin avec échec
    On voit le principe: le chargement est bufferisé et est fait par morceau autant de fois que readData est appelé. Quand c'est fini, la méthode finished est appelée, et c'est elle qui enregistre sur disque et lance le signal "fintelecharge" qui va signaler à l'appelant que l'opération est terminée.

    La méthode qui sera appelée à la fin de l'opération contiendra cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        @QtCore.pyqtSlot(bool)
        def telecharge_ok(self, ok):
            """exécuté à la fin de l'opération téléchargement + enregistrement"""
            if ok:
                QtGui.QMessageBox.information(None, 
                                    u"Téléchargement", 
                                    u"Réussite: fichier enregistré sur disque!") 
            else:
                QtGui.QMessageBox.critical(None, 
                                    u"Téléchargement",
                                    u"Echec: fichier non enregistré!")
    Ouf. C'est fini! Et ça fonctionne bien chez moi. Désolé: c'est du Python 2.7 et PyQt4, mais l'idée est là.

    Et merci d'avoir posé la question: j'aurais eu besoin d'une solution un jour ou l'autre...

  6. #6
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 303
    Par défaut
    Wow, ça c'est du bon boulot.

    Merci.

    J'avais bien regardé le code source mais de toutes façons, avec le menu par défaut on a pas de signaux en retour. En d'autres termes on ne sait pas que l'utilisateur a cliqué sur "Enregistrer l'image", donc ça ne servait pas à grand chose.

  7. #7
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    ouha ca c'est du taf

    perso je me suis limité à virer le menu car ca se limite à afficher une image.

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

Discussions similaires

  1. Clic droit/gauche souris
    Par Mouse! dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 30/05/2013, 20h34
  2. Problème avec le clic droit
    Par nebule dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 20/10/2004, 16h29
  3. [FLASH MX2004] Clic droit contextuel
    Par pioup dans le forum Flash
    Réponses: 2
    Dernier message: 29/07/2004, 09h31
  4. Réponses: 2
    Dernier message: 09/05/2003, 17h41
  5. Evènement sur clic droit !?
    Par soccersoft dans le forum Composants VCL
    Réponses: 6
    Dernier message: 26/12/2002, 21h39

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