The purpose of this code is to have a square that appears in a canvas for some time and is then erased. I understand that all painting events must be handled by the overloaded function paintEvent.
However, first, the squares are not being drawn and I believe, that the times at which the squares are supposed to be drawn and erased are not being respected either. My guess is this happens due to the frequency at which the event appears.
I already tried to call QPaintEvent under the functions drawApple and eraseApple. What am I missing?
import sys, random
import numpy as np
import math
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QTimer
from PyQt4.QtCore import QRect
from PyQt4.QtGui import QPaintEvent
class Game(QtGui.QMainWindow):
def __init__(self):
super(Game, self).__init__()
self.initUI()
def initUI(self):
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Background, QtCore.Qt.white)
self.setPalette(palette)
self.tboard = Board(self)
self.setCentralWidget(self.tboard)
self.resize(400, 400)
self.center()
self.setWindowTitle('Game')
self.show()
def center(self):
screen = QtGui.QDesktopWidget().screenGeometry()
size = self.geometry()
self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
class Board(QtGui.QFrame):
BoardWidth = 400
BoardHeight = 400
SquareWidth = 15
SquareHeight = 15
Speed = 10000
def __init__(self, parent):
super(Board, self).__init__(parent)
#self.setAutoFillBackground(True)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.timer_draw = QtCore.QTimer()
self.timer_draw.timeout.connect(self.drawApple)
self.timer_draw.start(self.Speed)
self.timer_draw.setInterval(self.Speed)
self.timer_erase = QtCore.QTimer()
self.timer_erase.timeout.connect(self.eraseApple)
self.timer_erase.start(self.Speed + self.Speed/2)
self.timer_erase.setInterval(self.Speed)
self.apple_color = QtCore.Qt.red
self.bkg_color = QtCore.Qt.white
self.draw_apple = False
self.x_apple = 0
self.y_apple = 0
self.rect = QRect(self.x_apple, self.y_apple, self.SquareWidth, self.SquareHeight)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
print "Paint Event?"
if self.draw_apple == True:
print "Draw"
self.apple_color = QtCore.Qt.red
else:
print "Do not draw"
self.apple_color = self.bkg_color
painter.setPen(self.apple_color)
painter.drawRect(self.rect)
def drawApple(self):
print "Enters drawApple"
self.x_apple = np.random.randint(0, math.floor(self.BoardWidth/self.SquareWidth)) * self.SquareWidth
self.y_apple = np.random.randint(0, math.floor(self.BoardHeight/self.SquareHeight)) * self.SquareHeight
self.draw_apple == True
def eraseApple(self):
print "Enters eraseApple"
self.draw_apple == True
def main():
app = QtGui.QApplication([])
game = Game()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You should call the update() function as it calls paintEvent(). Also I recommend using a single timer for that task. You only have to deny the variable draw_apple to change state.
import sys, random
import numpy as np
import math
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QTimer, QRect
from PyQt4.QtGui import QPaintEvent
class Game(QtGui.QMainWindow):
def __init__(self):
super(Game, self).__init__()
self.initUI()
def initUI(self):
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Background, QtCore.Qt.white)
self.setPalette(palette)
self.tboard = Board(self)
self.setCentralWidget(self.tboard)
self.resize(400, 400)
self.center()
self.setWindowTitle('Game')
self.show()
def center(self):
screen = QtGui.QDesktopWidget().screenGeometry()
size = self.geometry()
self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
class Board(QtGui.QFrame):
BoardWidth = 400
BoardHeight = 400
SquareWidth = 15
SquareHeight = 15
Speed = 10000
def __init__(self, parent):
super(Board, self).__init__(parent)
#self.setAutoFillBackground(True)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.timer_draw = QtCore.QTimer(self)
self.timer_draw.timeout.connect(self.drawApple)
self.timer_draw.start(self.Speed)
self.apple_color = QtCore.Qt.red
self.draw_apple = False
self.x_apple = 0
self.y_apple = 0
self.drawApple()
def paintEvent(self, event):
painter = QtGui.QPainter(self)
print "Paint Event?"
if self.draw_apple == True:
print "Draw"
self.apple_color = QtCore.Qt.red
else:
print "Do not draw"
self.apple_color = QtCore.Qt.white
painter.setPen(self.apple_color)
painter.drawRect(self.rect)
def drawApple(self):
self.draw_apple = not self.draw_apple
self.x_apple = np.random.randint(0, math.floor(self.BoardWidth/self.SquareWidth)) * self.SquareWidth
self.y_apple = np.random.randint(0, math.floor(self.BoardHeight/self.SquareHeight)) * self.SquareHeight
self.rect = QRect(self.x_apple, self.y_apple, self.SquareWidth, self.SquareHeight)
self.update()
def main():
app = QtGui.QApplication([])
game = Game()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Related
I have a problem using simpledialog.askstring from tkinter, it opens two pop up windows, one of them is the regular one to input a value, but the other is a blank window that freezes completely and you have to force the cloosure of the window, enter image description hereas shown in the image in the link. I'm using spyder.
What could be happening?
This is what I have so far:
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QApplication, QMainWindow, QComboBox,
QLabel, QPushButton, QGroupBox
import tkinter as tk
from tkinter import simpledialog
from PIL import ImageGrab
import sys
import cv2
import numpy as np
# import imageToString
import pyperclip
import webbrowser
import pytesseract
pytesseract.pytesseract.tesseract_cmd =
r"C:\Users\amc\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
class Communicate(QObject):
snip_saved = pyqtSignal()
class MyWindow(QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__()
self.win_width = 340
self.win_height = 200
self.setGeometry(50, 50, self.win_width, self.win_height)
self.setWindowTitle("PSD Generator")
self.initUI()
def initUI(self):
#Define buttons
self.searchOpen = QPushButton(self)
self.searchOpen.setText("Digitilize Graph")
self.searchOpen.move(10,75)
self.searchOpen.setFixedSize(150,40)
self.searchOpen.clicked.connect(self.snip_graph_clicked)
self.copyPartNum = QPushButton(self)
self.copyPartNum.setText("Snip Table")
self.copyPartNum.move((self.win_width/2)+10, 75)
self.copyPartNum.setFixedSize(150,40)
self.copyPartNum.clicked.connect(self.snip_table_clicked)
self.notificationBox = QGroupBox("Notification Box", self)
self.notificationBox.move(10,135)
self.notificationBox.setFixedSize(self.win_width-20,55)
self.notificationText = QLabel(self)
self.notificationText.move(20, 145)
self.reset_notif_text()
def snip_graph_clicked(self):
self.snipWin = SnipWidget(False, True, self)
self.snipWin.notification_signal.connect(self.reset_notif_text)
self.snipWin.show()
self.notificationText.setText("Snipping... Press ESC to quit snipping")
self.update_notif()
def snip_table_clicked(self):
self.snipWin = SnipWidget(True, False, self)
self.snipWin.notification_signal.connect(self.reset_notif_text)
self.snipWin.show()
self.notificationText.setText("Snipping... Press ESC to quit snipping")
self.update_notif()
def reset_notif_text(self):
self.notificationText.setText("Idle...")
self.update_notif()
def define_notif_text(self, msg):
print('notification was sent')
self.notificationText.setText('notification was sent')
self.update_notif()
def update_notif(self):
self.notificationText.move(20, 155)
self.notificationText.adjustSize()
class SnipWidget(QMainWindow):
notification_signal = pyqtSignal()
def __init__(self, copy_table, scan_graph, parent):
super(SnipWidget, self).__init__()
self.copy_table = copy_table
self.scan_graph = scan_graph
root = tk.Tk()# instantiates window
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
self.setGeometry(0, 0, screen_width, screen_height)
self.setWindowTitle(' ')
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.setWindowOpacity(0.3)
self.is_snipping = False
QtWidgets.QApplication.setOverrideCursor(
QtGui.QCursor(QtCore.Qt.CrossCursor)
)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.c = Communicate()
self.show()
if self.copy_table == True:
# the input dialog
BH_Ref = simpledialog.askstring(title="New PSD",prompt="Borehole Number Ref:")
Depth = simpledialog.askstring(title="New PSD",prompt="Sample depth (m):")
self.c.snip_saved.connect(self.searchAndOpen)
if self.scan_graph == True:
# the input dialog
BH_Ref = simpledialog.askstring(title="New PSD",prompt="Borehole Number Ref:")
Depth = simpledialog.askstring(title="New PSD",prompt="Sample depth (m):")
self.c.snip_saved.connect(self.IdAndCopy)
def paintEvent(self, event):
if self.is_snipping:
brush_color = (0, 0, 0, 0)
lw = 0
opacity = 0
else:
brush_color = (128, 128, 255, 128)
lw = 3
opacity = 0.3
self.setWindowOpacity(opacity)
qp = QtGui.QPainter(self)
qp.setPen(QtGui.QPen(QtGui.QColor('black'), lw))
qp.setBrush(QtGui.QColor(*brush_color))
qp.drawRect(QtCore.QRect(self.begin, self.end))
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
print('Quit')
QtWidgets.QApplication.restoreOverrideCursor();
self.notification_signal.emit()
self.close()
event.accept()
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = self.begin
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
x1 = min(self.begin.x(), self.end.x())
y1 = min(self.begin.y(), self.end.y())
x2 = max(self.begin.x(), self.end.x())
y2 = max(self.begin.y(), self.end.y())
self.is_snipping = True
self.repaint()
QtWidgets.QApplication.processEvents()
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
self.is_snipping = False
self.repaint()
QtWidgets.QApplication.processEvents()
img = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2GRAY)
self.snipped_image = img
QtWidgets.QApplication.restoreOverrideCursor();
self.c.snip_saved.emit()
self.close()
self.msg = 'snip complete'
self.notification_signal.emit()
def searchAndOpen(self):
img_str = self.imgToStr(self.snipped_image)
msg_str = f'Text in snip is {img_str}'
def IdAndCopy(self):
img_str = self.imgToStr(self.snipped_image)
pyperclip.copy(img_str)
def find_str(self, image_data):
img = image_data
h,w = np.shape(img)
asp_ratio = float(w/h)
img_width = 500
img_height = int(round(img_width/asp_ratio))
desired_image_size = (img_width,img_height)
img_resized = cv2.resize(img, desired_image_size)
imgstr = str(pytesseract.image_to_string(img_resized))
print(imgstr)
return imgstr
def imgToStr(self, image):
# img_str = imageToString.main(image)
img_str = self.find_str(image)
return img_str
def window():
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec_())
window()
So I want to make an animation as the arrow from the Waze app, I want that it moves smoothly and constant. I don't know how to do it inside the QtGraphicsView. My object(arrow) moves by an QVariantAnimation, Which interpolates from the current position until the next position. End it slightly stops. I don't wanna this feature (stops), I want that my animation runs continuous and smoothly. Does anyone know how?
Here is a minimum reproducible example:
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
import sys
import random
random.seed(0)
class Example(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.button = QtWidgets.QPushButton("Start", self)
self.button.clicked.connect(self.doAnim)
self.button.move(10, 10)
self.scene = QtWidgets.QGraphicsScene()
self.view = QtWidgets.QGraphicsView(self)
self.view.setScene(self.scene)
self.view.setGeometry(150, 30, 500, 800)
self.setGeometry(300, 300, 380, 300)
self.setWindowTitle('Animation')
pen = QtGui.QPen()
pen.setBrush(QtGui.QBrush(QtCore.Qt.darkBlue))
pen.setWidth(5)
self.scene.addEllipse(0,0,10,10, pen)
self.show()
self.ellipse = self.scene.items()[0]
def doAnim(self):
# Every time that I click on the start buttom this animation runs
# and stops,
pos = self.ellipse.pos()
new_pos = QtCore.QPointF(pos.x()+ random.randint(-10, 10), pos.y() +random.randint(-10, 10))
self.anim = QtCore.QVariantAnimation()
self.anim.setDuration(1000)
self.anim.setStartValue(pos)
self.anim.setEndValue(new_pos)
self.anim.setLoopCount(-1)
self.anim.valueChanged.connect(self.ellipse.setPos)
self.anim.start(QtCore.QVariantAnimation.DeleteWhenStopped)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
The simple solution is to connect to the finished signal of the animation, and set again the start/end values if a new target position is available.
from random import randrange
from PyQt5 import QtCore, QtGui, QtWidgets
class Example(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QGridLayout(self)
self.startButton = QtWidgets.QPushButton("Start")
layout.addWidget(self.startButton)
self.addPointButton = QtWidgets.QPushButton("Add target point")
layout.addWidget(self.addPointButton, 0, 1)
self.view = QtWidgets.QGraphicsView()
layout.addWidget(self.view, 1, 0, 1, 2)
self.scene = QtWidgets.QGraphicsScene()
self.view.setScene(self.scene)
self.scene.setSceneRect(-10, -10, 640, 480)
pen = QtGui.QPen(QtCore.Qt.darkBlue, 5)
self.ellipse = self.scene.addEllipse(0, 0, 10, 10, pen)
self.queue = []
self.startButton.clicked.connect(self.begin)
self.addPointButton.clicked.connect(self.addPoint)
self.anim = QtCore.QVariantAnimation()
self.anim.setDuration(1000)
self.anim.valueChanged.connect(self.ellipse.setPos)
self.anim.setStartValue(self.ellipse.pos())
self.anim.finished.connect(self.checkPoint)
def begin(self):
self.startButton.setEnabled(False)
self.addPoint()
def addPoint(self):
self.queue.append(QtCore.QPointF(randrange(600), randrange(400)))
self.checkPoint()
def checkPoint(self):
if not self.anim.state() and self.queue:
if self.anim.currentValue():
# a valid currentValue is only returned when the animation has
# been started at least once
self.anim.setStartValue(self.anim.currentValue())
self.anim.setEndValue(self.queue.pop(0))
self.anim.start()
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
import sys
import random
import queue
import time
class Position(queue.Queue):
def __init__(self, *args, **kwargs):
super(Position, self).__init__(*args, **kwargs)
class Worker(QtCore.QThread):
pos_signal = QtCore.pyqtSignal(QtCore.QPointF)
def __init__(self, rect, parent=None, *args, **kwargs):
super().__init__(parent)
random.seed(0)
self.pos = QtCore.QPointF(0, 0)
self.rect: QtCore.QRectF = rect
def run(self) -> None:
new_pos = QtCore.QPointF(self.pos.x()+ random.randint(-100, 100), self.pos.y() +random.randint(-100, 100))
if not self.rect.contains(new_pos):
self.run()
else:
self.pos = new_pos
self.pos_signal.emit(new_pos)
time.sleep(0.1)
self.run()
class Example(QtWidgets.QWidget):
next_signal = QtCore.pyqtSignal()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.button = QtWidgets.QPushButton("Start", self)
self.button.clicked.connect(self.doAnim)
self.scene = QtWidgets.QGraphicsScene()
self.view = QtWidgets.QGraphicsView(self)
self.view.setScene(self.scene)
self.view.setGeometry(100, 100, 500, 800)
self.setGeometry(300, 300, 800, 800)
pen = QtGui.QPen()
pen.setBrush(QtGui.QBrush(QtCore.Qt.darkBlue))
pen.setWidth(5)
self.scene.addEllipse(0,0,20,10, pen)
self.ellipse = self.scene.items()[0]
self.rect = QtCore.QRectF(0,0, 200, 200)
self.scene.addRect(self.rect, pen)
self.positions = Position()
self.producer = Worker(rect=self.rect)
self.producer.pos_signal.connect(self.positions.put)
self.producer.start()
self.old = QtCore.QPointF(0, 0)
self.new = None
def ready(self):
self.next_signal.emit()
self.old = self.new
self.doAnim()
def doAnim(self):
# Every time that I click on the start buttom this animation runs
# and stops,
self.sequential_animation = QtCore.QSequentialAnimationGroup(self)
self.new = self.positions.get()
self.anim = QtCore.QVariantAnimation()
self.anim.setDuration(1000)
self.anim.setStartValue(self.old)
self.anim.setEndValue(self.new)
self.anim.valueChanged.connect(self.ellipse.setPos)
self.anim.finished.connect(self.ready)
self.sequential_animation.addAnimation(self.anim)
self.sequential_animation.start(QtCore.QSequentialAnimationGroup.DeleteWhenStopped)
# self.anim.start(QtCore.QVariantAnimation.DeleteWhenStopped)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
This is my code. It simulate a signal that i get from a oscilloscope. I'm trying to create a interface, but i am new at coding (and english), and i got some problems.
i already create a real time plot graph and a button,but when clicked, the signal stop to update and i just get the same signal over and over again. I just need to know how to keeping updating the signal while i'm in the loop, if it is possible.
import pyqtgraph as pg
import numpy as np
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QThread, pyqtSignal
class plotarT(QThread):
signal = pyqtSignal(object)
def __init__(self):
QThread.__init__(self)
self.phase = 0
def __del__(self):
self.wait()
def update(self):
self.t = np.arange(0, 3.0, 0.01)
self.s = np.sin(2 * np.pi * self.t + self.phase) #sin function
self.phase += 0.1
QThread.msleep(2500) #To simulate the time that oscilloscope take to respond
def run(self):
while True:
self.update()
self.signal.emit(self.s) #this emit the vectors
class Window(QDialog):
def __init__(self):
self.app = QtGui.QApplication(sys.argv)
super().__init__()
self.title = "PyQt5 GridLayout"
self.top = 100
self.left = 100
self.width = 1000
self.height = 600
self.InitWindow()
self.traces = dict()
pg.setConfigOptions(antialias=True)
def InitWindow(self):
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
self.gridLayoutCreation()
vboxLayout = QVBoxLayout()
vboxLayout.addWidget(self.groupBox)
self.setLayout(vboxLayout)
self.show()
def gridLayoutCreation(self): #my interface
self.groupBox = QGroupBox("Grid Layout Example")
gridLayout = QGridLayout()
self.guiplot = pg.PlotWidget()
gridLayout.addWidget(self.guiplot,0,8,8,12)
BtnL = QPushButton('Test')
gridLayout.addWidget(BtnL, 0, 1)
self.tlg = QLineEdit('')
gridLayout.addWidget(self.tlg, 1,1)
self.groupBox.setLayout(gridLayout)
BtnL.clicked.connect(self.get_data)
def get_data(self):
raw1 = []
raw2 = []
for i in range(2): #the signal does not update while running the loop
raw1.append(self.s)
time.sleep(1)
print(self.s)
def plotar(self,s): #here i plot the vector
self.s = s
self.guiplot.clear()
self.guiplot.plot(s)
def teste(self):
self.get_thread = plotarT()
self.get_thread.signal.connect(self.plotar) #connect to function
self.get_thread.start()
def main():
app = QtGui.QApplication(sys.argv)
form = Window()
form.show()
form.teste()
app.exec_()
if __name__ == '__main__': #Run my aplicattion
main()
Try it:
import pyqtgraph as pg
import numpy as np
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QThread, pyqtSignal, QTimer # + QTimer
class plotarT(QThread):
signal = pyqtSignal(object)
def __init__(self):
QThread.__init__(self)
self.phase = 0
def __del__(self):
self.wait()
def update(self):
self.t = np.arange(0, 3.0, 0.01)
self.s = np.sin(2 * np.pi * self.t + self.phase) #sin function
self.phase += 0.1
QThread.msleep(500) # 500
def run(self):
while True:
self.update()
self.signal.emit(self.s) #this emit the vectors
class Window(QDialog):
def __init__(self):
self.app = QtGui.QApplication(sys.argv)
super().__init__()
self.title = "PyQt5 GridLayout"
self.top = 100
self.left = 100
self.width = 1000
self.height = 600
self.InitWindow()
self.traces = dict()
pg.setConfigOptions(antialias=True)
self.timer = QTimer(self, timeout=self.pipe_output, interval=1000) # +++
def InitWindow(self):
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
self.gridLayoutCreation()
vboxLayout = QVBoxLayout()
vboxLayout.addWidget(self.groupBox)
self.setLayout(vboxLayout)
self.show()
def gridLayoutCreation(self): #my interface
self.groupBox = QGroupBox("Grid Layout Example")
gridLayout = QGridLayout()
self.guiplot = pg.PlotWidget()
gridLayout.addWidget(self.guiplot,0,8,8,12)
BtnL = QPushButton('Test')
gridLayout.addWidget(BtnL, 0, 1)
self.tlg = QLineEdit('')
gridLayout.addWidget(self.tlg, 1,1)
self.groupBox.setLayout(gridLayout)
BtnL.clicked.connect(self.get_data)
def get_data(self):
# raw1 = []
# raw2 = []
# for i in range(2): #the signal does not update while running the loop
# raw1.append(self.s)
# time.sleep(1)
# print(self.s)
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
self.timer.start()
self.raw1 = []
self.raw2 = []
self.i = 0
def pipe_output(self):
self.i += 1
self.raw1.append(self.s)
print("\n ----------- \n", self.s)
if self.i == 2:
self.timer.stop()
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def plotar(self, s): # here i plot the vector
print("def plotar(self, s):", type(s))
self.s = s
self.guiplot.clear()
self.guiplot.plot(self.s) #(s)
def teste(self):
self.get_thread = plotarT()
self.get_thread.signal.connect(self.plotar) #connect to function
self.get_thread.start()
def main():
app = QtGui.QApplication(sys.argv)
form = Window()
form.show()
form.teste()
app.exec_()
if __name__ == '__main__': #Run my aplicattion
main()
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_())
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_())
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_())
Trying to draw arc and problem is I want to cal draw function form another py file and no luck so far (if draw function in main py file it is ok). I imported another py file but nothing happens. here is the code:
main.py
from PyQt4 import QtGui, Qt, QtCore
import sys
from src.cPrg import cPrg
from PyQt4.Qt import QPen
class mainWindow(QtGui.QWidget):
def __init__(self):
super(mainWindow, self).__init__()
self.otherFile = cPrg()
self.initUI()
def initUI(self):
#self.exitBtn = QtGui.QPushButton('Exit', self)
#self.exitBtn.setGeometry(100,100,60,40)
#self.exitBtn.clicked.connect(self.close_app)
self.label = QtGui.QLabel(self)
self.label.setText(self.otherFile.textas)
self.label.setGeometry(100,140, 60, 40)
self.otherFile.setGeometry(20,20, 20,20)
self.otherFile.startA = 270
self.otherFile.endA = -270
#self.showFullScreen()
self.setGeometry(100, 100, 800, 480)
self.setWindowTitle('Window Title')
self.show()
def close_app(self):
sys.exit()
def main():
app = QtGui.QApplication(sys.argv)
gui = mainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
and anotherfile.py
from PyQt4 import QtGui, QtCore, Qt
from PyQt4.Qt import QPen
class cPrg(QtGui.QWidget):
def __init__(self):
super(cPrg, self).__init__()
self.startA = 0
self.endA = 0
self.textas = 'bandom'
def paintEvent(self, e):
painter = QtGui.QPainter(self)
painter.setRenderHint(painter.Antialiasing)
rect = e.rect
r = QtCore.QRect(200,200,20,20) #<-- create rectangle
size = r.size() #<-- get rectangle size
r.setSize(size*10) #<-- set size
startAngle = self.startA*16 #<-- set start angle to draw arc
endAngle = self.endA*16 #<-- set end arc angle
painter.setPen(QPen(QtGui.QColor('#000000'))) #<-- arc color
#painter.setBrush(QtCore.Qt.HorPattern)
painter.drawArc(r, startAngle, endAngle) #<-- draw arc
painter.end()
super(cPrg,self).paintEvent(e)
What I doing wrong and how can I change line width?
Thank you
EDIT: all painting I made in main py file, here is the code:
from PyQt4 import QtGui, Qt, QtCore
import sys
from src.cprg import cPrg
from src.cprogress import GaugeWidget
from PyQt4.Qt import QPen
class mainWindow(QtGui.QWidget):
def __init__(self):
self.otherFile = cPrg()
self.gauge = GaugeWidget()
self.i = 0
self.lineWidth = 3
self._value = 0
self.completed = 0
super(mainWindow, self).__init__()
self.initUI()
def initUI(self):
self.setValue(.5)
#self.showFullScreen()
self.setGeometry(100, 100, 800, 480)
self.setWindowTitle('Window Title')
self.show()
def close_app(self):
sys.exit()
def setValue(self, val):
val = float(min(max(val, 0), 1))
self._value = -270 * val
self.update()
def setLineWidth(self, lineWidth):
self.lineWidth = lineWidth
def paintEvent(self, e):
painter = QtGui.QPainter(self)
painter.setRenderHint(painter.Antialiasing)
rect = e.rect
outerRadius = min(self.width(),self.height())
#arc line
r = QtCore.QRect(20,20,outerRadius-10,outerRadius-10) #<-- create rectangle
size = r.size() #<-- get rectangle size
r.setSize(size*.4) #<-- set size
startAngle = 270*16 #<-- set start angle to draw arc
endAngle = -270*16 #<-- set end arc angle
painter.setPen(QPen(QtGui.QColor('#000000'), self.lineWidth)) #<-- arc color
#painter.setBrush(QtCore.Qt.HorPattern)
painter.drawArc(r, startAngle, endAngle) #<-- draw arc
#arc prg
painter.save()
painter.setPen(QPen(QtGui.QColor('#ffffff'), 20))
painter.drawArc(r, startAngle, self._value*16)
painter.restore()
painter.end()
super(mainWindow,self).paintEvent(e)
def main():
app = QtGui.QApplication(sys.argv)
gui = mainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
this is my simple circular progress bar, now question is how can I place setValue, setlineWidth and paintEvent functions into separate py file and then just call by importing this file and class with these functions? I tried this:
from PyQt4 import QtGui, Qt, QtCore
import sys
from src.cprg import cPrg #<import progressbar
from src.cprogress import GaugeWidget
from PyQt4.Qt import QPen
class mainWindow(QtGui.QWidget):
def __init__(self):
self.otherFile = cPrg() #< imported progress bar
self.gauge = GaugeWidget()
self.i = 0
self.lineWidth = 3
self._value = 0
self.completed = 0
super(mainWindow, self).__init__()
self.initUI()
def initUI(self):
self.otherFile.setGeometry(10,10,100,100) #<<<< progress bar size
self.otherFile.setValue(0.5) #< progress bar value
and this is not working.
Change line width with QPen(color, line_width), update() redraw with paintEvent.
try with this:
from PyQt4 import QtGui, QtCore
class cPrg:
def __init__(self):
self.linewidth = 0
def setLineWidth(self, linewidth):
self.linewidth = linewidth
def drawArc(self, painter):
painter.setRenderHint(painter.Antialiasing)
r = QtCore.QRect(200,200,20,20) #<-- create rectangle
size = r.size() #<-- get rectangle size
r.setSize(size*10) #<-- set size
startAngle = self.startA*16 #<-- set start angle to draw arc
endAngle = self.endA*16 #<-- set end arc angle
painter.setPen(QtGui.QPen(QtGui.QColor('#000000'), self.linewidth)) #<-- arc color
painter.drawArc(r, startAngle, endAngle) #<-- draw arc
class mainWindow(QtGui.QWidget):
def __init__(self):
super(mainWindow, self).__init__()
self.otherFile = cPrg()
self.initUI()
self.i = 0
def initUI(self):
self.label = QtGui.QLabel(self)
self.label.setText(self.otherFile.textas)
self.label.setGeometry(100,140, 60, 40)
self.otherFile.startA = 270
self.otherFile.endA = -270
self.setGeometry(100, 100, 800, 480)
self.setWindowTitle('Window Title')
timer = QtCore.QTimer(self)
timer.timeout.connect(self.changeLineWidth)
timer.start(1000)
def changeLineWidth(self):
self.otherFile.setLineWidth(self.i)
self.i += 1
self.i %= 60
self.update()
def paintEvent(self, e):
painter = QtGui.QPainter(self)
self.otherFile.drawArc(painter)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = mainWindow()
w.show()
sys.exit(app.exec_())
If you want a circular progressbar, your must be override QProgressbar:
from math import ceil
from PyQt4 import QtGui, Qt, QtCore
import sys
class cPrg(QtGui.QProgressBar):
def __init__(self, parent=None):
super(cPrg, self).__init__(parent)
self.linewidth = 1
def factor(self, value):
a = 360 / (self.maximum() - self.minimum())
b = -a / (self.maximum() - self.minimum())
return a*value + b
def setLineWidth(self, linewidth):
self.linewidth = linewidth
self.update()
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(painter.Antialiasing)
r = self.rect()
val = ceil(self.factor(self.value()))
nr = QtCore.QRect(r.topLeft() + QtCore.QPoint(self.linewidth, self.linewidth),
QtCore.QSize(r.width()-2*self.linewidth, r.height()-2*self.linewidth))
painter.setPen(QtGui.QPen(QtGui.QColor('#000000'), self.linewidth))
painter.drawArc(nr, 0*16, val*16)
class mainWindow(QtGui.QWidget):
def __init__(self):
super(mainWindow, self).__init__()
self.otherFile = cPrg(self)
self.otherFile.setMinimum(0)
self.otherFile.setMaximum(360)
self.otherFile.setValue(90)
self.initUI()
timerLW = QtCore.QTimer(self)
timerLW.timeout.connect(self.changeLW)
timerLW.start(100)
timerVal = QtCore.QTimer(self)
timerVal.timeout.connect(self.updateValue)
timerVal.start(100)
def initUI(self):
self.label = QtGui.QLabel(self)
self.label.setText("test")
self.label.setGeometry(200, 200, 60, 40)
self.otherFile.setGeometry(0, 0, 200, 200)
self.setGeometry(0, 0, 800, 480)
self.setWindowTitle('Window Title')
def changeLW(self):
lw = (self.otherFile.linewidth + 1) % 20
self.otherFile.setLineWidth(lw)
def updateValue(self):
self.otherFile.setValue(self.otherFile.value() + 1)
def main():
app = QtGui.QApplication(sys.argv)
gui = mainWindow()
gui.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()