I've created a small app and I'm trying to make it so that when the main window is resized (and the GraphicsView and scene are too) that the whole scene (pixmap and rectangles) scale vertically to fit completely inside the GraphicsView. I don't want a vertical scrollbar and I don't want it to scale horizontally.
I can't figure out how to scale the scene properly. I use a GraphicsScene to contain a graph and a couple vertical rectangle "markers". When I can scale the graph to fit by redrawing the pixmap and then reattach it, the z-order is wrong AND the rectangle widgets are not scaled with it.
I need to keep track of the rectangle widgets, so I can't just keep deleting and re-adding them as there's meta data along with each one.
I know about fitInView (from here: Issue with fitInView of QGraphicsView when ItemIgnoresTransformations is on) that applies to the containing GraphicsView, but I don't understand why it needs a parameter. I just want the scene to fit in the GraphicsView (vertically but not horizontally) so why doesn't GraphicsView just scale everything in the scene to fit inside it's current size? What should the parameter look like to get the scene to fit vertically?
In the resizeEvent I can redraw the pixmap and re-add, but then it covers the rectangles as the z-order is messed up. Also, it doesn't stay centered vertically in the scene and I would need to copy over the meta data.
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets
import PyQt5 as qt
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QGroupBox, QDialog, QVBoxLayout
from PyQt5.QtWidgets import QVBoxLayout, QGridLayout, QStackedWidget, QTabWidget
import numpy as np
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(GraphicsScene, self).__init__(parent)
def minimumSizeHint(self):
return QtCore.QSize(300, 200)
def dragMoveEvent(self, event):
print("dragMoveEvent", event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
#super(MainWindow).__init__()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
max_x, max_y = 2400, 700
max_x_view = 1200
self.max_x = max_x
self.max_y = max_y
self.first = True
self.setGeometry(200, 200, max_x_view, self.max_y)
self.gv = QtWidgets.QGraphicsView(self)
self.gv.setGeometry(0, 0, max_x_view, self.max_y)
self.gv2 = QtWidgets.QGraphicsView(self)
layout.addWidget(self.gv)
layout.addWidget(self.gv2)
scene = GraphicsScene()
self.scene = scene
self.gv.setScene(scene)
tab_widget = QTabWidget()
tab_widget.setTabPosition(QTabWidget.West)
widget = QWidget()
widget.setLayout(layout)
tab_widget.addTab(widget, "main")
self.setCentralWidget(tab_widget)
np.random.seed(777)
self.x_time = np.linspace(0, 12.56, 3000)
rand_data = np.random.uniform(0.0, 1.0, 3000)
self.data = .45*(np.sin(2*self.x_time) + rand_data) - .25*(np.sin(3*self.x_time))
self.first = True
pixmap_height = max_y//2 - 2*22 # 22 to take care of scrollbar height
pixmap = self.draw_graph()
pen = QtGui.QPen()
pen.setWidth(2)
pen.setColor(QtGui.QColor("red"))
self.gv1_pixmap = scene.addPixmap(pixmap)
rect = scene.sceneRect()
print("scene rect = {}".format(rect))
scene.setSceneRect(rect)
side, offset = 50, 200
for i in range(2):
r = QtCore.QRectF(QtCore.QPointF((i + 1)*offset + i * 2 * side, 2), QtCore.QSizeF(side, pixmap_height - 4))
rect_ref = scene.addRect(r, pen, QColor(255, 0, 0, 127))
rect_ref.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
all_items = scene.items()
print(all_items)
def draw_graph(self):
print("draw_graph: main Window size {}:".format(self.size()))
pixmap_height = self.height()//2 - 2*22 # 22 to take care of scrollbar height
x_final = self.x_time[-1]
data = self.data / np.max(np.abs(self.data))
data = [abs(int(k * pixmap_height)) for k in self.data]
x_pos = [int(self.x_time[i] * self.max_x / x_final) for i in range(len(data))]
pixmap = QtGui.QPixmap(self.max_x, pixmap_height)
painter = QtGui.QPainter(pixmap)
pen = QtGui.QPen()
pen.setWidth(2)
rect = pixmap.rect()
pen.setColor(QtGui.QColor("red"))
painter.drawRect(rect)
print("pixmap rect = {}".format(rect))
painter.fillRect(rect, QtGui.QColor('lightblue'))
pen.setWidth(2)
pen.setColor(QtGui.QColor("green"))
painter.setPen(pen)
for x, y in zip(x_pos, data):
painter.drawLine(x, pixmap_height, x, pixmap_height - y)
painter.end()
return pixmap
def resizeEvent(self, a0: QtGui.QResizeEvent):
#print("main Window resizeEvent")
print("main Window size {}:".format(a0.size()))
redraw = False
if redraw:
pixmap = self.draw_graph()
self.scene.removeItem(self.gv1_pixmap)
self.gv1_pixmap = self.scene.addPixmap(pixmap)
self.gv1_pixmap.moveBy(0, 30)
else:
#rect = QtCore.QRect(self.gv.startPos, self.gv.endPos)
#sceneRect = self.gv.mapToScene(rect).boundingRect()
#print 'Selected area: viewport coordinate:', rect,', scene coordinate:', sceneRect
#self.gv.fitInView(sceneRect)
pass
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
My solution will fit the height of the smallest rectangle that encapsulates all the items (sceneRect) to the viewport of the QGraphicsView. So set the height of the items a value not so small so that the image quality is not lost. I have also scaled the items using the QTransforms. In addition, the QGraphicsView coordinate system was inverted since by default the vertical axis is top-bottom and I have inverted it so that the painting is more consistent with the data.
I have refactored the OP code to make it more scalable, there is a GraphItem that takes the data (x, y) and the image dimensions.
Considering the above, the solution is:
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphItem(QtWidgets.QGraphicsPixmapItem):
def __init__(self, xdata, ydata, width, height, parent=None):
super(GraphItem, self).__init__(parent)
self._xdata = xdata
self._ydata = ydata
self._size = QtCore.QSize(width, height)
self.redraw()
def redraw(self):
x_final = self._xdata[-1]
pixmap = QtGui.QPixmap(self._size)
pixmap_height = pixmap.height()
pixmap.fill(QtGui.QColor("lightblue"))
painter = QtGui.QPainter(pixmap)
pen = QtGui.QPen(QtGui.QColor("green"))
pen.setWidth(2)
painter.setPen(pen)
for i, (x, y) in enumerate(
zip(self._xdata, self._ydata / np.max(np.abs(self._ydata)))
):
x_pos = int(x * self._size.width() / x_final)
y_pos = abs(int(y * pixmap_height))
painter.drawLine(x_pos, 0, x_pos, y_pos)
painter.end()
self.setPixmap(pixmap)
class HorizontalRectItem(QtWidgets.QGraphicsRectItem):
def itemChange(self, change, value):
if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.scene():
newPos = self.pos()
newPos.setX(value.x())
return newPos
return super(HorizontalRectItem, self).itemChange(change, value)
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.scale(1, -1)
def resizeEvent(self, event):
h = self.mapToScene(self.viewport().rect()).boundingRect().height()
r = self.sceneRect()
r.setHeight(h)
self.setSceneRect(r)
height = self.viewport().height()
for item in self.items():
item_height = item.boundingRect().height()
tr = QtGui.QTransform()
tr.scale(1, height / item_height)
item.setTransform(tr)
super(GraphicsView, self).resizeEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
tab_widget = QtWidgets.QTabWidget(tabPosition=QtWidgets.QTabWidget.West)
self.setCentralWidget(tab_widget)
self.graphics_view_top = GraphicsView()
self.graphics_view_bottom = QtWidgets.QGraphicsView()
container = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(container)
lay.addWidget(self.graphics_view_top)
lay.addWidget(self.graphics_view_bottom)
tab_widget.addTab(container, "main")
self.resize(640, 480)
side, offset, height = 50, 200, 400
np.random.seed(777)
x_time = np.linspace(0, 12.56, 3000)
rand_data = np.random.uniform(0.0, 1.0, 3000)
data = 0.45 * (np.sin(2 * x_time) + rand_data) - 0.25 * (np.sin(3 * x_time))
graph_item = GraphItem(x_time, data, 3000, height)
self.graphics_view_top.scene().addItem(graph_item)
for i in range(2):
r = QtCore.QRectF(
QtCore.QPointF((i + 1) * offset + i * 2 * side, 2),
QtCore.QSizeF(side, height),
)
it = HorizontalRectItem(r)
it.setPen(QtGui.QPen(QtGui.QColor("red"), 2))
it.setBrush(QtGui.QColor(255, 0, 0, 127))
self.graphics_view_top.scene().addItem(it)
it.setFlags(
it.flags()
| QtWidgets.QGraphicsItem.ItemIsMovable
| QtWidgets.QGraphicsItem.ItemSendsGeometryChanges
)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()
Related
I have a QLabel showing a QPixmap that has both horizontal and vertical policies set to expanding. I have written separate code to automatically scale the pixmap according to the size of the widget, but the window cannot be resized to make the image smaller than it is, and it results in it not being able to be made smaller. How do I allow the window to be resized freely?
Resizing code:
def resizeEvent(self, a0: QtGui.QResizeEvent):
self.page.setPixmap(
self.loader.img.scaled(
self.page.width(), self.page.height(), QtCore.Qt.KeepAspectRatio
)
)
The easiest way is to inherit from QWidget override paintEvent and use QTransform to scale image to fit.
from PyQt5 import QtWidgets, QtGui, QtCore
class ImageLabel(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self._image = None
def setImage(self, image):
self._image = image
self.update()
def paintEvent(self, event):
if self._image is None or self._image.isNull():
return
painter = QtGui.QPainter(self)
width = self.width()
height = self.height()
imageWidth = self._image.width()
imageHeight = self._image.height()
r1 = width / imageWidth
r2 = height / imageHeight
r = min(r1, r2)
x = (width - imageWidth * r) / 2
y = (height - imageHeight * r) / 2
painter.setTransform(QtGui.QTransform().translate(x, y).scale(r,r))
painter.drawImage(QtCore.QPointF(0,0), self._image)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
label = ImageLabel()
label.setImage(QtGui.QImage("path/to/image.jpg"))
label.show()
app.exec()
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
Librecad uses a widget which can be infinitely resized, you can zoom in and out as much as you can. Which widget does it uses?
When I paint into a common widget, the painting is done at certain coordinates of the widget. However, I would like to draw at floating coordinates of the widget and use a line width which is fixed to certain pixels of the viewport.
Before resizing:
After resizing:
Which widget provides this functionality?
You have to use QGraphicsView and QGraphicsScene(see Graphics View Framework):
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.factor = 1.2
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self.setRenderHints(
QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform
)
self.setMouseTracking(True)
self.setScene(
QtWidgets.QGraphicsScene(QtCore.QRectF(-400, -400, 800, 800), self)
)
QtWidgets.QShortcut(QtGui.QKeySequence.ZoomIn, self, activated=self.zoomIn) # Ctrl + +
QtWidgets.QShortcut(QtGui.QKeySequence.ZoomOut, self, activated=self.zoomOut) # Ctrl + -
#QtCore.pyqtSlot()
def zoomIn(self):
self.zoom(self.factor)
#QtCore.pyqtSlot()
def zoomOut(self):
self.zoom(1 / self.factor)
def zoom(self, f):
self.scale(f, f)
def drawForeground(self, painter, rect):
super(GraphicsView, self).drawForeground(painter, rect)
if not hasattr(self, "cursor_position"):
return
painter.save()
painter.setTransform(QtGui.QTransform())
pen = QtGui.QPen(QtGui.QColor("yellow"))
pen.setWidth(4)
painter.setPen(pen)
r = self.mapFromScene(rect).boundingRect()
linex = QtCore.QLine(
r.left(), self.cursor_position.y(), r.right(), self.cursor_position.y(),
)
liney = QtCore.QLine(
self.cursor_position.x(), r.top(), self.cursor_position.x(), r.bottom(),
)
for line in (linex, liney):
painter.drawLine(line)
painter.restore()
def mouseMoveEvent(self, event):
self.cursor_position = event.pos()
self.scene().update()
super(GraphicsView, self).mouseMoveEvent(event)
def wheelEvent(self, event):
angle = event.angleDelta().y()
if angle < 0:
self.zoomIn()
else:
self.zoomOut()
super(GraphicsView, self).wheelEvent(event)
if __name__ == "__main__":
import sys
import random
app = QtWidgets.QApplication(sys.argv)
w = GraphicsView()
for _ in range(4):
r = QtCore.QLineF(
*random.sample(range(-200, 200), 2), *random.sample(range(50, 150), 2)
)
it = w.scene().addLine(r)
pen = QtGui.QPen(QtGui.QColor(*random.sample(range(255), 3)))
pen.setWidthF(5.0)
pen.setCosmetic(True)
it.setPen(pen)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
I present here a simple pyqt code, but I developed my whole design and algo upon this. The problem, is that PyQt is unable to manage a large number of objects when created. This is simple code for drawing many rectangles inside a big one. And it has Zoom and pan feature too.
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
item = None
class Rectangle(QGraphicsItem):
def __init__(self, parent, x, y, width, height, scene = None, fill=None):
self.parent = parent
super(Rectangle, self).__init__()
self.setFlags(QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
rect = QRectF(x,y,width,height)
self.dimen = [x,y,width,height]
self.rect = rect
scene.addItem(self)
self.show_its_ui()
#Function to get relative position
def get_relative_location(self,loc):
self.loc = QPointF(loc[0],loc[1])
global item
self.loc = self.mapFromItem(item, self.loc)
self.loc = (self.loc.x(),self.loc.y())
self.loc = list(self.loc)
self.dimen[0] = self.loc[0]
self.dimen[1] = self.loc[1]
#Showing its UI in the form of a rectangle
def show_its_ui(self):
#First gets its relative location and set it.
if(item is not None):
self.get_relative_location([self.dimen[0],self.dimen[1]])
#Make a Final rectangle
rect = QRectF(self.dimen[0],self.dimen[1],self.dimen[2],self.dimen[3])
self.rect = rect
def boundingRect(self):
return self.rect.adjusted(-2, -2, 2, 2)
def parentWidget(self):
return self.scene().views()[0]
def paint(self, painter, option, widget):
pen = QPen(Qt.SolidLine)
pen.setColor(Qt.black)
pen.setWidth(1)
painter.setBrush(QtGui.QColor(255, 50, 90, 200))
painter.drawRect(self.rect)
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setDragMode(QGraphicsView.RubberBandDrag)
self.setRenderHint(QPainter.Antialiasing)
self.setRenderHint(QPainter.TextAntialiasing)
def wheelEvent(self, event):
factor = 1.41 ** (event.delta() / 240.0)
self.scale(factor, factor)
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.Width = 800
self.Height = 500
self.view = GraphicsView()
self.scene = QGraphicsScene(self)
self.scene.setSceneRect(0, 0, self.Width, self.Height)
self.view.setScene(self.scene)
self.initUI()
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.view)
mainWidget = QtGui.QWidget()
mainWidget.setLayout(hbox)
self.setCentralWidget(mainWidget)
def initUI(self):
self.group = QGraphicsItemGroup()
self.group.setFlags(QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
global item
item = self.group
self.group.setFiltersChildEvents(True)
self.group.setHandlesChildEvents(False)
self._link1 = Rectangle(self, 10, 10, self.Width, self.Height,self.scene)
self._link1.setFiltersChildEvents(True)
self._link1.setHandlesChildEvents(False)
self.group.addToGroup(self._link1)
self.scene.addItem(self.group)
self.addObjects()
#Here I added objects in the big canvas
def addObjects(self):
xpos = 20
ypos = 20
#Change the below to 5 each
width = 50
height = 50
#Generate many rectangles
while(ypos < 450):
xpos = 20
while(xpos < 750):
t = Rectangle(self._link1,xpos,ypos,width,height,self.scene,True)
self.group.addToGroup(t)
xpos += (width+2)
ypos += (height+2)
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
method = mainWindow
mainWindow.show()
sys.exit(app.exec_())
Try changing, the width and height values present in addObjects function of the mainwindow class, say to 5 and 5 respectively from 50. Then the whole application run at very slow speed, when you pan/zoom. Please share your suggestions in rectifying this.
I am new to Python. I have drawn polygon and circle with fixed coordinates. Now I want to move this polygon and circle using mouse to some other place on window. Please guide me how can I do it?
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyFrame(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self)
def paintEvent(self, event=None):
paint=QPainter(self)
paint.setPen(QPen(QColor(Qt.green).dark(150),1,Qt.SolidLine))
segColor=QColor(Qt.green).dark(150)
paint.setBrush(segColor)
paint.setBrushOrigin(QPoint(225,225))
polygon=QPolygon([QPoint(250,175), QPoint(265,175), QPoint(250,190), QPoint(265,190),QPoint(250,175)])
paint.drawPolygon(polygon)
paint.setPen(QPen(QColor(Qt.red),1,Qt.SolidLine))
paint.setBrush(QBrush(Qt.NoBrush))
polygon1=QPolygon([QPoint(250,300), QPoint(250,500), QPoint(350,500), QPoint(350,300)])
paint.drawPolyline(polygon1)
paint.drawEllipse(50,50,50,50)
app=QApplication(sys.argv)
f=MyFrame()
f.show()
app.exec_()
You should look into the QGraphicsView instead of what you are doing, it has this all built in already.
http://doc.qt.nokia.com/4.7-snapshot/qgraphicsview.html
http://doc.qt.nokia.com/4.7-snapshot/qgraphicsscene.html
from PyQt4 import QtGui, QtCore
class MyFrame(QtGui.QGraphicsView):
def __init__( self, parent = None ):
super(MyFrame, self).__init__(parent)
self.setScene(QtGui.QGraphicsScene())
# add some items
x = 0
y = 0
w = 45
h = 45
pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green))
brush = QtGui.QBrush(pen.color().darker(150))
item = self.scene().addEllipse(x, y, w, h, pen, brush)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
if ( __name__ == '__main__' ):
app = QtGui.QApplication([])
f = MyFrame()
f.show()
app.exec_()
Edit: Showing how to create a QPainterPath
from PyQt4 import QtGui, QtCore
class MyFrame(QtGui.QGraphicsView):
def __init__( self, parent = None ):
super(MyFrame, self).__init__(parent)
scene = QtGui.QGraphicsScene()
self.setScene(scene)
# add some items
x = 0
y = 0
w = 45
h = 45
pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green))
brush = QtGui.QBrush(pen.color().darker(150))
item = scene.addEllipse(x, y, w, h, pen, brush)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
# create an open path
path = QtGui.QPainterPath()
path.moveTo(-w, -h)
path.lineTo(-w, h)
path.lineTo(w, h)
path.lineTo(w, -h)
clr = QtGui.QColor('blue')
clr.setAlpha(120)
brush = QtGui.QBrush(clr)
pen = QtGui.QPen(QtCore.Qt.NoPen)
fill_item = scene.addRect(-w, y, w*2, h, pen, brush)
path_item = scene.addPath(path)
if ( __name__ == '__main__' ):
app = QtGui.QApplication([])
f = MyFrame()
f.show()
app.exec_()
inspired by Eric's answers, here's some code that animates the dot by updating its x and y coordinates.
from PyQt5.QtGui import QPen, QBrush, QColor
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsItem, QApplication
class GameWindow(QGraphicsView):
def __init__( self, parent = None ):
super().__init__(parent)
self.sx = 635
self.sy = 475
scene = QGraphicsScene(0,0,self.sx,self.sy)
self.setScene(scene)
self.x = 0
self.y = 0
self.w = 30
self.h = 30
pen = QPen(QColor('dodgerblue'))
#pen = QPen(QColor(Qt.green))
brush = QBrush(pen.color())
#brush = QBrush(pen.color().darker(150))
# As opposed to using QPen and QBrush, this colors the periphery only
#dot = scene.addEllipse(self.x, self.y, self.w, self.h, QColor('dodgerblue'))
self.dot = scene.addEllipse(self.x, self.y, self.w, self.h, pen, brush)
self.dot.setFlag(QGraphicsItem.ItemIsMovable)
if __name__ == '__main__':
import sys
fps = 50
refresh_period = 1000/fps # ms
app = QApplication(sys.argv)
gw = GameWindow()
gw.resize(640,480)
gw.show()
# if the steps match the gw aspect ratio, the dot will move along the main diagonal,
# otherwise the dot will drift
xstep = 4
ystep = 3
#ystep = xstep * gw.sy / gw.sx
def moveDot():
# In place of the next four lines, one can have a function
# or a feed from an external source to update gw.x and gw.y
gw.x += xstep
gw.x %= gw.sx
gw.y += ystep
gw.y %= gw.sy
gw.dot.setRect(gw.x,gw.y,gw.w,gw.h)
timer = QTimer()
timer.timeout.connect(moveDot)
# Comment this line out to be able to click and drag the dot
timer.start(refresh_period)
sys.exit(app.exec_())