sw123456
sw123456

Reputation: 3459

Animating a rectangle in PyQT5: Why is QtCore not defined?

I am trying to animate a rectangle in PyQT by creating an animation loop. I have done this in TKinter using the window.after() method and am trying to do the same thing in PyQt5 using QtCore.QTimer.singleShot(), however, when I run the code it says that QtCore is not defined yet I believe that I have imported it!? Also - would this method work anyway? Is there a better method?

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import *
from PyQt5.QtCore import *


def animate():
    global a
    global x
    mw.paintEvent = paintEvent
    a = a+1
    x = x+1
    QtCore.QTimer.singleShot(33, animate)


def paintEvent(e):
    qp = QPainter()
    qp.begin(mw)
    qp.setBrush(QColor(200, 0, 0))
    qp.drawRect(a, b, x, y)
    qp.end()

a = 10
b = 15
x = 90
y = 60

app = QApplication(sys.argv)

mw = QMainWindow()
mw.setWindowTitle('PyQt5 - Main Window')
mw.setWindowIcon(QIcon("icon.jpg"))
mw.resize(300,100)

animate()

mw.show()
sys.exit(app.exec_())

Upvotes: 3

Views: 8305

Answers (2)

Bakuriu
Bakuriu

Reputation: 101919

The QtCore reference is undefined because you are using a star import:

from PyQt5.QtCore import *

this imports everything that is inside QtCore into the global namespace but it does not import the name QtCore.

In fact you can use:

QTimer.singleShot(x)

without the need for QtCore. in front.

However you should probably use:

from PyQt5 import QtCore

This said:

I have no idea why you are using the singleShot timer when you do not want a single shot timer but a period one. You should do something like:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import *
from PyQt5.QtCore import *


class MyWindow(QMainWindow):
    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        qp.setBrush(QColor(200, 0, 0))
        qp.drawRect(a, b, x, y)
        qp.end()


def updateValues():
    global a, x
    a += 1
    x += 1
    mw.update()  # <-- update the window!


a = 10
b = 15
x = 90
y = 60

app = QApplication(sys.argv)

mw = MyWindow()
mw.setWindowTitle('PyQt5 - Main Window')
mw.setWindowIcon(QIcon("icon.jpg"))
mw.resize(300,100)

timer = QTimer()
timer.timeout.connect(updateValues)
timer.start(33)

mw.show()
sys.exit(app.exec_())

The QTimer object called with start(msec) will emit a timeout() signal every msec milliseconds. In this way you don't have to restart it every time.

Moreover I find really ugly to patch instances by changing their methods like you are doing in animate() with mw.paintEvent = paintEvent. Besides: you could put that line outside the function.

Note: Inside the function that updates the values you have to call mw.update() otherwise no paintEvent is generated. Moreover it seems like timer is getting garbage collected, thus blocking the timer so it's better to just have a global reference to it.

Upvotes: 3

Bryan Oakley
Bryan Oakley

Reputation: 385830

You haven't imported QTCore, you've imported everything in QTCore.

Change the way you import

Try changing this:

from PyQt5.QtCore import *

to this:

from PyQt5 import QtCore

Or, change the way you call QTimer

change this:

QTCore.QTimer.singleShot(33, animate)

to this:

QTImer.singleShot(33, animate)

Upvotes: 3

Related Questions