Getting PySide2 QCharts to show up when using Qt Designer

Question:

I’ve have a similar problem to the question here: How to insert QChartView in form with Qt Designer?

So I created my MainWindow of my UI in Qt Designer and I’m trying to get a QtChart to show up inside one of the tabs in my window. I’m importing the .ui file into a python program, and so far I can get the main window to display fine, but not the chart. I’ve spent most of the day trying to follow the instructions listed in the above answer, but so far I haven’t been able to get my promoted widget to correctly import into my main program. I’ve been wondering if part of the reason is that I’m trying do this in the python version of Qt (i.e. PySide2) instead of the C++ version this answer was probably written for.

I’ve tried using both a QWidget and the recommended QGraphicsView as my base to promote my QChartView to, but so far every attempt gives me an error that reads:
"QFormBuilder was unable to create a custom widget of the class 'QChartView'; defaulting to base class 'QWidget'." What am I doing wrong?

Like the linked question/answer states, I set my promoted widget with a "Promoted Class Name" of QChartView and the "Header File" to QtCHarts. Below is the base code of my Python program (ignore my weird imports at the beginning, as that’s a separate issue I’m dealing with where my program won’t find the class imports unless I format them that way.)

Any help would be greatly appreciated! Thanks!

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

[EDIT]: Here is the .ui file code that I’m loading, as requested. It’s not the full file as the original is too long to post, but it should be enough to get the idea:

<?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>

Asked By: AWheeler

||

Answers:

QWidget as a container:

In this case I do not recommend applying the promotion because it complicates the task a lot but I will show how to apply the solution shown in my other answer: Use a QWidget as a container in the .ui.

For the example I have created a .ui with several components and where you want to place the QChartView, place a QWidget (to make it visible I have set a green background color):

enter image description here

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>

Then the logic is simple: get the QWidget through the objectName which in this case is “widget”, then place a layout inside that widget, and then place the QChartView inside the widget through the layout.

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

enter image description here


QChartView Promotion:

If you still want to use the promotion method then you must implement a custom QUiLoader override the createWidget method by returning the QChartView if the className is QChartView:

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_())
Answered By: eyllanesc

The simplest way for promotion of QGraphicsView to QChartView in Qt Designer I could come up with is:

  1. create a QChartViewPointer.py file and place it next to your main.py file

  2. write only 2 lines in the QChartViewPointer.py file:

from PySide2.QtCharts import QtCharts
QChartView=QtCharts.QChartView

this code creates a QChartView variable that points to the QtCharts.QChartView class

  1. in Qt Designer, add QGraphicsView to the form (you can also use QWidget, but I prefer QGraphicsView, since QChartView inherits from QGraphicsView)

  2. Right click on the QGraphicsView and select Promote to…

5.Set:

Promoted Class Name: QChartView (QChartView is a variable from the QChartViewPointer.py file that points to the QtCharts.QChartView class)

Header file: QChartViewPointer.h (QChartViewPointer.h is the name of the file where the QChartView variable is declared. Instead of py write h – this is the syntax of the C ++ language in which PySide is written)

then press the add button and finally press promote.

Answered By: Nikolas