python - 更改 Pen 不会更新外部线程中的 QGraphicsLineItem
问题描述
我正在通过在 QGraphicsLine 的子类中编程的方法来更新笔的颜色,甚至是 QGraphicsLine 对象的笔。问题在于,当我设置新笔时,当我从线程调用它时,该行消失了。
import sys
from PyQt5.QtGui import QColor, QBrush, QPen, QPainter
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsEllipseItem, QGraphicsSceneMouseEvent, \
QGraphicsSceneHoverEvent, QGraphicsLineItem, QApplication, QMainWindow, QGraphicsView, QToolBar, QAction
from threading import Thread
from time import sleep
from random import randint
class GraphicsLine(QGraphicsLineItem):
def __init__(self, x1: float, y1: float, x2: float, y2: float):
super(GraphicsLine, self).__init__(x1, y1, x2, y2)
pen = QPen(QColor(0, 0, 0))
pen.setWidth(5)
self.setPen(pen)
self.setZValue(5)
def change_color(self):
pen = QPen(QColor(randint(0, 255), randint(0, 255), randint(0, 255)))
pen.setWidth(5)
self.setPen(pen)
class GraphicsNode(QGraphicsEllipseItem):
def __init__(self, x: float, y: float, size: int):
super(GraphicsNode, self).__init__(x - size/2, y - size/2, size, size)
self.setAcceptHoverEvents(True)
self.setZValue(10)
brush = QBrush(QColor(0, 0, 0))
pen = QPen(QColor(0, 0, 0))
pen.setWidth(0)
self.setBrush(brush)
self.setPen(pen)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
pass
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None:
self.setBrush(QColor(0, 255, 0))
def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None:
self.setBrush(QColor(0, 0, 0))
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.width = 600
self.height = 500
self.thread_stop = False
self.toolbar = QToolBar()
self.action_color = QAction('Change Color', self)
self.action_color.triggered.connect(self.__change_color)
self.toolbar.addAction(self.action_color)
self.action_stop = QAction('Stop Thread', self)
self.action_stop.triggered.connect(self.__stop_thread)
self.toolbar.addAction(self.action_stop)
self.addToolBar(self.toolbar)
self.scene = QGraphicsScene()
self.graphics_view = QGraphicsView(self.scene, self)
self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing)
self.graphics_view.setGeometry(0, 20, 600, 500)
self.__create_graphs()
self.show()
def __create_graphs(self):
self.nodes = [GraphicsNode(0, 0, 20), GraphicsNode(0, 100, 20)]
self.lines = [GraphicsLine(0, 0, 0, 100)]
for node in self.nodes:
self.scene.addItem(node)
for line in self.lines:
self.scene.addItem(line)
self.thread = Thread(target=self.__color_changer_thread)
self.thread.start()
def __color_changer_thread(self):
while not self.thread_stop:
for line in self.lines:
line.change_color()
sleep(5)
def __change_color(self):
for line in self.lines:
line.change_color()
def __stop_thread(self):
self.thread_stop = True
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
单击 ToolBar 中的 Action 时对象 GraphicsLine 的颜色会发生变化,但是线程使该项目不可见。如果对线程进行了评论,则操作底部会毫无问题地更改颜色。
先感谢您。
解决方案
非常感谢@musicamante。
解决方案 该解决方案包括创建一个 QThread 而不是 POSIX 线程,并在 QThread 子类中创建一个信号并将其连接到在 Widget 中创建的插槽。(参考:从后台工作线程修改 Qt GUI)
import sys
from PyQt5.QtCore import QThread, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QColor, QBrush, QPen, QPainter
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsEllipseItem, QGraphicsSceneMouseEvent, \
QGraphicsSceneHoverEvent, QGraphicsLineItem, QApplication, QMainWindow, QGraphicsView, QToolBar, QAction
from threading import Thread
from time import sleep
from random import randint
class ColorChangingThread(QThread):
signal_color_change = pyqtSignal(int, name='Scheduled color change')
def __init__(self):
super(ColorChangingThread, self).__init__()
self.stop_thread = False
def run(self) -> None:
while not self.stop_thread:
self.signal_color_change.emit(0)
self.sleep(5)
class GraphicsLine(QGraphicsLineItem):
def __init__(self, x1: float, y1: float, x2: float, y2: float):
super(GraphicsLine, self).__init__(x1, y1, x2, y2)
pen = QPen(QColor(0, 0, 0))
pen.setWidth(5)
self.setPen(pen)
self.setZValue(5)
def change_color(self):
pen = QPen(QColor(randint(0, 255), randint(0, 255), randint(0, 255)))
pen.setWidth(5)
self.setPen(pen)
class GraphicsNode(QGraphicsEllipseItem):
def __init__(self, x: float, y: float, size: int):
super(GraphicsNode, self).__init__(x - size/2, y - size/2, size, size)
self.setAcceptHoverEvents(True)
self.setZValue(10)
brush = QBrush(QColor(0, 0, 0))
pen = QPen(QColor(0, 0, 0))
pen.setWidth(0)
self.setBrush(brush)
self.setPen(pen)
def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
pass
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None:
self.setBrush(QColor(0, 255, 0))
def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None:
self.setBrush(QColor(0, 0, 0))
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.width = 600
self.height = 500
self.thread = ColorChangingThread()
self.thread.signal_color_change.connect(self.slot_color_change)
self.toolbar = QToolBar()
self.action_color = QAction('Change Color', self)
self.action_color.triggered.connect(self.__change_color)
self.toolbar.addAction(self.action_color)
self.action_stop = QAction('Stop Thread', self)
self.action_stop.triggered.connect(self.__stop_thread)
self.toolbar.addAction(self.action_stop)
self.addToolBar(self.toolbar)
self.scene = QGraphicsScene()
self.graphics_view = QGraphicsView(self.scene, self)
self.graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing)
self.graphics_view.setGeometry(0, 20, 600, 500)
self.__create_graphs()
self.show()
def __create_graphs(self):
self.nodes = [GraphicsNode(0, 0, 20), GraphicsNode(0, 100, 20)]
self.lines = [GraphicsLine(0, 0, 0, 100)]
for node in self.nodes:
self.scene.addItem(node)
for line in self.lines:
self.scene.addItem(line)
self.thread.start()
@pyqtSlot(int)
def slot_color_change(self, value):
print('Received signal with value %d' % value)
self.__change_color()
def __change_color(self):
for line in self.lines:
line.change_color()
def __stop_thread(self):
self.thread.stop_thread = True
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
推荐阅读
- sql - 在 oracle 中比较时间戳和 sysdate
- java - Java spring 'Hello World' 示例无法编译
- selenium - 即使我无头运行,我也会收到“未知错误:找不到 Chrome 二进制文件”错误
- java - 在 Java 中,如何使一个类中的公共变量对导入包中的另一个类中的方法可见?
- sql - 计算秤的数量
- django - Django Rest Framework 唯一的验证与请求中缺少的字段
- python - 为什么我在使用 if 语句时不断收到语法错误?
- java - 返回一些东西而不是返回 null
- pandas - 仅合并和连接非空列
- javascript - 无法从json动态添加选项到选择