1

I am learning Qt and how to create GUIs with python. I managed to create my own Qt files and fill it with buttons and other simple things, but now I found this amazing attitude indicator

This ai.py file contains an attitude widget that I would like to import in my own GUI. So I designed my .ui file with an empty widget named "viz_widget", then I wrote this python file

# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtCore, QtGui, uic
from ai import AttitudeIndicator

qtCreatorFile1 = "mainwindow.ui" # Enter file here.


Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile1)


class OperatorGUI(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(OperatorGUI, self).__init__(parent)
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        self.viz_widget = AttitudeIndicator()
        self.viz_widget.setPitch(10)
        self.viz_widget.setRoll(20)
        self.viz_widget.setHover(500/10.)
        self.viz_widget.setBaro(500/10.)   
        self.viz_widget.update()

    # Key press functions
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Q: #Q: close the window
            print "pressed Q: exit by keyboard"
            self.close()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = OperatorGUI()
    window.show()
    sys.exit(app.exec_())

The GUI is launched, there aren't any errors, but I can not display the attitude widget into my GUI. Is it possible to import the widget? What is my error?

Thank you in advance

EDIT: this is the file maiwindow.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>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QWidget" name="viz_widget" native="true">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>40</y>
      <width>671</width>
      <height>441</height>
     </rect>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>
8
  • You probably just need to add the widget to the window's layout - or rather, to the layout of its central widget. Commented Sep 1, 2017 at 13:49
  • @ekhumoro I added a widget in my window (ui.file) named viz_widget in QtCreator. Then I connected it to the object AttitudeIndicator in the line self.viz_widget = AttitudeIndicator(). Do I have to do something more or something different? Commented Sep 1, 2017 at 14:02
  • Firstly: get rid of those two __init__ calls - they are not needed if you use super. Secondly, remove the widget you added in QtCreator, so you just have an empty main-window (and save the changes). Then add this line to the end of __init__: layout = QtGui.QVBoxLayout(self.centralWidget()). Finally, add the widget to the layout: layout.addWidget(self.viz_widget). Commented Sep 1, 2017 at 14:17
  • @ekhumoro Thank you. I will work on that (your first command seems to give error to me) but I would like to ask if it is possible (at least in theory) to insert this external widget in my GUI (in the place where I put the "empty" widget) Commented Sep 1, 2017 at 15:12
  • If you want to literally replace a widget at runtime, you can use widget promotion. See this answer for an example of how to do this. Commented Sep 1, 2017 at 15:37

1 Answer 1

1

Here's the steps needed to add an AttitudeIndicator widget both in code, and via promotion in Qt Designer.

Firstly, you will need to make some changes to the "mainwindow.ui" file. So, in Qt designer, click on the central-widget in the Object Inspector, and then in the Property Editor, change the objectName to central_widget. This is important, because the current name is shadowing the QMainWindow.centralWidget() method that we need to use later. Secondly, with the central-widget still selected, click Lay Out Horizontally on the toolbar (the icon has three blue vertical bars) - and save the changes.

Now right-click the viz_widget (either in the Object Inspector or on the form), choose Promote to ..., and enter MyAttitudeIndicator in Promoted class name, and ai_widget in Header file. Then click Add and Promote - and save the changes. After doing that, you should see the Class change from QWidget to MyAttitudeIndicator in the Object Inspector. (But note that the actual widget on the form will not be displayed as an AttitudeIndicator. To do that, you'd need to write a custom designer plugin, which goes way beyond the scope of this question).

To make use of these changes, some code needs to be added. Firstly, you need to create a module called ai_widget.py for the promoted widget class. The module should contain this code:

from ai import AttitudeIndicator

class MyAttitudeIndicator(AttitudeIndicator):
    def __init__(self, parent, hz=30):
        super(MyAttitudeIndicator, self).__init__(hz=hz)
        self.setParent(parent)

The main reason why this class is needed is because the original AttitudeIndicator has a buggy API. The constructor really needs to take a parent widget (which is fixed in the above code). However, you could also use this class to add your own custom features.

The final step is to add some changes to the main script, which is shown below. Note that all the widgets added in Qt Designer will become attributes of the object passed to setupUi() (i.e. the main-window, self, in this case).

import sys
from PyQt4 import QtCore, QtGui, uic
from ai import AttitudeIndicator

qtCreatorFile1 = "mainwindow.ui" # Enter file here.

Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile1)

class OperatorGUI(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(OperatorGUI, self).__init__(parent)
        self.setupUi(self)

        # promoted widget from qt designer
        self.viz_widget.setPitch(10)
        self.viz_widget.setRoll(20)
        self.viz_widget.setHover(500/10.)
        self.viz_widget.setBaro(500/10.)

        # optional second widget
        self.viz_widget2 = AttitudeIndicator()
        self.viz_widget2.setPitch(10)
        self.viz_widget2.setRoll(-40)
        layout = self.centralWidget().layout()
        layout.addWidget(self.viz_widget2)

    # Key press functions
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Q: #Q: close the window
            print "pressed Q: exit by keyboard"
            self.close()

if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)
    window = OperatorGUI()
    window.show()
    sys.exit(app.exec_())
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much. The second strategy works wonderfully (maybe the central widget name made the trick). Promotion seems very interesting but it still does not work and give me this error super(MyAttitudeIndicator, self).__init__(hz=hz) TypeError: __init__() got an unexpected keyword argument 'hz'. I have no clue about hz. But you found at least one solution working and I accept the answer and thank you again for your help.
@marcoresk. No problem. I used the current "ai.py" from github, which has that hz argument. My code has been thoroughly tested, so I know it all works correctly.
I discovered that, with no awareness, deleting hz=hz in ai_widget the promotion seems to work (at least it appears in the GUI). Thank you again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.