使用 Qt Designer 时显示 PySide2 QCharts

Getting PySide2 QCharts to show up when using Qt Designer

我遇到了与此处问题类似的问题:

所以我在 Qt Designer 中创建了我的 UI 的主窗口,我试图让 QtChart 显示在我的 window 中的一个选项卡中。我正在将 .ui 文件导入 python 程序,到目前为止,我可以让主要的 window 正常显示,但不是图表。我一天中的大部分时间都在尝试按照上述答案中列出的说明进行操作,但到目前为止,我还无法让我的升级小部件正确导入到我的主程序中。我一直想知道是否部分原因是我正在尝试在 Qt 的 python 版本(即 PySide2)中执行此操作,而不是此答案可能是针对 C++ 版本编写的。

我试过同时使用 QWidget 和推荐的 QGraphicsView 作为我的基础来提升我的 QChartView,但到目前为止每次尝试都会给我一个错误,内容如下: "QFormBuilder was unable to create a custom widget of the class 'QChartView'; defaulting to base class 'QWidget'."我做错了什么?

与链接的 question/answer 状态一样,我将我的升级小部件设置为 QChartView 的“升级 Class 名称”和 QtCHarts 的“头文件”。下面是我的 Python 程序的基本代码(忽略开始时我奇怪的导入,因为这是一个单独的问题,我正在处理我的程序找不到 class 导入的地方,除非我格式化它们那样。)

如有任何帮助,我们将不胜感激!谢谢!

import sys
import PySide2.QtCore as Qt_Core
import PySide2.QtGui as Qt_Gui
import PySide2.QtWidgets as Qt_Widgets
import PySide2.QtUiTools as Qt_UiTools
import PySide2.QtCharts as Qt_Chart
from PySide2.QtCharts import QtCharts
import Pico_Image_Resources
import Chart_UI

# Having import issues with submodules.
# Need to explicitly import submodules.
QMainWindow = Qt_Widgets.QMainWindow
QApplication = Qt_Widgets.QApplication
QGraphicsView = Qt_Widgets.QGraphicsView
QUiLoader = Qt_UiTools.QUiLoader
QFile = Qt_Core.QFile
QStyleFactory = Qt_Widgets.QStyleFactory
QtCharts = Qt_Chart.QtCharts
QChartView = QtCharts.QChartView
QPainter = Qt_Gui.QPainter
#-----------------------------------------

class MainWindow(QMainWindow):

    def __init__(self, ui_file, parent=None):
        super(MainWindow, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)
 
        chartUI = Chart_UI.generateChart()
        self.chart = QtCharts.QChart()

        """
        Code that defines my chart setup is here

        """
        
        loader = QUiLoader()
        self.window = loader.load(ui_file)
        QApplication.setStyle(QStyleFactory.create('Fusion'))
        ui_file.close()
      
        #Normal Way to set up 'ChartView'
        # self.chartView = QChartView(self.chart)

        self.chartView = self.window.findChild(QChartView, 'calibrationChart')
        self.chartView.setChart(self.chart)
        self.chartView.setRenderHint(QPainter.Antialiasing)

        self.window.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow('My_Main_Window.ui')
    sys.exit(app.exec_())

[编辑]:这是我按要求加载的 .ui 文件代码。这不是完整的文件,因为原始文件太长 post,但应该足以理解:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <author></author>
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="enabled">
   <bool>true</bool>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1280</width>
    <height>720</height>
   </rect>
  </property>
  <property name="minimumSize">
   <size>
    <width>1280</width>
    <height>720</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="styleSheet">
   <string notr="true"/>
  </property>
  <property name="toolButtonStyle">
   <enum>Qt::ToolButtonFollowStyle</enum>
  </property>
  <widget class="QWidget" name="centralwidget">
   <property name="styleSheet">
    <string notr="true"/>
   </property>
   <widget class="QTabWidget" name="tabWidget">
    <property name="geometry">
     <rect>
      <x>400</x>
      <y>10</y>
      <width>871</width>
      <height>641</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>10</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="focusPolicy">
     <enum>Qt::TabFocus</enum>
    </property>
    <property name="currentIndex">
     <number>0</number>
    </property>
    <widget class="QWidget" name="tabCalib">
     <property name="enabled">
      <bool>true</bool>
     </property>
     <attribute name="title">
      <string>Chart 1</string>
     </attribute>
     <widget class="QChartView" name="calibrationChart" native="true">
      <property name="geometry">
       <rect>
        <x>19</x>
        <y>19</y>
        <width>821</width>
        <height>571</height>
       </rect>
      </property>
     </widget>
    </widget>
    <widget class="QWidget" name="tabDynamic">
     <attribute name="title">
      <string>Chart 2</string>
     </attribute>
     <widget class="QGraphicsView" name="graphicsView_2">
      <property name="geometry">
       <rect>
        <x>10</x>
        <y>10</y>
        <width>861</width>
        <height>591</height>
       </rect>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Sunken</enum>
      </property>
      <property name="renderHints">
       <set>QPainter::Antialiasing|QPainter::TextAntialiasing</set>
      </property>
     </widget>
    </widget>
   </widget>
   <widget class="QWidget" name="verticalLayoutWidget">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>10</y>
      <width>361</width>
      <height>451</height>
     </rect>
    </property>
    <layout class="QVBoxLayout" name="verticalLayout">
     <property name="spacing">
      <number>10</number>
     </property>
     <property name="sizeConstraint">
      <enum>QLayout::SetDefaultConstraint</enum>
     </property>
     <property name="leftMargin">
      <number>0</number>
     </property>
     <item>
      <widget class="QLabel" name="label_20">
       <property name="minimumSize">
        <size>
         <width>0</width>
         <height>32</height>
        </size>
       </property>
       <property name="maximumSize">
        <size>
         <width>16777215</width>
         <height>32</height>
        </size>
       </property>
       <property name="font">
        <font>
         <family>Calibri</family>
         <pointsize>11</pointsize>
         <weight>75</weight>
         <bold>true</bold>
         <strikeout>false</strikeout>
        </font>
       </property>
       <property name="frameShape">
        <enum>QFrame::StyledPanel</enum>
       </property>
       <property name="frameShadow">
        <enum>QFrame::Plain</enum>
       </property>
       <property name="text">
        <string>Test Title Here</string>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
       <property name="wordWrap">
        <bool>false</bool>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QGroupBox" name="groupBox">
       <property name="title">
        <string>Please fill in the following data boxes:</string>
       </property>
       <widget class="QWidget" name="layoutWidget">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>40</y>
          <width>341</width>
          <height>271</height>
         </rect>
        </property>
        <layout class="QFormLayout" name="formLayout">
         <property name="labelAlignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
         <property name="horizontalSpacing">
          <number>10</number>
         </property>
         <property name="verticalSpacing">
          <number>10</number>
         </property>
         <item row="0" column="0">
          <widget class="QLabel" name="label_2">
           <property name="text">
            <string>Field One:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QLineEdit" name="lineEdit_8"/>
         </item>
         <item row="1" column="0">
          <widget class="QLabel" name="label_3">
           <property name="text">
            <string>Field Two:</string>
           </property>
          </widget>
         </item>
         <item row="1" column="1">
          <widget class="QLineEdit" name="lineEdit"/>
         </item>
         <item row="2" column="0">
          <widget class="QLabel" name="label_4">
           <property name="text">
            <string>Field Three:</string>
           </property>
          </widget>
         </item>
         <item row="2" column="1">
          <widget class="QLineEdit" name="lineEdit_2"/>
         </item>
         <item row="4" column="0">
          <widget class="QLabel" name="label_5">
           <property name="text">
            <string>Field Five:</string>
           </property>
          </widget>
         </item>
         <item row="4" column="1">
          <widget class="QLineEdit" name="lineEdit_3"/>
         </item>
         <item row="5" column="0">
          <widget class="QLabel" name="label_6">
           <property name="text">
            <string>Field Six:</string>
           </property>
          </widget>
         </item>
         <item row="5" column="1">
          <widget class="QLineEdit" name="lineEdit_4"/>
         </item>
         <item row="6" column="0">
          <widget class="QLabel" name="label_7">
           <property name="text">
            <string>Selection One:</string>
           </property>
          </widget>
         </item>
         <item row="6" column="1">
          <widget class="QComboBox" name="comboBox">
           <property name="currentIndex">
            <number>3</number>
           </property>
           <item>
            <property name="text">
             <string>123</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>456</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>789</string>
            </property>
           </item>
          </widget>
         </item>
         <item row="7" column="0">
          <widget class="QLabel" name="label_8">
           <property name="text">
            <string>Selection Two:</string>
           </property>
          </widget>
         </item>
         <item row="7" column="1">
          <widget class="QComboBox" name="comboBox_2">
           <property name="currentIndex">
            <number>3</number>
           </property>
           <item>
            <property name="text">
             <string>123</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>456</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>789</string>
            </property>
           </item>
          </widget>
         </item>
         <item row="8" column="0">
          <widget class="QLabel" name="label_9">
           <property name="text">
            <string>Output:</string>
           </property>
          </widget>
         </item>
         <item row="8" column="1">
          <widget class="QLineEdit" name="lineEdit_7">
           <property name="enabled">
            <bool>false</bool>
           </property>
          </widget>
         </item>
         <item row="3" column="0">
          <widget class="QLabel" name="label_21">
           <property name="text">
            <string>Field Four:</string>
           </property>
          </widget>
         </item>
         <item row="3" column="1">
          <widget class="QLineEdit" name="lineEdit_5">
           <property name="enabled">
            <bool>false</bool>
           </property>
           <property name="readOnly">
            <bool>true</bool>
           </property>
           <property name="clearButtonEnabled">
            <bool>false</bool>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </widget>
     </item>
    </layout>
   </widget>
   <widget class="Line" name="line">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>470</y>
      <width>361</width>
      <height>21</height>
     </rect>
    </property>
    <property name="orientation">
     <enum>Qt::Horizontal</enum>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>140</x>
      <y>500</y>
      <width>111</width>
      <height>41</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <family>Calibri</family>
      <pointsize>14</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: rgb(85, 255, 0)</string>
    </property>
    <property name="text">
     <string>START TEST</string>
    </property>
    <property name="checkable">
     <bool>false</bool>
    </property>
    <property name="checked">
     <bool>false</bool>
    </property>
    <property name="default">
     <bool>false</bool>
    </property>
    <property name="flat">
     <bool>false</bool>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1280</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionSettings"/>
    <addaction name="separator"/>
    <addaction name="actionClose"/>
   </widget>
   <widget class="QMenu" name="menuAbout">
    <property name="title">
     <string>About</string>
    </property>
   </widget>
   <addaction name="menuFile"/>
   <addaction name="menuAbout"/>
  </widget>
  <widget class="QStatusBar" name="statusbar">
   <property name="enabled">
    <bool>true</bool>
   </property>
   <property name="autoFillBackground">
    <bool>false</bool>
   </property>
   <property name="styleSheet">
    <string notr="true">background-color: rgb(0, 132, 203);</string>
   </property>
   <property name="sizeGripEnabled">
    <bool>true</bool>
   </property>
  </widget>
  <action name="actionSettings">
   <property name="text">
    <string>Settings</string>
   </property>
  </action>
  <action name="actionClose">
   <property name="text">
    <string>Close</string>
   </property>
  </action>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QChartView</class>
   <extends>QWidget</extends>
   <header>QtCharts</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources>
 </resources>
 <connections/>
</ui>

作为容器的 QWidget:

在这种情况下,我不建议应用提升,因为它会使任务复杂化很多,但我将展示如何应用 中所示的解决方案:使用 QWidget 作为 .ui.

例如,我创建了一个包含多个组件的 .ui,在您要放置 QChartView 的位置放置一个 QWidget(为了使其可见,我设置了绿色背景色):

design.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>636</width>
    <height>480</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
    <item row="0" column="0">
     <widget class="QListWidget" name="listWidget"/>
    </item>
    <item row="1" column="0">
     <widget class="QTableWidget" name="tableWidget"/>
    </item>
    <item row="0" column="1" rowspan="2">
     <widget class="QWidget" name="widget" native="true">
      <property name="styleSheet">
       <string notr="true">background-color: rgb(138, 226, 52);</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>636</width>
     <height>24</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

那么逻辑很简单:通过objectName获取QWidget,在本例中为"widget",然后在该widget中放置一个layout,然后通过layout将QChartView放置在widget中。

import random
import sys

from PySide2 import QtCore, QtGui, QtUiTools, QtWidgets
from PySide2.QtCharts import QtCharts


def ui_to_window(filename, parent=None):
    file = QtCore.QFile(filename)
    if not file.open(QtCore.QFile.ReadOnly):
        return
    loader = QtUiTools.QUiLoader()
    window = loader.load(file, parent)
    return window


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = ui_to_window("design.ui")
    window.widget.setContentsMargins(0, 0, 0, 0)
    lay = QtWidgets.QVBoxLayout(window.widget)
    lay.setContentsMargins(0, 0, 0, 0)

    chartview = QtCharts.QChartView()
    chartview.setContentsMargins(0, 0, 0, 0)
    lay.addWidget(chartview)

    series = QtCharts.QLineSeries()

    for i in range(10):
        series << QtCore.QPointF(i, random.uniform(0, 10))

    # Create Chart and set General Chart setting
    chart = QtCharts.QChart()
    chart.addSeries(series)
    chart.setAnimationOptions(QtCharts.QChart.SeriesAnimations)

    # X Axis Settings
    axisX = QtCharts.QValueAxis()
    chart.addAxis(axisX, QtCore.Qt.AlignBottom)
    series.attachAxis(axisX)

    # Y Axis Settings
    axisY = QtCharts.QValueAxis()
    chart.addAxis(axisY, QtCore.Qt.AlignLeft)
    series.attachAxis(axisY)

    chartview.setChart(chart)

    window.show()
    sys.exit(app.exec_())


QChartView 推广:

如果您仍想使用提升方法,那么如果类名是 QChartView,则必须通过返回 QChartView 实现自定义 QUiLoader 覆盖 createWidget 方法:

import random
import sys

from PySide2 import QtCore, QtGui, QtUiTools, QtWidgets
from PySide2.QtCharts import QtCharts


class UiLoader(QtUiTools.QUiLoader):
    def createWidget(self, className, parent=None, name=""):
        if className == "QChartView":
            return QtCharts.QChartView(parent)
        return super().createWidget(className, parent, name)


def ui_to_window(filename, parent=None):
    file = QtCore.QFile(filename)
    if not file.open(QtCore.QFile.ReadOnly):
        return
    loader = UiLoader()
    window = loader.load(file, parent)
    return window


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = ui_to_window("Pico_LaserCal_MainWindow.ui")
    series = QtCharts.QLineSeries()

    for i in range(10):
        series << QtCore.QPointF(i, random.uniform(0, 10))

    # Create Chart and set General Chart setting
    chart = QtCharts.QChart()
    chart.addSeries(series)
    chart.setAnimationOptions(QtCharts.QChart.SeriesAnimations)

    # X Axis Settings
    axisX = QtCharts.QValueAxis()
    chart.addAxis(axisX, QtCore.Qt.AlignBottom)
    series.attachAxis(axisX)

    # Y Axis Settings
    axisY = QtCharts.QValueAxis()
    chart.addAxis(axisY, QtCore.Qt.AlignLeft)
    series.attachAxis(axisY)

    window.calibrationChart.setChart(chart)

    window.show()
    sys.exit(app.exec_())