在PyQt中连接类之间的信号和槽

3

目标是将TicTacToe这个顶级类的信号与类连接起来。

它会抛出一个错误:TicTacToe无法在此上下文中转换为PyQt5.QtCore.QObject

#!/usr/bin/env python


from PyQt5.QtCore import (QLineF, QPointF, QRectF, pyqtSignal)
from PyQt5.QtGui import (QIcon, QBrush, QColor, QPainter, QPixmap)
from PyQt5.QtWidgets import (QAction, QMainWindow, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem,
                             QGridLayout, QVBoxLayout, QHBoxLayout,
                             QLabel, QLineEdit, QPushButton)

class TicTacToe(QGraphicsItem):
    def __init__(self):
        super(TicTacToe, self).__init__()

    def paintEvent(self, painter, option, widget):
        painter.setPen(Qt.black)
        painter.drawLine(0,100,300,100)


    def boundingRect(self):
        return QRectF(0,0,300,300)

    def mousePressEvent(self, event):
        pos = event.pos()
        self.select(int(pos.x()/100), int(pos.y()/100))
        self.update()
        super(TicTacToe, self).mousePressEvent(event)

    messageSignal = pyqtSignal(int)


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        scene = QGraphicsScene(self)
        self.tic_tac_toe = TicTacToe()
        scene.addItem(self.tic_tac_toe)

        scene.addPixmap(QPixmap("exit.png"))

        self.setScene(scene)

    def keyPressEvent(self, event):
        key = event.key()
        if key == Qt.Key_R:
            self.tic_tac_toe.reset()
        super(MyGraphicsView, self).keyPressEvent(event)

class Example(QMainWindow):    
    def __init__(self):
        super(Example, self).__init__()

        self.y = MyGraphicsView()
        self.setCentralWidget(self.y)

        self.y.tic_tac_toe.messageSignal.connect (self.messageSlot)

        self.initUI()

    def messageSlot(self, val):
        self.statusBar().showMessage(val)


    def initUI(self):               
        self.toolbar = self.addToolBar('Tools')


        self.setGeometry(30, 30, 30, 20)
        self.setWindowTitle('Menubar')    
        self.show()        


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    mainWindow = Example()

    mainWindow.showFullScreen()
    sys.exit(app.exec_())
2个回答

5
只有继承自 QObject 的类才能创建信号,例如 QWidgetQMainWindowQGraphicsView 都继承自 QObject,因此它们可以拥有信号。但是,由于效率问题,QGraphicsItem 不继承自 QObject,因此它们无法创建信号。如果您想要一个是 QObject 的项,必须使用 QGraphicsObject。此外,项具有 paint() 方法,而非 paintEvent()
class TicTacToe(QGraphicsObject):
    def paint(self, painter, option, widget):
        painter.setPen(Qt.black)
        painter.drawLine(0,100,300,100)

    def boundingRect(self):
        return QRectF(0,0,300,300)

    def mousePressEvent(self, event):
        pos = event.pos()
        # self.select(int(pos.x()/100), int(pos.y()/100))
        self.update()
        super(TicTacToe, self).mousePressEvent(event)

    messageSignal = pyqtSignal(int)

如果您仍想使用 QGraphicsItem,一个可能的解决方法是创建一个负责通信的类,并继承自 QObject
class Helper(QObject):
    messageSignal = pyqtSignal(int)

class TicTacToe(QGraphicsObject):
    def __init__(self, helper):
        super(TicTacToe, self).__init__()
        self.helper = helper

    def paint(self, painter, option, widget):
        painter.setPen(Qt.black)
        painter.drawLine(0,100,300,100)

    def boundingRect(self):
        return QRectF(0,0,300,300)

    def mousePressEvent(self, event):
        pos = event.pos()
        self.helper.emit(10)
        # self.select(int(pos.x()/100), int(pos.y()/100))
        self.update()
        super(TicTacToe, self).mousePressEvent(event)


class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        scene = QGraphicsScene(self)
        self.helper = Helper(self)
        self.tic_tac_toe = TicTacToe(self.helper)
        scene.addItem(self.tic_tac_toe)
        scene.addPixmap(QPixmap("exit.png"))
        self.setScene(scene)

    def keyPressEvent(self, event):
        key = event.key()
        if key == Qt.Key_R:
            self.tic_tac_toe.reset()
        super(MyGraphicsView, self).keyPressEvent(event)

class Example(QMainWindow):    
    def __init__(self):
        super(Example, self).__init__()

        self.y = MyGraphicsView()
        self.setCentralWidget(self.y)
        self.helper.messageSignal.connect(self.messageSlot)
        self.initUI()

    def messageSlot(self, val):
        self.statusBar().showMessage(val)


    def initUI(self):               
        self.toolbar = self.addToolBar('Tools')
        self.setGeometry(30, 30, 30, 20)
        self.setWindowTitle('Menubar')    
        self.show()  

3
问题在于你的类 TicTacToe 没有直接或间接继承自 QObject,这意味着它不能被 Qt 用作信号源。
尝试改为从 QGraphicsObject 继承...
class TicTacToe(QGraphicsObject):
def __init__(self):
    super(TicTacToe, self).__init__()

但我需要QGraphicsItem。QGraphicsItem没有继承自QObject吗?有什么解决方法吗? - Aquarius_Girl
1
“我需要QGraphicsItem”这句话的确切意思是什么?QGraphicsItem并没有继承自QObject,但是QGraphicsObject同时继承了QGraphicsItemQObject。因此,在我看来,在这种情况下用QGraphicsObject替换QGraphicsItem应该完全可以胜任。 - G.M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接