I have a QFrame on my QWidget and after clicking QPushButton my
QFrame animates from (QRect(0, 0, 100, 100)) to (QRect(600, 500, 100,
100))
Question is: I want to know QFrame every x and y
position when it is animating
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(600, 500, 100, 100))
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
When an animation is running, it will trigger the signal valueChanged each time the animated value has changed:
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.valueChanged.connect(lambda: print(self.frame.pos()))
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(600, 500, 100, 100))
self.anim.start()
Related
This code implements the ability to move objects with the mouse by using the QGraphicsItem.ItemIsMovable flag. But how to make objects move with a snap to a grid?
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsScene, QGraphicsView, QGraphicsItem
from PyQt5.QtGui import QPen, QBrush
from PyQt5.Qt import Qt
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "PyQt5 QGraphicView"
self.top = 200
self.left = 500
self.width = 600
self.height = 500
self.InitWindow()
def InitWindow(self):
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.createGraphicView()
self.show()
def createGraphicView(self):
self.scene = QGraphicsScene()
self.greenBrush = QBrush(Qt.green)
self.grayBrush = QBrush(Qt.gray)
self.pen = QPen(Qt.red)
graphicView = QGraphicsView(self.scene, self)
graphicView.setGeometry(0, 0, 600, 500)
self.shapes()
def shapes(self):
ellipse = self.scene.addEllipse(20, 20, 200, 200, self.pen, self.greenBrush)
rect = self.scene.addRect(-100, -100, 200, 200, self.pen, self.grayBrush)
ellipse.setFlag(QGraphicsItem.ItemIsMovable)
rect.setFlag(QGraphicsItem.ItemIsMovable)
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
I have drawn a rectangle on QWidget after clicking push button rectangle moves from "LEFT TOP CORNER" to "RIGHT TOP CORNER"
How to move rectangle:
from "LEFT TOP CORNER" to "RIGHT TOP CORNER"
and "RIGHT TOP CORNER" to "RIGHT BOTTOM CORNER"
and "RIGHT BOTTOM CORNER" to "LEFT BOTTOM CORNER"
and "LEFT BOTTOM CORNER" to "LEFT TOP CORNER"
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(1366, 0, 100, 100))
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Although using the finished signal is interesting, a more compact and scalable method is to use QSequentialAnimationGroup where you can concatenate animations that will run sequentially.
from PyQt5 import QtCore, QtGui, QtWidgets
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QtGui.QFont("Times New Roman")
font.setPixelSize(20)
self.start = QtWidgets.QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
# self.start.clicked.connect(self.doAnimation)
self.frame = QtWidgets.QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
r = self.frame.rect()
rects = []
r.moveTopLeft(self.rect().topLeft())
rects.append(QtCore.QRect(r))
r.moveTopRight(self.rect().topRight())
rects.append(QtCore.QRect(r))
r.moveBottomRight(self.rect().bottomRight())
rects.append(QtCore.QRect(r))
r.moveBottomLeft(self.rect().bottomLeft())
rects.append(QtCore.QRect(r))
r.moveTopLeft(self.rect().topLeft())
rects.append(QtCore.QRect(r))
sequential_animation = QtCore.QSequentialAnimationGroup(self, loopCount=-1)
for rect_start, rect_end in zip(rects[:-1], rects[1:]):
animation = QtCore.QPropertyAnimation(
targetObject=self.frame,
propertyName=b"geometry",
startValue=rect_start,
endValue=rect_end,
duration=1000,
)
sequential_animation.addAnimation(animation)
self.start.clicked.connect(sequential_animation.start)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Example()
sys.exit(app.exec())
You can use signal to run next animation when first is finished
self.anim.finished.connect(self.doAnimation_2)
This code moves rectangle all time - last animation starts first animation.
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation_1)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation_1(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(300, 0, 100, 100))
self.anim.finished.connect(self.doAnimation_2)
self.anim.start()
def doAnimation_2(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(300, 0, 100, 100))
self.anim.setEndValue(QRect(300, 300, 100, 100))
self.anim.finished.connect(self.doAnimation_3)
self.anim.start()
def doAnimation_3(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(300, 300, 100, 100))
self.anim.setEndValue(QRect(0, 300, 100, 100))
self.anim.finished.connect(self.doAnimation_4)
self.anim.start()
def doAnimation_4(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(0, 300, 100, 100))
self.anim.setEndValue(QRect(0, 0, 100, 100))
self.anim.finished.connect(self.doAnimation_1)
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
If you will have to run different animations in different moments then probably you could use QTimer
I can not understand how to make the QPainter() draw inside a QLabel, here is the code I told would have worked:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QColor, QBrush
class Labella(QLabel):
def __init__(self, parent):
super().__init__()
lb = QLabel('text', parent)
lb.setStyleSheet('QFrame {background-color:grey;}')
lb.resize(200, 200)
qp = QPainter(lb)
qp.begin(lb);
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(0,0,20,20);
qp.end();
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
self.drawRectangles(qp)
qp.end()
def drawRectangles(self, qp):
col = QColor(0, 0, 0)
col.setNamedColor('#040404')
qp.setPen(col)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 200, 60)
class Example(QWidget):
def __init__(self):
super().__init__()
lb = Labella(self)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Colours')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I can only find examples in C++ same as for the Qt documentation, please instruct me where I should have find the information if not here.
The documentation suggests to use QPainter inside the paintEvent.
By using the constructor like below, inside the method paintEvent, no need to call begin() and end()
(Your class Labella just miss a parameter to initialize the parent)
The method save() and restore() can be convenient to store a standard config of a QPainter, allowing to draw something different before restoring the settings.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QColor, QBrush
class Labella(QLabel):
def __init__(self, parent):
super().__init__(parent=parent)
self.setStyleSheet('QFrame {background-color:grey;}')
self.resize(200, 200)
def paintEvent(self, e):
qp = QPainter(self)
self.drawRectangles(qp)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(0,0,20,20)
def drawRectangles(self, qp):
qp.setBrush(QColor(255, 0, 0, 100))
qp.save() # save the QPainter config
qp.drawRect(10, 15, 20, 20)
qp.setBrush(QColor(0, 0, 255, 100))
qp.drawRect(50, 15, 20, 20)
qp.restore() # restore the QPainter config
qp.drawRect(100, 15, 20, 20)
class Example(QWidget):
def __init__(self):
super().__init__()
lb = Labella(self)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Colours')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I don't know why but my 2 custom widgets(SquareCalc, LinePainting) when i use them in QXBoxLayout(twoWidgets) , there are being superimposed each other one.
I'm using python 3.5.2 with PyQt5
This is my code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QPainter, QPen
from PyQt5.QtWidgets import (QApplication, QWidget,
QGridLayout, QVBoxLayout, QHBoxLayout,QLabel, QLineEdit, QPushButton)
class SquareCalc(QWidget):
def __init__(self):
super().__init__()
def initUI(self):
self.setGeometry(0,0,100,100)
self.inputLine = QLineEdit()
self.outputLine = QLineEdit()
self.outputLine.setReadOnly(True)
self.inputLine.returnPressed.connect(self.calc)
self.calcButton = QPushButton("&Calc")
self.calcButton.clicked.connect(self.calc)
lineLayout = QGridLayout()
lineLayout.addWidget(QLabel("num"), 0, 0)
lineLayout.addWidget(self.inputLine, 0, 1)
lineLayout.addWidget(QLabel("result"), 1, 0)
lineLayout.addWidget(self.outputLine, 1, 1)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.calcButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(lineLayout)
mainLayout.addLayout(buttonLayout)
self.setLayout(mainLayout)
def calc(self):
n = int(self.inputLine.text())
r = n**2
self.outputLine.setText(str(r))
class LinePainting(QWidget):
def __init__(self):
super().__init__()
def initPainting(self):
self.setGeometry(0, 0, 300, 300)
self.setWindowTitle('Pen styles')
mainLayout = QVBoxLayout()
mainLayout.addWidget(self)
self.show()
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
self.drawLines(qp)
qp.end()
def drawLines(self, qp):
pen = QPen(Qt.black, 2, Qt.SolidLine)
qp.setPen(pen)
qp.drawLine(20, 40, 250, 40)
pen.setStyle(Qt.DashLine)
qp.setPen(pen)
qp.drawLine(20, 80, 250, 80)
pen.setStyle(Qt.DashDotLine)
qp.setPen(pen)
qp.drawLine(20, 120, 250, 120)
pen.setStyle(Qt.DotLine)
qp.setPen(pen)
qp.drawLine(20, 160, 250, 160)
pen.setStyle(Qt.DashDotDotLine)
qp.setPen(pen)
qp.drawLine(20, 200, 250, 200)
pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
qp.setPen(pen)
qp.drawLine(20, 240, 250, 240)
class twoWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.widget1 = SquareCalc()
self.widget2 = LinePainting()
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.widget1)
mainLayout.addWidget(self.widget2)
self.setLayout(mainLayout)
self.setWindowTitle("Mix line/factorial")
self.widget2.initPainting()
self.widget1.initUI()
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = twoWidget()
main_window.setStyleSheet(open("lol.qss", "r").read())
main_window.show()
sys.exit(app.exec_())
I find the problem , i just need no put a fixed size to my widget SquareCalc,
just add
self.setFixedSize(sizeX,sizeY)
In replace of :
self.setGeometry(0, 0, 300, 300)
Just because QPainter no need to have a minimum size , on the contrary QLineEdit() and QPushButton(), yes
I am trying to draw a rect around the items that are selected in the scene (either via RubberBandDrag or ctrl+click for each item).
In order to do this I've subclassed QGraphicsScene and reimplemented the selectionChanged method to add a QGraphicsRectItem around the selected area, but for some reason, this method is not being called when items are selected or unselected in the scene. I've made sure that the items are in fact selectable.
Here is a minimal example of what I'm trying to do:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class DiagramScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.selRect = None
def selectionChanged(self):
area = self.selectionArea().boundingRect()
pen = QPen()
pen.setColor(Qt.black)
pen.setStyle(Qt.DashLine)
self.selRect = self.addRect(area, pen)
if __name__ == "__main__":
app = QApplication(sys.argv)
view = QGraphicsView()
view.setDragMode(QGraphicsView.RubberBandDrag)
scene = DiagramScene()
scene.setSceneRect(0, 0, 500, 500)
rect1 = scene.addRect(20, 20, 100, 50)
rect2 = scene.addRect(80, 80, 100, 50)
rect3 = scene.addRect(140, 140, 100, 50)
rect1.setFlag(QGraphicsItem.ItemIsSelectable, True)
rect2.setFlag(QGraphicsItem.ItemIsSelectable, True)
rect3.setFlag(QGraphicsItem.ItemIsSelectable, True)
view.setScene(scene)
view.show()
sys.exit(app.exec_())
selectionChanged is a signal, not a method that you have to implement. What you need to do is to connect this signal to slot and your the implementation in the slot, so whenever the signal is emitted, your code gets executed:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class DiagramScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.selRect = None
self.selectionChanged.connect(self.onSelectionChanged)
#pyqtSlot()
def onSelectionChanged(self):
area = self.selectionArea().boundingRect()
pen = QPen()
pen.setColor(Qt.black)
pen.setStyle(Qt.DashLine)
self.selRect = self.addRect(area, pen)
if __name__ == "__main__":
app = QApplication(sys.argv)
view = QGraphicsView()
view.setDragMode(QGraphicsView.RubberBandDrag)
scene = DiagramScene()
scene.setSceneRect(0, 0, 500, 500)
rect1 = scene.addRect(20, 20, 100, 50)
rect2 = scene.addRect(80, 80, 100, 50)
rect3 = scene.addRect(140, 140, 100, 50)
rect1.setFlag(QGraphicsItem.ItemIsSelectable, True)
rect2.setFlag(QGraphicsItem.ItemIsSelectable, True)
rect3.setFlag(QGraphicsItem.ItemIsSelectable, True)
view.setScene(scene)
view.show()
sys.exit(app.exec_())