此问题与Win10和Python 3.6.6上的VS Code有关。我是Python和PySide2的新手。
我在StackOverflow上阅读了很多与此相关的主题,可能与另一个主题重复,但是我无法绘制小部件。
我知道必须以某种方式覆盖小部件对象的paintEvent()。那里的大多数示例都在主窗口上进行了绘画,但是我无法从ui.file在小部件上进行传输。
我在.py文件中创建了两个类MainForm和Drawer。MainForm包含UI的实现,我正在尝试绘制一个小部件(名为“ widget”)。在我的.ui文件中,有一个小部件和一个graphicsview。我正在尝试在小部件上实现绘画。
paintEventTest.py文件如下所示:
import sys from PySide2 import QtWidgets from PySide2 import QtGui from PySide2 import QtCore from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import ( QApplication, QPushButton, QLineEdit, QTextEdit, QSpinBox, QMainWindow, QDesktopWidget, QTableWidget, QTableWidgetItem, QToolButton, QToolTip) from PySide2.QtCore import QFile, QObject, Qt class MainForm(QMainWindow): def __init__(self, ui_file, parent=None): super(MainForm, self).__init__(parent) ui_file = QFile(ui_file) ui_file.open(QFile.ReadOnly) ### Load UI file from Designer ### loader = QUiLoader() self.ui_window = loader.load(ui_file) ui_file.close() self.ui_window.show() ### THIS IS NOT WORKING (OBVIOUSLY?) ### widget = self.ui_window.widget drawer = Drawer() drawer.paintEvent(widget) class Drawer(QtWidgets.QWidget): def paintEvent(self, e): ''' the method paintEvent() is called automatically the QPainter class does all the low-level drawing coded between its methods begin() and end() ''' qp = QtGui.QPainter() qp.begin(self) self.drawGeometry(qp) qp.end() def drawGeometry(self, qp): qp = QtGui.QPainter(self) qp.setPen(QtGui.QPen(Qt.green, 8, Qt.DashLine)) qp.drawEllipse(40, 40, 400, 400) if __name__ == '__main__': app = QApplication(sys.argv) app.setStyle('Fusion') form = MainForm('./UI designer/testUI.ui') sys.exit(app.exec_())
testUI.ui看起来像这样,并在“ 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>731</width> <height>633</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QGraphicsView" name="graphicsView"> <property name="minimumSize"> <size> <width>0</width> <height>200</height> </size> </property> </widget> </item> <item> <widget class="QWidget" name="widget" native="true"> <property name="minimumSize"> <size> <width>0</width> <height>250</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>300</height> </size> </property> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>731</width> <height>21</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
我正在上面的代码中得到这个。我不希望它能起作用,但是对于如何引用要绘制的特定小部件,我真的一无所知。
QWidget::paintEngine: Should no longer be called QPainter::begin: Paint device returned engine == 0, type: 1 QWidget::paintEngine: Should no longer be called QPainter::begin: Paint device returned engine == 0, type: 1 QPainter::setPen: Painter not active QPainter::end: Painter not active, aborted
我也对在带有graphicsscene和graphicsitem的graphicsview上进行等效代码绘制感兴趣。
如您所指出,paintEvent应该仅被覆盖。因此,一种方法是升级窗口小部件 您必须具有以下结构:
├── main.py ├── mywidget.py └── UI designer └── testUI.ui
在mywidget.py文件中,实现所需的类:
mywidget.py
from PySide2 import QtCore, QtGui, QtWidgets class Drawer(QtWidgets.QWidget): def paintEvent(self, e): """ the method paintEvent() is called automatically the QPainter class does all the low-level drawing coded between its methods begin() and end() """ qp = QtGui.QPainter() qp.begin(self) self.drawGeometry(qp) qp.end() def drawGeometry(self, qp): qp.setPen(QtGui.QPen(QtCore.Qt.green, 8, QtCore.Qt.DashLine)) qp.drawEllipse(40, 40, 400, 400)
然后,您必须使用Qt Designer打开.ui,右键单击窗口小部件并在上下文菜单中选择“提升为…”,然后在对话框中填写以下内容:
按添加按钮,然后按升级按钮,生成以下.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>731</width> <height>633</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QGraphicsView" name="graphicsView"> <property name="minimumSize"> <size> <width>0</width> <height>200</height> </size> </property> </widget> </item> <item> <widget class="Drawer" name="widget" native="true"> <property name="minimumSize"> <size> <width>0</width> <height>250</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>300</height> </size> </property> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>731</width> <height>23</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <customwidgets> <customwidget> <class>Drawer</class> <extends>QWidget</extends> <header>mywidget</header> <container>1</container> </customwidget> </customwidgets> <resources/> <connections/> </ui>
另一方面,QUiLoader仅加载Qt默认提供的小部件,因此,如果要使用新的小部件,必须覆盖createWidget方法:
main.py
import os import sys from PySide2 import QtCore, QtGui, QtWidgets, QtUiTools from mywidget import Drawer class UiLoader(QtUiTools.QUiLoader): def createWidget(self, className, parent=None, name=""): if className == "Drawer": widget = Drawer(parent) widget.setObjectName(name) return widget return super(UiLoader, self).createWidget(className, parent, name) class MainForm(QtCore.QObject): def __init__(self, ui_file, parent=None): super(MainForm, self).__init__(parent) ui_file = QtCore.QFile(ui_file) ui_file.open(QtCore.QFile.ReadOnly) ### Load UI file from Designer ### loader = UiLoader() self.ui_window = loader.load(ui_file) ui_file.close() self.ui_window.show() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) app.setStyle("Fusion") file = os.path.join( os.path.dirname(os.path.realpath(__file__)), "./UI designer/testUI.ui" ) form = MainForm(file) sys.exit(app.exec_())