当前位置: 首页 > 面试题库 >

由设计师创建的小部件上的PySide2绘画

赵越
2023-03-14
问题内容

此问题与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应该仅被覆盖。因此,一种方法是升级窗口小部件,您可以在以下答案中看到几个示例:

  • https://stackoverflow.com/a/46616419
  • https://stackoverflow.com/a/52131384
  • https://stackoverflow.com/a/47273625
  • https://stackoverflow.com/a/46671439

您必须具有以下结构:

├── 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_())


 类似资料:
  • 问题内容: 以下是我的脚本。基本上,它将要求用户在“输入”框中输入一个数字。用户输入数字并单击“确定”后,它将为您提供“标签+按钮”的组合,具体取决于用户在“输入”框中键入的数字。 通常,当我创建标签小部件时,我会做这样的事情 因此,当我以后想要更改标签的文本时,只需执行此操作 但是现在,由于我正在使用for循环一次创建所有标签,因此创建标签后,是否仍要处理单个标签?例如,用户在输入框中输入“ 5

  • 面试建议有: 细心准备:回归到之前说到作品集三个层级,第一步先把话讲清楚,熟练并精彩的讲述“能力故事”。其实已经可以打败70-80%的设计师了,只需要按照我梳理的步骤细心准备相信大家都可以做好。 作品集讲解的三个层级 层级一:把我做了什么讲清楚 层级二:回答针对业务上的随机提问 层级三:回答开放式随机的提问   大胆自信:为什么说大胆,面试需要我们自信的态度,落落大方的回答提问,让面试官产生信任。

  • 一面感觉还不错就是个双方互相了解的这个过程,是周六早上面的一个面试官,人还不错,问了我一下项目很简单的聊了一下,大概十多分钟就结束了,然后二面因为阳了没能去到现场,约的线上面试,问的项目比较细致可能是面试官不了解我的这个项目吧,也比较杂个人感觉还不错。后面反问了一下这个岗位是干什么的,以及招几个人?说了只招一个人,而且是专家类型的人才。他这一说我就知道没有希望了。但是招收专家类型的人才为什么要校招

  • 问题内容: 我是Python的新手。我想创建一个以图像为背景的应用程序。但是,当我在图像上添加“标签”时,标签上会看到白色背景。我们是否可以将“标签”小部件的颜色设置为“透明”? 问题答案: 我不知道一种使Label背景透明的方法。一种选择是使用Canvas小部件作为整个对象的基础,然后使用该方法添加背景图像并创建文本标签。这将需要更多的工作,但是文本应该在图像顶部没有背景的情况下呈现。(诚​​然

  • 问题内容: 我在gwt应用程序上有一个FlowPanel对象。 它给了我以下错误: 如何设置的ID ? 问题答案: 我正在使用GWT 2.4.0,此代码可以正常工作。 要么

  • 我将用Netbeans GUI-builder制作的GUI转移到Eclipse。我想知道GUI构建器在代码中输入的这条看起来吓人的消息是否仍然相关: