PyQt4: mouseReleaseEvent(), Reaktion darauf im Hauptfenster?

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
BeFu
User
Beiträge: 7
Registriert: Donnerstag 4. April 2013, 07:59
Wohnort: Europa
Kontaktdaten:

Hallo,

mit beiegügtem Code (Python 3.3.1 PyQt4.10) sollte mein Verständnisproblem ersichtlich sein:
Wie können auf einen Mouse-Klick (rechts) in einem Unterfenster (hier definiert in loglistwidget.py) reagiert werden, und dabei Daten aus dem Unterfenster im Hauptfenster (MainWindow) weiter bearbeitet werden?

In class MainWindow hängt self.listWidget als logDockWidget von MainWindow. In listWidget werden die in MainWindow ausgelösten Operationen gelogt und angezeigt. Ein Rechts-Klick im logWidget öffnet den Frage-Dialog, ob die darin gelogten Operationen tatsächlich gelöscht werden sollen. Dazu wir die Instanz self.listWidget von der eigens programmierten class LogListWidget() abegleitet. In dessen Methode mouseReleaseEvent() wird kontrolliert, ob die rechte Maus-Taste nach Klick wieder losgelassen wird. In diesem Fall wird der Inhalt von self.listWidget gelöscht.

Nun möchte ich die in self.mouseEventList (Attribut von class LogListWidget() ) gepeicherten Daten in MainWindow weiter bearbeiten können.

Welchen Code muss ich dazu eventuell in class LogListWidget() ergänzen um das Signal (Event) rightMouseButtonReleased zu werfen (emit)?

Und mit welchem Code reagiere ich in MainWindow auf das oben genannte Signal?

Meine Versuche in MainWindow auf in self.listWidget ausgelöste Events gemäß http://zetcode.com/tutorials/pyqt4/germ ... ndsignals/ zu reagieren sind gescheitert.

Weclches self.connect( ...?...) muss ich dazu in __init__() von class MainWindow() einfügen?

Toll wäre, wenn Ihr in Eurer Antwort den beigefügten Code ergänzt. - Danke.

Schöne Grüße,

BeFu
P.S.: Wie kann ich die Anzeige des log-Widget verhindern, das nach Rechts-Klick auf self.listWidget erscheint?

EventSignalSlot.pyw:

Code: Alles auswählen

#!/bin/usr/env python3
# -*- coding: utf-8 -*-
#
#
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import loglistwidget    # class of logListWidget in which 
                        # specific event handlers are reimplemented

__DEBUG__= False    # True for debugging

__version__ = "0.0.1"

MTIME= 5000 # time in ms for showing messages

# MainMindow is additional child from 'loglistwidget.LogListWidget'.
# Otherwise we won't be able to handle events (like mouse clicks) that 
# are done in 'loglistwidget.LogListWidget'
class MainWindow(QMainWindow, loglistwidget.LogListWidget):
    def __init__(self, parent= None):
        super(MainWindow, self).__init__(parent)
        self.dirty= False               # True after change of file
        self.filename= None
        
        # log history of operations and show them in dock window
        logDockWidget= QDockWidget("Log", self)
        logDockWidget.setObjectName("LogDockWidget")
        logDockWidget.setAllowedAreas(Qt.RightDockWidgetArea)
        self.listWidget= loglistwidget.LogListWidget()
        logDockWidget.setWidget(self.listWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)
        
        # The calculated crc is shown in the application's status bar
        self.crcLabel= QLabel() # Display Widget
        self.crcLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        status= self.statusBar()
        status.setSizeGripEnabled(False)
        status.addPermanentWidget(self.crcLabel)
        status.showMessage("Ready", MTIME)
 
        # create application's actions with help method createAction
        # File Menu Actions:
        fileNewAction= self.createAction("&New ...", self.fileNew,
                            QKeySequence.New, None, "Load file")
        fileOpenAction = self.createAction("&Open...", self.fileOpen,
                QKeySequence.Open, None,
                "Open file")
        fileQuitAction= self.createAction("&Quit", self.close, "Ctrl+Q", 
                            None, "Close the application")

        # create reference of file menu in application's memu bar
        self.fileMenu = self.menuBar().addMenu("&File")
        
        # add created actions to application's file menue
        self.fileMenuActions = (fileNewAction, fileOpenAction,
#                fileSaveAction, fileSaveAsAction, 
                None, 
#                filePrintAction,
                fileQuitAction)        
        
        self.connect(self.fileMenu, SIGNAL("aboutToShow()"),
                     self.updateFileMenu)  
              
        # set minimum size of MainWindow
        self.setMinimumSize(600, 150)
        if __DEBUG__ :
            print("width= {}, heigth= {}".
                  format(self.listWidget.width(), 
                         self.listWidget.height()))

        self.setWindowTitle("EventSignalSlot v{}".format(__version__))
        

#### Frage:
        # Welche Methode muss ich in LogListWidget() implementieren,
        # damit ich das Signal (Event?) hier in MainWindow() auswerten
        # kann, um z.B. die in LogLostWidget() erzeugte Maus - 'info' 
        # hier weiter verarbeiten zu können?
        # Nach meinem Verständnis müsste hierzu ein SIGNAL (EVENT?)
        # mit 'info' als Paramenter von LogListWidget() geliefert werden.
        #
        # Gemäß http://zetcode.com/tutorials/pyqt4/eventsandsignals/
        # würde ich im hiesigen __init__() die SIGNAL-SLOT-Verbindug
        # herstellen mit
        # self.listWidget.mouseRelaseEvent.connect(self.showInfo) 
        # Das klappt nicht, da mouseReleaseEvent über keine Methode
        # connect verfügt.
        # 
####    

    # drop mouse events that are taken in MainWindow.
    # So they are not handled by the loglistwidget
    def mouseReleaseEvent(self, event):
        pass

    def showListWidget(self):
        print("Hallo")


#### Frage:
    # Hier würde ich die SLOT-Methode implementieren, welche die von
    # LotListWidget() gelieferte Maus - 'info' weiter verarbeitet,
    # z.B. in einer MessageBox anzeigt, oder in einer Datei speichert ...
    #
    # def showInfo(self, info):
    #    QMessageBox.information(self, "listWidget Info",
    #                            info, QMessageBox.Ok)
    #
####
            
    # helper method for creating available menu actions of our application
    def createAction(self, text, slot= None, shortcut= None, icon= None,
                     tip= None, checkable= False, signal="triggered()"):
        action= QAction(text, self)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if shortcut is not None:
            action.setShortcut(shortcut)
        if icon is not None:
            action.setIcon(QIcon(":/{}.png".format(icon)))
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if checkable:
            action.setCheckable(True)
        return(action)
    
    # helper method for adding actions to appropriate menu in menu bar
    def addActions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)
            
    # method for controlling whether changes are made and should be stored
    def okToContinue(self):
        if self.dirty:
            reply = QMessageBox.question(self,
                    "Checksum Calculator - Unsaved Changes",
                    "Save unsaved calculations?",
                    QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                return self.fileSave()
        return True
    
    # method for displaying message in statusbar of MainWindow and 
    # list widget of log widget
    def updateStatus(self, message):
        self.statusBar().showMessage(message, MTIME)
        self.listWidget.addItem(message)
        
    def updateFileMenu(self):
        self.fileMenu.clear()   # clearing all action of 'File munu'
        # add back original list of File menu actions except of 'flie quit'
        self.addActions(self.fileMenu, self.fileMenuActions[:-1])
                
    # Define own slot functions:of MainWindow
    def fileNew(self):
        if not self.okToContinue():
            return
        else:
            self.updateStatus("Create new file not possible")
  
    def fileOpen(self):
        if not self.okToContinue():
            return
        else:
            self.updateStatus("Open a file is not implemented yet")
            return
    

# main #######################################################################
def main():
    app = QApplication(sys.argv)
    app.setApplicationName("EventSignalSlot")
    form = MainWindow()
    form.show()
    app.exec_()


main()
loglistwidget.py:

Code: Alles auswählen

#!/bin/usr/env python3
# -*- coding: utf-8 -*-
#
# class of LogListWigdet with reimplemented specific event handlers

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class LogListWidget(QListWidget, QObject):
    """
    'LogListWidget' is child of 'QListWidget' with reimplemented
    event handlers.
    
    Parameter:
    ----------
    parent window
    
    Reimplemented Event Handlers:
    -----------------------------
    mouseReleaseEvent:    provides list with informations
                          after mouse button is released.
    """
    def __init__(self, parent= None):
        super(LogListWidget, self).__init__(parent)   
                
        self.mouseEventList=[]  # list of data that are handled by the
                                # MainWindow of application 
    
    # PyQt implements also events that occur when we press a mouse boutten
    # for example on a QtGui.QListWidget
    # 
    # mouseReleaseEvent(self, QMouseEvent e)
    # mousePressEvent(self, QMouseEvent e)
    #

    def mouseReleaseEvent(self, event):
        """
        Reimplemented Event Handler:
        
        SIGNAL oder EVENT?
        ------
        list with the following elements:
         - which mouse butten was released: 1 = Left Button, 2 = Right Button
         - item at the position where mouse button was released
         - x, v coordinates of position where mouse button was released
        """         
        self.mouseEventList.clear()
        button= event.button()
        if button == 1:
            info=" Left Mouse Button was released"
        if button == 2:
            info= "Right Mouse Button was releaded"

        # first element of list: 1= Left Button or 2= Right Button
        self.mouseEventList.append(button)
        #second element of list: x- and y-coordinate of mouse Position
        mpos=(event.x(), event.y())
        self.mouseEventList.append(mpos)        
        
        info+= " at x={}, y={}".format(mpos[0], mpos[1])

        # select an item on which was clicked
        item= self.itemAt(event.x(), event.y())
        if item: 
            # third emelement of list: item that was clicked
            self.mouseEventList.append(item)
            info+= "; item: {}".format(item.text(), QMessageBox.Ok)


#### Frage:
        # Der Inhalt von 'info' soll in 'MainWindow()' weiter 
        # bearbeitbar sein. 
        # 'MainWindow()' ist in 'eventsignalSlot.pyw' definiert
        #
        # QMessageBox hier auskommentiert, da sonst 'LogListWidget'
        # hier verlassen wird.
        # 
        # QMessageBox.information(self, "Mouse Info",
        #                        info, QMessageBox.Ok)
####

        if button ==2:
            if QMessageBox.question(self, "Log", 
                    "Do you really want to clear log list?", 
                    QMessageBox.Ok, QMessageBox.No) == QMessageBox.Ok:
                self.clear()

    def getMouseEventList(self):
        return(self.mouseEventList)
    
    # Make events available by properties
    mouseeventlist= property(getMouseEventList)

# main #######################################################################
if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    logListWidget = LogListWidget()
    logListWidget.show()
    app.exec_()
Zuletzt geändert von Anonymous am Freitag 10. Mai 2013, 07:50, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Das Ziel ist der Weg
BeFu
User
Beiträge: 7
Registriert: Donnerstag 4. April 2013, 07:59
Wohnort: Europa
Kontaktdaten:

Hallo,

der beigefügte Code zeigt wie man den SIGNAL - SLOT Mechanismus in einer mit PyQt4 erstellten GUI nutzen kann, um in einer Kontroll-Klasse (MainWindow) Daten weiter bearbeiten zu können, welche aus einem davon aufgerufenen Widget (self.listWidget) stammen.

Zur Übergabe der Daten muss im aufgerufenen Widget ein pyqtSignal(...) erzeugt werden.
Die in diesem aufgerufenen Widget überschriebene Methode mouseReleaseEvent(...) emit dieses SIGNAL, das in MainWindow mit der dort definierten SLOT -Methode verbunden wird.

In den beigefügten *.py Dateien stehen #### vor und nach den relevanten Code-Abschnitten.

Toll wäre, wenn jemand wüsste, an welcher Stelle event.accep() bzw. event.ignore() oder Event-Filter ?? eingefügt werden müssen, damit nach loslassen des rechten Mouse Button im self.listWidget dieses Event nicht weiter an MainWindow gereicht wird, und das Widget zum (De)Aktivieren des Log-Widget erscheint.

Schöne Grüße,

BeFu

EventSignalSlot.py

Code: Alles auswählen

#!/bin/usr/env python3
# -*- coding: utf-8 -*-
#
#
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import loglistwidget    # class of logListWidget in which 
                        # specific event handlers are reimplemented

__version__ = "0.0.2"

MTIME= 5000 # time in ms for showing messages

# MainMindow is additional child from 'loglistwidget.LogListWidget'.
# Otherwise we won't be able to handle events (like mouse clicks) that 
# are done in 'loglistwidget.LogListWidget'
class MainWindow(QMainWindow, loglistwidget.LogListWidget):
    def __init__(self, parent= None):
        super(MainWindow, self).__init__(parent)
        self.dirty= False               # True after change of file
        self.filename= None
        
        # log history of operations and show them in dock window
        logDockWidget= QDockWidget("Log", self)
        logDockWidget.setObjectName("LogDockWidget")
        logDockWidget.setAllowedAreas(Qt.RightDockWidgetArea)
        self.listWidget= loglistwidget.LogListWidget()
        logDockWidget.setWidget(self.listWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)
        
        # The calculated crc is shown in the application's status bar
        self.crcLabel= QLabel() # Display Widget
        self.crcLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        status= self.statusBar()
        status.setSizeGripEnabled(False)
        status.addPermanentWidget(self.crcLabel)
        status.showMessage("Ready", MTIME)
 
        # create application's actions with help method createAction
        # File Menu Actions:
        fileNewAction= self.createAction("&New ...", self.fileNew,
                            QKeySequence.New, None, "Load file")
        fileOpenAction = self.createAction("&Open...", self.fileOpen,
                QKeySequence.Open, None,
                "Open file")
        fileQuitAction= self.createAction("&Quit", self.close, "Ctrl+Q", 
                            None, "Close the application")

        # create reference of file menu in application's memu bar
        self.fileMenu = self.menuBar().addMenu("&File")
        
        # add created actions to application's file menue
        self.fileMenuActions = (fileNewAction, fileOpenAction,
#                fileSaveAction, fileSaveAsAction, 
                None, 
#                filePrintAction,
                fileQuitAction)        
        
        self.connect(self.fileMenu, SIGNAL("aboutToShow()"),
                     self.updateFileMenu)  
              
        # set minimum size of MainWindow
        self.setMinimumSize(600, 150)

        self.setWindowTitle("EventSignalSlot v{}".format(__version__))

####        
        # Connect SIGNAL 'mouseReleased' which is emit by self.listWidget
        # with SLOT self.showListWidget
        self.listWidget.mouseReleased.connect(self.showListWidget)
####

    # drop mouse events that are taken in MainWindow.
    # So they are not handled by the loglistwidget
    def mouseReleaseEvent(self, event):
        pass

####
    # decorator for PyQt4 SLOT function <-- it's a must!
    @pyqtSlot(str)    
    def showListWidget(self, msg):
        QMessageBox.information(self, "EventSignalSlot", 
                "Current List of selected item for Log Widget:"
                "\n\n{}".format(msg))
####

    # helper method for creating available menu actions of our application
    def createAction(self, text, slot= None, shortcut= None, icon= None,
                     tip= None, checkable= False, signal="triggered()"):
        action= QAction(text, self)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if shortcut is not None:
            action.setShortcut(shortcut)
        if icon is not None:
            action.setIcon(QIcon(":/{}.png".format(icon)))
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if checkable:
            action.setCheckable(True)
        return(action)
    
    # helper method for adding actions to appropriate menu in menu bar
    def addActions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)
            
    # method for controlling whether changes are made and should be stored
    def okToContinue(self):
        if self.dirty:
            reply = QMessageBox.question(self,
                    "Checksum Calculator - Unsaved Changes",
                    "Save unsaved calculations?",
                    QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                return self.fileSave()
        return True
    
    # method for displaying message in statusbar of MainWindow and 
    # list widget of log widget
    def updateStatus(self, message):
        self.statusBar().showMessage(message, MTIME)
        self.listWidget.addItem(message)
        
    def updateFileMenu(self):
        self.fileMenu.clear()   # clearing all action of 'File munu'
        # add back original list of File menu actions except of 'flie quit'
        self.addActions(self.fileMenu, self.fileMenuActions[:-1])
                
    # Define own slot functions:of MainWindow
    def fileNew(self):
        if not self.okToContinue():
            return
        else:
            self.updateStatus("Create new file not possible")
  
    def fileOpen(self):
        if not self.okToContinue():
            return
        else:
            self.updateStatus("Open a file is not implemented yet")
            return
    

# main #######################################################################
def main():
    app = QApplication(sys.argv)
    app.setApplicationName("EventSignalSlot")
    form = MainWindow()
    form.show()
    app.exec_()


main()
loglistwidget.py

Code: Alles auswählen

#!/bin/usr/env python3
# -*- coding: utf-8 -*-
#
# class of LogListWigdet with reimplemented specific event handlers

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class LogListWidget(QListWidget, QObject):
    """
    'LogListWidget' is child of 'QListWidget' with reimplemented
    event handlers.
    
    Parameter:
    ----------
    parent window
    
    Reimplemented Event Handlers:
    -----------------------------
    mouseReleaseEvent:    provides list with informations
                          after mouse button is released.
    """
####    
    # Create PyQt Signal for Released Mouse Button as class attribute
    # Emit this Signal after right Mouse Button is released
    mouseReleased = pyqtSignal(str)
####    

    def __init__(self, parent= None):
        super(LogListWidget, self).__init__(parent)   
                
        self.mouseEventList=[]  # list of data that are handled by the
                                # MainWindow of application 
    
    # PyQt implements also events that occur when we press a mouse boutten
    # for example on a QtGui.QListWidget
    # 
    # mouseReleaseEvent(self, QMouseEvent e)
    # mousePressEvent(self, QMouseEvent e)
    #

    def mouseReleaseEvent(self, event):
        """
        Reimplemented Event Handler:
        
        emit SIGNAL on EVENT (Right Mouse Button Released)
        ------
        list with the following elements:
         - which mouse butten was released: 1 = Left Button, 2 = Right Button
         - item at the position where mouse button was released
         - x, v coordinates of position where mouse button was released
        """         
        button= event.button()

        # first element of list: 1= Left Button or 2= Right Button
        self.mouseEventList.append(button)
        #second element of list: x- and y-coordinate of mouse Position
        mpos=(event.x(), event.y())
        self.mouseEventList.append(mpos)        

        # select an item on which was clicked
        item= self.itemAt(event.x(), event.y())
        if item: 
            # third emelement of list: item that was clicked
            self.mouseEventList.append(str(item.text()))

        if button ==2:
            if QMessageBox.question(self, "Log", 
                    "Do you really want to clear log list?", 
                    QMessageBox.Ok, QMessageBox.No) == QMessageBox.Ok:
                self.clear() # Clear List of logWidget
####
                # Emit SIGNAL with every entry since start of application 
                self.mouseReleased.emit(str(self.mouseEventList))
####
                

# main #######################################################################
if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    logListWidget = LogListWidget()
    logListWidget.show()
    app.exec_()
Das Ziel ist der Weg
Antworten