pyqt4 drawing arc from other py file - python

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

Related

How to make a constant and smooth animation?

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

How do I stop the small spinning circles along the scanning line in QPainter?

I'm trying to rotate a line in a circle like clock's second arm. When rotating the line, I also want to draw small circles here and there inside the circle. The problem is that the small circles I drew is rotating along the line. I want these circles stay at their location and move with my code. Can someone help me?
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2.QtOpenGL import *
from OpenGL import GL
class Helper:
def __init__(self):
gradient = QLinearGradient(QPointF(50, -20), QPointF(80, 20))
gradient.setColorAt(0.0, Qt.green)
gradient.setColorAt(1.0, Qt.blue)
self.background = QBrush(QColor(0, 0, 0))
self.circlePen = QPen(Qt.green)
self.circlePen.setWidth(2)
self.textPen = QPen(Qt.green,8,Qt.SolidLine)
self.textFont = QFont()
self.textFont.setPixelSize(100)
def paint(self, painter, event, elapsed):
painter.fillRect(event.rect(), self.background)
painter.setPen(self.circlePen)
painter.translate(400, 400)
painter.drawEllipse(-250,-250,500,500)
painter.rotate(elapsed * 0.35)
painter.setBrush(QColor(Qt.green))
dx = 100
dy = 100
for i in range(10):
painter.drawEllipse(dx,dy,8,8)
dx += 10
dy += 10
painter.save()
painter.drawLine(0,-250,0,0)
painter.restore()
class GLWidget(QGLWidget):
def __init__(self, helper, parent = None):
QGLWidget.__init__(self, QGLFormat(QGL.SampleBuffers), parent)
self.helper = helper
self.elapsed = 0
self.setFixedSize(800, 800)
def animate(self):
self.elapsed = (self.elapsed + self.sender().interval()) % 1000
self.repaint()
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
self.helper.paint(painter, event, self.elapsed)
painter.end()
class Window(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
helper = Helper()
openGL = GLWidget(helper, self)
openGLLabel = QLabel(self.tr("OpenGL"))
openGLLabel.setAlignment(Qt.AlignHCenter)
layout = QGridLayout()
layout.addWidget(openGL, 100, 100)
layout.addWidget(openGLLabel, 1, 0)
self.setLayout(layout)
timer = QTimer(self)
self.connect(timer, SIGNAL("timeout()"), openGL.animate)
timer.start(1)
self.setWindowTitle(self.tr("2D Painting on Native and OpenGL Widgets"))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
small green circles are rotating with line
small green circles are rotating with line
1: The results of above code
The result I have
The result I want like this

PySide/PyQT5: How to emit signals from a QGraphicsItem?

I want to emit a signal from a QGraphicsItem when it is doubled-clicked, in order to change a widget in the main window. The graphics-scene/-item does not provide an emit() method, but I was just wondering if there is an alternate way to do this. The code below has a function within a QGraphicsView class that will print to the terminal when an item is double-clicked. How can I make that into a slot/signal instead (if QGraphicsItem does not support signal/slots)?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
def __init__( self, parent = None ):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
pen = QPen(QColor(Qt.green))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(0, 0, 45, 45, pen, brush)
item.setPos(0,0)
def mouseDoubleClickEvent(self, event):
print("Circle Clicked!")
# this double click event prints to terminal but how to setup
# signal/slot to update the QWidget QLabel text instead?
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel("Double Click Green Circle (Howto change this QWidget Label with signals?)")
bottom = MyFrame()
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Below is a simple example showing one way to emit signals from a graphics-item. This defines a custom signal on a subclass of QGraphicsScene and then uses the scene() method of graphics-items to emit it:
import sys
from PySide import QtCore, QtGui
class GraphicsScene(QtGui.QGraphicsScene):
itemDoubleClicked = QtCore.Signal(object)
class GraphicsRectangle(QtGui.QGraphicsRectItem):
def mouseDoubleClickEvent(self, event):
self.scene().itemDoubleClicked.emit(self)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = QtGui.QGraphicsView()
self.scene = GraphicsScene(self)
self.view.setScene(self.scene)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
for i in range(1, 4):
self.scene.addItem(GraphicsRectangle(50 * i, 50 * i, 20, 20))
self.scene.itemDoubleClicked.connect(self.handleItemDoubleClicked)
def handleItemDoubleClicked(self, item):
print(item.boundingRect())
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
UPDATE:
Below is a an example based on the code in your question. The basic idea is the same: define a custom signal on an available QObject (the graphics-view in this case), and use that to emit the double-click notification.
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
itemDoubleClicked = Signal(object)
def __init__(self, parent=None):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
for i, color in enumerate('red blue green'.split()):
pen = QPen(QColor(color))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(i * 50, i * 50, 45, 45, pen, brush)
item.setData(0, color.upper())
def mouseDoubleClickEvent(self, event):
item = self.itemAt(event.pos())
if item is not None:
self.itemDoubleClicked.emit(item)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel('Double Click a Circle')
bottom = MyFrame()
bottom.itemDoubleClicked.connect(
lambda item, top=top:
top.setText('Double Clicked: %s' % item.data(0)))
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

PyQt4: Use QVariantAnimation to animate between two values

I have a custom progress bar that I would like to animate as it changes from one value to another. When I get a value, I repaint the rectangle which represents the progress bar - so I think this should be as simple as animating the value itself and redrawing on each change. I've been looking through the Animation Framework documentation and I"m pretty sure subclassing a QVariantAnimation will do what I need - but there are little to no Python examples that I can find, and I'm a bit lost.
Here's where I've got so far (please excuse me if this is way off):
import sys
from PyQt4 import QtGui, QtCore
class AnimateBetweenNums(QtCore.QVariantAnimation):
def __init__(self):
QtCore.QVariantAnimation.__init__(self)
def updateCurrentValue(self, value):
print value.toString()
class MyProgressbar(QtGui.QWidget):
def __init__(self):
super(MyProgressbar, self).__init__()
self.initUI()
def initUI(self):
self.setMinimumSize(2, 2)
self.value = 50
def setValue(self, value):
oldValue = 10
newValue = 70
anim = AnimateBetweenNums()
anim.setStartValue(oldValue)
anim.setEndValue(newValue)
anim.setDuration(1000)
anim.start()
anim.valueChanged.connect(self.updateValue)
def updateValue(self, value):
self.value = value
self.repaint()
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
self.drawWidget(qp)
qp.end()
def drawWidget(self, qp):
size = self.size()
w = size.width()
h = size.height()
till = int(((w / 100.0) * self.value))
#the bar
qp.setPen(QtGui.QColor(255, 255, 255))
qp.setBrush(QtGui.QColor(0, 228, 47))
qp.drawRect(0, 0, till, h)
#the box
pen = QtGui.QPen(QtGui.QColor(75,80,100), 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(QtCore.Qt.NoBrush)
qp.drawRect(0, 0, w - 1, h - 1)
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QtGui.QVBoxLayout()
self.button10 = QtGui.QPushButton("10")
hbox.addWidget(self.button10)
self.button70 = QtGui.QPushButton("70")
hbox.addWidget(self.button70)
self.progress = MyProgressbar()
hbox.addWidget(self.progress)
self.setLayout(hbox)
self.setGeometry(300, 300, 390, 210)
self.show()
self.button10.clicked.connect(self.changeValue10)
self.button70.clicked.connect(self.changeValue70)
def changeValue10(self, value):
self.progress.setValue(10)
self.progress.repaint()
def changeValue70(self, value):
self.progress.setValue(70)
self.progress.repaint()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Below is a re-written version of your script that hopefully does what you intended. The animation object should only be created once, and because you are using Python 2 with PyQt4, you need to make sure any QVariant values are converted correctly. I also changed the setValue() method so that it restarts from the previous value.
import sys
from PyQt4 import QtGui, QtCore
class AnimateBetweenNums(QtCore.QVariantAnimation):
def __init__(self):
QtCore.QVariantAnimation.__init__(self)
def updateCurrentValue(self, value):
print value.toString()
class MyProgressbar(QtGui.QWidget):
def __init__(self):
super(MyProgressbar, self).__init__()
self.initUI()
def initUI(self):
self.setMinimumSize(2, 2)
self.anim = AnimateBetweenNums()
self.anim.setDuration(1000)
self.anim.valueChanged.connect(self.updateValue)
self.value = 50
def setValue(self, value):
self.anim.setStartValue(self.value)
self.anim.setEndValue(value)
self.anim.start()
def updateValue(self, value):
self.value = QtCore.QVariant(value).toInt()[0]
self.repaint()
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
self.drawWidget(qp)
qp.end()
def drawWidget(self, qp):
size = self.size()
w = size.width()
h = size.height()
till = int(((w / 100.0) * self.value))
#the bar
qp.setPen(QtGui.QColor(255, 255, 255))
qp.setBrush(QtGui.QColor(0, 228, 47))
qp.drawRect(0, 0, till, h)
#the box
pen = QtGui.QPen(QtGui.QColor(75,80,100), 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setBrush(QtCore.Qt.NoBrush)
qp.drawRect(0, 0, w - 1, h - 1)
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QtGui.QVBoxLayout()
self.button10 = QtGui.QPushButton("10")
hbox.addWidget(self.button10)
self.button70 = QtGui.QPushButton("70")
hbox.addWidget(self.button70)
self.progress = MyProgressbar()
hbox.addWidget(self.progress)
self.setLayout(hbox)
self.setGeometry(300, 300, 390, 210)
self.show()
self.button10.clicked.connect(self.changeValue10)
self.button70.clicked.connect(self.changeValue70)
def changeValue10(self, value):
self.progress.setValue(10)
def changeValue70(self, value):
self.progress.setValue(70)
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Make a rectangle blink in PyQt

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

Categories

Resources