1

这个程序是一个红绿灯程序,但我想在窗口的右侧空间放置一个 gif,当颜色为绿色时将显示步行者 gif,当颜色为红色或黄色时显示停止 gif,所以我尝试使用我得到的 QMovie结果好坏参半,但仍然出现错误,或者 gif 不会出现在窗口中,您能帮帮我吗?

from itertools import cycle
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer,Qt,QPoint
from PyQt5.QtWidgets import QApplication,QMainWindow
from PyQt5.QtGui import QPainter,QColor,QMovie
class TrafficLight(QMainWindow):
    def __init__(self,parent = None):
        super(TrafficLight, self).__init__(parent)
        self.setWindowTitle("TrafficLight ")
        self.traffic_light_color1 = cycle(\[
            QColor('red'),
            QColor('gray'),
            QColor('gray')
        \])
        self.traffic_light_color2 = cycle(\[
            QColor('gray'),
            QColor('yellow'),
            QColor('gray')
        \])
        self.traffic_light_color3 = cycle(\[
            QColor('gray'),
            QColor('gray'),
            QColor('green')
        \])

        self._current_color1 = next(self.traffic_light_color1)
        self._current_color2 = next(self.traffic_light_color2)
        self._current_color3 = next(self.traffic_light_color3)
        timer = QTimer(self, timeout=self.change_color)
        x = 0
        if x == 0 :
            self.movie1 = QMovie("Walking-man2[enter image description here][1].gif")
            self.movie1.frameChanged.connect(self.repaint)
            self.movie1.start()
            timer.start(30*100)
            x = 1
        elif x == 1 :
            self.movie1 = QMovie("tenor(1).gif")
            self.movie1.frameChanged.connect(self.repaint)
            self.movie1.start()
            timer.start(10*100)
            x = 2
        elif x == 2:
            self.movie1 = QMovie("tenor(1).gif")
            self.movie1.frameChanged.connect(self.repaint)
            self.movie1.start()
            timer.start(40*100)
            x = 0
        self.resize(700, 510)

    @QtCore.pyqtSlot()
    def change_color(self):
        self._current_color1 = next(self.traffic_light_color1)
        self._current_color2 = next(self.traffic_light_color2)
        self._current_color3 = next(self.traffic_light_color3)
        self.update()

    def paintEvent(self, event):
        p1 = QPainter(self)
        p1.setBrush(self._current_color1)
        p1.setPen(Qt.black)
        p1.drawEllipse(QPoint(125, 125), 50, 50)

        p2 = QPainter(self)
        p2.setBrush(self._current_color2)
        p2.setPen(Qt.black)
        p2.drawEllipse(QPoint(125, 250),50,50)

        p3 = QPainter(self)
        p3.setBrush(self._current_color3)
        p3.setPen(Qt.black)
        p3.drawEllipse(QPoint(125, 375),50,50)

        currentFrame = self.movie1.currentPixmap()
        frameRect = currentFrame.rect()
        frameRect.moveCenter(self.rect().center())
        if frameRect.intersects(event.rect()):
            painter = QPainter(self)
            painter.drawPixmap(frameRect.left(), frameRect.top(), currentFrame)


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = TrafficLight()
    w.show() 
    sys.exit(app.exec_())
4

2 回答 2

2

将一种状态更改为另一种状态的逻辑可以使用有限状态机 (FSM) 来实现,幸运的是 Qt 使用状态机框架来实现它:

from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets

class LightWidget(QtWidgets.QWidget):
    def __init__(self, color, parent=None):
        super(LightWidget, self).__init__(parent)
        self._state = False
        self._color = color
        self.setFixedSize(150, 150)

    @QtCore.pyqtSlot()
    def turnOn(self):
        self._state = True
        self.update()

    @QtCore.pyqtSlot()
    def turnOff(self):
        self._state = False
        self.update()

    def paintEvent(self, event):
        color = self._color if self._state else QtGui.QColor('gray')
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(QtCore.Qt.black)
        painter.setBrush(color)
        painter.drawEllipse(self.rect())

class TrafficLightWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(TrafficLightWidget, self).__init__(parent)
        hlay = QtWidgets.QHBoxLayout(self)
        container = QtWidgets.QWidget()
        container.setStyleSheet('''background-color : black''')
        vlay = QtWidgets.QVBoxLayout(container)
        self.m_red = LightWidget(QtGui.QColor("red"))
        self.m_yellow = LightWidget(QtGui.QColor("yellow"))
        self.m_green = LightWidget(QtGui.QColor("green"))
        vlay.addWidget(self.m_red)
        vlay.addWidget(self.m_yellow)
        vlay.addWidget(self.m_green)
        hlay.addWidget(container, alignment=QtCore.Qt.AlignCenter)
        self.label = QtWidgets.QLabel("Test", alignment=QtCore.Qt.AlignCenter)
        hlay.addWidget(self.label, 1)

        red_to_yellow = createLightState(self.m_red, 30*1000, partial(self.change_gif, "gif_red.gif"))
        yellow_to_green = createLightState(self.m_yellow, 20*1000, partial(self.change_gif, "gif_yellow.gif"))
        green_to_yellow = createLightState(self.m_green, 40*1000, partial(self.change_gif, "gif_green.gif"))
        yellow_to_red = createLightState(self.m_yellow, 20*1000, partial(self.change_gif, "gif_yellow.gif"))

        red_to_yellow.addTransition(red_to_yellow.finished, yellow_to_green)
        yellow_to_green.addTransition(yellow_to_green.finished, green_to_yellow)
        green_to_yellow.addTransition(green_to_yellow.finished, yellow_to_red)
        yellow_to_red.addTransition(yellow_to_red.finished, red_to_yellow)

        machine = QtCore.QStateMachine(self)
        machine.addState(red_to_yellow)
        machine.addState(yellow_to_green)
        machine.addState(green_to_yellow)
        machine.addState(yellow_to_red)
        machine.setInitialState(red_to_yellow)
        machine.start()

    @QtCore.pyqtSlot()
    def change_gif(self, gif):
        last_movie = self.label.movie()
        movie = QtGui.QMovie(gif)
        self.label.setMovie(movie)
        movie.start()
        if last_movie is not None:
            last_movie.deleteLater()

def createLightState(light, duration, callback):
    lightState = QtCore.QState()
    timer = QtCore.QTimer(
        lightState, 
        interval=duration, 
        singleShot=True
    )
    timing = QtCore.QState(lightState)
    timing.entered.connect(light.turnOn)
    timing.entered.connect(callback)
    timing.entered.connect(timer.start)
    timing.exited.connect(light.turnOff)
    done = QtCore.QFinalState(lightState)
    timing.addTransition(timer.timeout, done)
    lightState.setInitialState(timing)
    return lightState


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = TrafficLightWidget()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())
于 2019-03-11T16:42:17.500 回答
1

虽然答案不如 eyllanesc 的那么花哨……您可以使椭圆依赖于可变颜色,然后更改存储的可变颜色并调用 update()。可以使用标签显示 gif

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer,Qt,QPoint
from PyQt5.QtWidgets import QApplication,QMainWindow
from PyQt5.QtGui import QPainter,QColor,QMovie

class TrafficLight(QtWidgets.QWidget):
    def __init__(self,parent = None):
        super(TrafficLight, self).__init__(parent)
        self.setWindowTitle("TrafficLight ")
        layout = QtWidgets.QHBoxLayout()
        self.setLayout(layout)
        self.lblGif = QtWidgets.QLabel()
        layout.addSpacing(300)
        layout.addWidget(self.lblGif)

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.changeLight)
        self.timer.start(3000)

        self.resize(700, 510)
        self.x = 0
        self.changeLight()

    def changeLight(self):
        if self.x == 0 :
            self.color1 = QColor('red')
            self.color2 = QColor('grey')
            self.color3 = QColor('grey')
            self.loadGif('wait.gif')
            self.x = 1

        elif self.x == 1 :
            self.color1 = QColor('grey')
            self.color2 = QColor('yellow')
            self.color3 = QColor('grey')
            self.loadGif('almost.gif')
            self.x = 2

        elif self.x == 2:
            self.color1 = QColor('grey')
            self.color2 = QColor('grey')
            self.color3 = QColor('green')
            self.loadGif('walk.gif')
            self.x = 0
        self.update()

    def loadGif(self, path):
        movie = QtGui.QMovie(path)
        self.lblGif.setMovie(movie)
        movie.start()

    def paintEvent(self, event):
        p1 = QPainter(self)
        p1.setBrush(self.color1)
        p1.setPen(Qt.black)
        p1.drawEllipse(QPoint(125, 125), 50, 50)
        p1.end()

        p2 = QPainter(self)
        p2.setBrush(self.color2)
        p2.setPen(Qt.black)
        p2.drawEllipse(QPoint(125, 250),50,50)
        p2.end()

        p3 = QPainter(self)
        p3.setBrush(self.color3)
        p3.setPen(Qt.black)
        p3.drawEllipse(QPoint(125, 375),50,50)
        p3.end()

if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = TrafficLight()
    w.show()
    sys.exit(app.exec_())
于 2019-03-11T17:31:13.870 回答