PyQT QGraphicScene перемещает элемент в фоновом потоке

Извините за мой плохой английский. Мне нужно обновить графическую сцену в фоновом потоке. Мне нужно, чтобы поток перемещал мой прямоугольник на сцене. Но это не работает, когда запускаются потоки, прямоугольник скрывается на сцене, и я не вижу его хода. Только если я перемещаю мышью по сцене другой объект, я вижу, как движется мой прямоугольник. Но если я изменю цвет прямоугольника в потоке, он будет работать нормально. Я хочу сделать простую клиент-серверную игру, но я не понимаю, как перемещать объекты на сцене из потока. Я знаю, что сцена QGraphics не является потокобезопасным объектом, но как я могу перемещать объекты в фоновом режиме без таймера или событий?

class MyGraphicRect2(QGraphicsItem):
    def __init__(self, x, y, width, height):
        super().__init__()
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.setPos(self.x, self.y)
        self.color = QColor('red')

        # self.setToolTip('Test')

        self.setAcceptDrops(True)
        self.setCursor(Qt.OpenHandCursor)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)
        self.setAcceptHoverEvents(True)


        s = Shadow()
        b = Blur()
        c = ColorChange()
        self.setGraphicsEffect(s)
        # self.setGraphicsEffect(c)

        # self.setGraphicsEffect(b)

    def setColor(self, color):
        self.color = QColor(color)

    def boundingRect(self):
        return QRectF(self.x, self.y, self.width, self.height)

    def paint(self, painter, options, widget):
        painter.setPen(QPen(QColor('black')))
        painter.setBrush(self.color)
        painter.drawRect(self.x, self.y, self.width, self.height)


class MoveThread(QThread):
    def __init__(self,object,scene,view):
        super().__init__()
        self.object=object
        self.scene=scene
        self.view=view
    def run(self):
        for i in range(1,10):
            time.sleep(1)
            self.object.moveBy(30,0)
            print(self.object.pos().x())
            #self.object.update()
            self.view.updateSceneRect(QRectF(0,0,800,800))


         #for color in ['green','white','black','magenta','yellow']:
         #   time.sleep(1)
         #   self.object.setColor(color)
         #   self.object.update()


class MyGraphicScene(QMainWindow):
    def __init__(self):
        super().__init__()
        self.rect=QRectF(0,0,800,800)
        self.Scene=QGraphicsScene(self.rect)
        self.View=QGraphicsView()
        self.View.setCacheMode(QGraphicsView.CacheNone)
        self.sceneConfig()

    def sceneConfig(self):
                         self.Scene.setBackgroundBrush(QBrush(QColor('yellow'),Qt.SolidPattern)))

    item=MyGraphicItem(30,30,100,100)
    self.item1=MyGraphicRect2(100,100,100,100)
    self.Scene.addItem(item)
    self.Scene.addItem(self.item1)
    line=QGraphicsLineItem(80,38,84,38)
    self.Scene.addItem(line)
    self.View.setScene(self.Scene)

def displayUI(self):
    print('Is scene active', self.Scene.isActive())
    self.setCentralWidget(self.View)
    self.th=MoveThread(self.item1,self.Scene,self.View)
    self.th.start()
    self.resize(1000,1000)
    self.show()


app=QApplication(sys.argv)

m=MyGraphicScene()

sys.exit(app.exec_())

person Yaroslav B    schedule 02.06.2017    source источник


Ответы (1)


В основном потоке работает графическая часть, поэтому в других потоках не следует изменять напрямую, это нужно сделать, отправив сигнал в основной поток, и именно в его слоте обновляется графическая часть.

В следующем примере создается сигнал, который выдается каждую секунду во вторичном потоке, он подключается к слоту updatePosition, и именно туда перемещается объект.

class MyGraphicRect2(QGraphicsItem):
    def __init__(self, x, y, width, height):
        super().__init__()
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.setPos(self.x, self.y)
        self.color = QColor('red')

        self.setAcceptDrops(True)
        self.setCursor(Qt.OpenHandCursor)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)
        self.setAcceptHoverEvents(True)

    def setColor(self, color):
        self.color = QColor(color)

    def boundingRect(self):
        return QRectF(self.x, self.y, self.width, self.height)

    def paint(self, painter, options, widget):
        painter.setPen(QPen(QColor('black')))
        painter.setBrush(self.color)
        painter.drawRect(self.x, self.y, self.width, self.height)


class MoveThread(QThread):
    s = pyqtSignal(float, float)
    def __init__(self):
        super().__init__()
    def run(self):
        for i in range(1,10):
            time.sleep(1)
            self.s.emit(30,0)


class MyGraphicScene(QMainWindow):
    def __init__(self):
        super().__init__()
        self.rect=QRectF(0,0,800,800)
        self.Scene=QGraphicsScene(self.rect)
        self.View=QGraphicsView()
        self.View.setCacheMode(QGraphicsView.CacheNone)
        self.sceneConfig()
        self.displayUI()

    def sceneConfig(self):
        self.Scene.setBackgroundBrush(QBrush(QColor('yellow'),Qt.SolidPattern))

        self.item1=MyGraphicRect2(100,100,100,100)
        self.Scene.addItem(self.item1)
        line=QGraphicsLineItem(80,38,84,38)
        self.Scene.addItem(line)
        self.View.setScene(self.Scene)

    def updatePosition(self, x, y):
        self.item1.moveBy(x, y)

    def displayUI(self):
        print('Is scene active', self.Scene.isActive())
        self.setCentralWidget(self.View)
        self.th=MoveThread()
        self.th.s.connect(self.updatePosition)
        self.th.start()
        self.resize(1000,1000)
        self.show()

import sys
app=QApplication(sys.argv)

m=MyGraphicScene()

sys.exit(app.exec_())
person eyllanesc    schedule 02.06.2017
comment
ВОТ ЭТО ДА!! Это работает!!!! Благодарю вас!!!!! Почему мне не пришла в голову такая мысль? Ведь я раньше делал обмен сигналами между потоками. Еще раз огромное спасибо!!!! - person Yaroslav B; 02.06.2017