How to put a gif in gui using python PyQt5

This program is a trafficlight program but i want to put a gif on the right space of the window that will show a walking man gif when the color is green and a stop gif when in red or yellow so I tried to use QMovie which I get mixed results and still ended up in an error or the gif won't appear at the window can you please help me?

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_())

Upvotes: 1

Views: 1103

Answers (2)

Rhdr
Rhdr

Reputation: 387

Though the answer ain't as fancy as eyllanesc's... You can make the ellipse depend on a variable color, then change the stored variable color and call update(). The gif can be displayed using a label

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_())

Upvotes: 1

eyllanesc
eyllanesc

Reputation: 243947

The logic of changing one state to another can be implemented with a Finite State Machine (FSM), and fortunately Qt implements it using The State Machine Framework:

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_())

Upvotes: 3

Related Questions