【问题标题】:Clear `QGraphicsView` immediately in Qt <= 5.12在 Qt <= 5.12 中立即清除 `QGraphicsView`
【发布时间】:2019-12-26 23:58:23
【问题描述】:

下面给定的代码源自 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()

主窗口.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>

【问题讨论】:

    标签: python pyqt5


    【解决方案1】:

    即使使用clear() 方法并不意味着视图已被清理,但您必须在项目中设置路径。正题,等效的方法是新建一个QPainterPath,另外不需要调用场景的update()方法。使用clear() 或设置一个空的QPainterPath 在python 端是等效的,但在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)
    

    【讨论】:

      猜你喜欢
      • 2012-07-19
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 2020-03-06
      • 2015-01-21
      相关资源
      最近更新 更多