How can change pixmap and move it alternatively in

2020-04-18 07:26发布

问题:

raiseTemmie.py

import random
import sys
import time

from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QApplication

class Example(QWidget):
    size=100
    imgNum=0
    imgQuantity=2

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setStyleSheet("background-color:transparent;")
        self.setGeometry(100, 100, 100, 100)
        self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
        self.label=QLabel(self)
        self.pixmaps=[QPixmap('left.png'),QPixmap('right.png'),QPixmap('stand.png')]
        for x in range(len(self.pixmaps)):
            self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio)
        self.label.setPixmap(self.pixmaps[2])
        self.resize(self.pixmaps[2].width(),self.pixmaps[2].height())
        self.show()

    def moving(self):
        distance=random.randint(10,40)
        direct =[random.randint(-1,2),random.randint(-1,2)]
        for x in range(0,distance):
            self.changeFoot()
            self.move(self.x()+5*direct[0],self.y()+5*direct[1])
            time.sleep(0.05)
        # self.changeTimer.stop()


    def changeFoot(self):
        if self.imgNum<self.imgQuantity-1:
            self.imgNum+=1
        else :
            self.imgNum=0
        self.label.setPixmap(self.pixmaps[self.imgNum])

    def mousePressEvent(self, QMouseEvent):
        self.label.setPixmap(self.pixmaps[2])
        self.changeTimer.stop()

    changeTimer=QTimer()
    def keyPressEvent(self, QKeyEvent):
        if QKeyEvent.key() == Qt.Key_Escape:
            sys.exit()
        if QKeyEvent.key() == Qt.Key_G:
            self.moving()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

I thought this code would switch the pixmap and move it simultaneously but it do not work well. The timer start after moving finished. What is the problem?

def keyPressEvent(self, QKeyEvent):
    if QKeyEvent.key() == Qt.Key_Escape:
        sys.exit()
    if QKeyEvent.key() == Qt.Key_G:
        self.moving()

if I press 'G', it starts the changeTimer and calls moving()

回答1:

A possible solution is to use qApp.processEvents() to update the data, this is recommended when tasks require little time as is your case, since the maximum time of the loop is 0.05sec*40=2sec.

def moving(self):
    distance=random.randint(10,40)
    direct =[random.randint(-1,2),random.randint(-1,2)]
    for x in range(0,distance):
        self.changeFoot()
        self.move(self.x()+5*direct[0],self.y()+5*direct[1])
        time.sleep(0.05)
        qApp.processEvents()

The solution may fail if time grows, another solution is to implement the timer and separate the tasks correctly as I show below:

class Example(QWidget):
    size=100
    imgNum=0
    imgQuantity=2

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setStyleSheet("background-color:transparent;")
        self.setGeometry(100, 100, 100, 100)
        self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
        self.label=QLabel(self)
        self.pixmaps=[QPixmap('left.png'),QPixmap('right.png'),QPixmap('stand.png')]
        for x in range(len(self.pixmaps)):
            self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio)
        self.label.setPixmap(self.pixmaps[2])
        self.resize(self.pixmaps[2].width(),self.pixmaps[2].height())

        self.changeTimer=QTimer(self)
        self.changeTimer.timeout.connect(self.onTimeout)
        self.show()

    def moving(self):
        self.distance= random.randint(10,40)
        self.direct = QPoint(random.randint(-1,2), random.randint(-1,2))
        self.changeTimer.start(50)

    def onTimeout(self):
        if self.distance == 0:
            self.changeTimer.stop()
        else:
            self.changeFoot()
            self.move(self.pos() +  self.direct)
        self.distance -= 1   

    def changeFoot(self):
        if self.imgNum<self.imgQuantity-1:
            self.imgNum+=1
        else :
            self.imgNum=0
        self.label.setPixmap(self.pixmaps[self.imgNum])

    def mousePressEvent(self, QMouseEvent):
        self.label.setPixmap(self.pixmaps[2])
        self.changeTimer.stop()

    def keyPressEvent(self, QKeyEvent):
        if QKeyEvent.key() == Qt.Key_Escape:
            self.close()
        if QKeyEvent.key() == Qt.Key_G:
            self.moving()

Note: It is advisable to use self.close() instead of sys.exit() since the first gives time for the program to free resources and close properly.