Reputation: 121
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
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
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