立即在Qt <= 5.12中清除`QGraphicsView`

时间:2019-12-26 23:58:23

标签: python pyqt5

下面的给定代码是从SO上的another question派生的。它会显示一个QMainWindow,其中有4个QGraphicsView用鼠标在其中绘制,而一个QPushButton则清除了4个QGraphicsView

QPainterPath类中有一个clear()方法,但是它是在Qt 5.13 中引入的,我正在使用Qt 5.12 。因此,我编写了自己的方法来清除视图及其路径。

绘图工作正常,单击Clear按钮不会导致错误,但是视图仅在下次绘图时清除,而不是立即清除。

有什么更好的解决方案可以立即清除视图?


main.py

import sys

from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPathItem
from PyQt5.QtGui import QPainterPath, QPen
from PyQt5.QtCore import Qt
from PyQt5.uic import loadUi

# Based on code from https://stackoverflow.com/a/44248794/7481773


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        loadUi("mainwindow.ui", self)

        self.layouts = (self.verticalLayout_top_left, self.verticalLayout_top_right,
                        self.verticalLayout_bottom_left, self.verticalLayout_bottom_right)

        self._views = []

        for layout in self.layouts:
            graphics_view = GraphicsView()
            self._views.append(graphics_view)
            layout.addWidget(graphics_view)

        self.clear_button.clicked.connect(self.clear_views)

    def clear_views(self):
        for view in self._views:
            view.clear_view()


class GraphicsView(QGraphicsView):
    def __init__(self):
        super().__init__()
        self.start = None
        self.end = None

        self.setScene(QGraphicsScene())
        self.path = QPainterPath()
        self.item = GraphicsPathItem()
        self.scene().addItem(self.item)

        self.contents_rect = self.contentsRect()
        self.setSceneRect(0, 0, self.contents_rect.width(), self.contents_rect.height())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def clear_view(self):
        # self.path.clear()  # Qt 5.13
        self.path = QPainterPath()
        self.scene().update()

    def mousePressEvent(self, event):
        self.start = self.mapToScene(event.pos())
        self.path.moveTo(self.start)

    def mouseMoveEvent(self, event):
        self.end = self.mapToScene(event.pos())
        self.path.lineTo(self.end)
        self.start = self.end
        self.item.setPath(self.path)


class GraphicsPathItem(QGraphicsPathItem):
    def __init__(self):
        super().__init__()
        pen = QPen()
        pen.setColor(Qt.black)
        pen.setWidth(5)
        self.setPen(pen)


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    app.exec_()
    del main_window, app


if __name__ == "__main__":
    main()

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Paint and Clear</string>
  </property>
  <property name="locale">
   <locale language="English" country="UnitedKingdom"/>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <layout class="QVBoxLayout" name="verticalLayout_top_left"/>
    </item>
    <item row="0" column="1">
     <layout class="QVBoxLayout" name="verticalLayout_top_right"/>
    </item>
    <item row="2" column="0">
     <layout class="QVBoxLayout" name="verticalLayout_bottom_left"/>
    </item>
    <item row="2" column="1">
     <layout class="QVBoxLayout" name="verticalLayout_bottom_right"/>
    </item>
    <item row="1" column="0" colspan="2">
     <widget class="QPushButton" name="clear_button">
      <property name="text">
       <string>Clear</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>24</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

1 个答案:

答案 0 :(得分:2)

即使使用clear()方法也不意味着视图已清除,但您必须在项目中设置路径。解决此问题的等效方法是建立新的QPainterPath,此外,不必调用场景的update()方法。从Python方面来看,使用clear()或设置空的QPainterPath等效,但是从C ++角度来看,它会导致优化应用程序的相同内存得以重用。

def clear_view(self):
    self.path = QPainterPath()
    self.item.setPath(self.path)

如果要同时兼容两个版本,可以使用try-except:

def clear_view(self):
    try:
        self.path.clear()
    except AttributeError as e:
        self.path = QPainterPath()
    self.item.setPath(self.path)