Create GUI in Python using Qt 2

Introduction

This notebook continues QtGui1

In Example 2 a MainWindow with a menubar is created and in Exercise 2 a this example is extended to a GUI for a WEFileIO class

Example 2

In this example a MainWindow with menubar is created. Use this example if menubar, toolbar and/or statusbar are required

Create ui

  • Open Qt Designer and create new "MainWindow"
  • Add "PushButton" to "MainWindow"
  • Set the text to "Open" (double click on button or enter in property editor)

Add action

  • Create new action in Action Editor
    • Text: "Open"
    • ObjectName: "actionOpen" (default)
    • Shortcut: Ctrl+O
    • ToolTip: "Open a file"

Connect action to PushButton

  • Add Signal/Slot in Signal/Slot Editor
    • Sender: pushButton
    • Signal: clicked()
    • Receiver: actionOpen
    • Slot: trigger()

Connect action to menu

  • Create a File menu by:
    • Doubleclick on “Type Here” in the menubar of the window
    • Type "File" + Enter
  • Drag actionOpen from Action Editor to the menu

Integrate into Python

  • Save as “MyUI/MyMainWindowUI.ui” in the same folder as this notebook
  • Create an empty "MyUI/MyMainWindowUI.py" file in the same folder (This is required in order to import the widget. Its content will be autogenerated if the file is completely empty or older than "MyUI/MyMainWindowUI.ui"

When loading via QtMainWindowLoader, actions are automatically connected to methods of the same name.

All PyQt elements are found in the ui-object, e.g. self.ui.pushButton and documentation of the PyQt elements is found at http://pyqt.sourceforge.net/Docs/PyQt4/classes.html

In order to integrate MyMainWindowUI in Python, subclass QtMainWindowLoader from QtGuiLoader and instantiate with MyMainWindowUI as ui_module argument.

In this example the action actionOpen can be invoked by:

  • The menu
  • Its shortcut (Ctrl+O)
  • The pushButton

Check out the body of actionOpen. What will happen?

Try it


In [2]:
import MyUI.MyMainWindowUI
from QtGuiLoader import QtMainWindowLoader
from PyQt4 import QtGui

class MyMainWindowWithMenu(QtMainWindowLoader):
    def __init__(self):
        try: self.ui = MyUI.MyMainWindowUI.Ui_Form() # Enables autocompletion (maybe...)
        except: pass
        QtMainWindowLoader.__init__(self, MyUI.MyMainWindowUI)
    
    def actionOpen(self):
        filename = str(QtGui.QFileDialog.getOpenFileName(self, "Open...", ".", "*.*"))
        if filename == "": return #cancel
        print filename

MyMainWindowWithMenu().start()

Exercise 2

In this exercise we will make a GUI for our WEFileIO project by extending the mainwindow from example 2 with a few widgets and the MyPlotControlUI from exercise 1

  • Open MyMainWindowUI in QtDesigner
  • Save it as "MyPlotMainWindowUI"
  • Add a Horisontal Layout to the window
  • Add a Horisontal Spacer to the horisontal layout
  • Add a Grid Layout to the horisontal layout, on the left side of the spacer
  • Set layoutName of grid layout to "gridLayoutPlot"
  • Add a Vertical Layout to the horisontal layout, on the right side of the spacer
  • Delete the spacer
  • Drag the "Open"-PushButton and drop it at the vertical layout
  • Add a Grid Layout below the "Open"-PushButton
  • Set layoutName of grid layout to "gridLayoutControl"
  • Right-click the form: Layout - Layout in a grid
  • Select horisontal layout and set layoutStretch to "1,0"

  • Create an empty "MyPlotMainWindowUI.py" file in the same folder

In [1]:
from QtGuiLoader import QtWidgetLoader
import MyUI.MyPlotControlUI
class MyPlotControlWidget(QtWidgetLoader):
    def __init__(self, we_file_io):
        try:self.ui = MyUI.MyPlotControlUI.Ui_Form() # Enables autocompletion (if you are lucky...)
        except: pass
        QtWidgetLoader.__init__(self, ui_module=MyUI.MyPlotControlUI)
        self.we_file_io = we_file_io
                
        #Connect widget signals to actionUpdatePlot
        self.ui.xLineEdit.editingFinished.connect(self.actionUpdatePlot)
        self.ui.yLineEdit.editingFinished.connect(self.actionUpdatePlot)
        self.ui.colorComboBox.currentIndexChanged.connect(self.actionUpdatePlot)
        self.ui.horizontalSlider.valueChanged.connect(self.actionUpdatePlot)
        self.ui.spinBox.valueChanged.connect(self.actionUpdatePlot)
        self.ui.doubleSpinBox.valueChanged.connect(self.actionUpdatePlot)

        
    x_str = property(lambda self : str(self.ui.xLineEdit.text()))
    y_str = property(lambda self : str(self.ui.yLineEdit.text()))
    color = property(lambda self : str(self.ui.colorComboBox.currentText()))
    width = property(lambda self : self.ui.horizontalSlider.value())
    ylim = property(lambda self : (self.ui.spinBox.value(), self.ui.doubleSpinBox.value()))
    
    def actionUpdatePlot(self):
        self.we_file_io.plot()

In [2]:
import sys
sys.path.append("../py4we") # append py4we package to path to access WEFileIO

from we_file_io import WEFileIO
import numpy as np
class MyPlotFileIO(WEFileIO):
    title = "No title"
    def __init__(self, mpl_widget):
        WEFileIO.__init__(self, file_type_name = "Exercise2file", file_extension = ".title")
        self.figure = mpl_widget.figure
        self.ui_control = MyPlotControlWidget(self)
        self.plot()

    def _read(self):
        with open(self.filename, 'r') as f:
            self.title = f.read()
        self.plot()
    
    def _plot(self, fig):
        axes = fig.axes[0]
        x = eval(self.ui_control.x_str)
        y = eval(self.ui_control.y_str)
        axes.plot(x,y, self.ui_control.color, linewidth=self.ui_control.width)
        axes.set_ylim(self.ui_control.ylim)
        axes.set_title(self.title)
        fig.canvas.draw()

In [3]:
import MyUI.MyPlotMainWindowUI
from QtGuiLoader import QtMainWindowLoader
from matplotlibwidget import MatplotlibWidget
from PyQt4 import QtGui

class MyPlotMainWindow(QtMainWindowLoader):
    def __init__(self):
        module = MyUI.MyPlotMainWindowUI
        try:self.ui = module.Ui_Form() # Enables autocompletion (if you are lucky...)
        except: pass
        QtMainWindowLoader.__init__(self, module)
        mpl = MatplotlibWidget()
        self.ui.gridLayoutPlot.addWidget(mpl)
        self.fileio = MyPlotFileIO(mpl)
        self.ui.gridLayoutControl.addWidget(self.fileio.ui_control)
        
    
    def actionOpen(self):
        filename = str(QtGui.QFileDialog.getOpenFileName(self, "Open...", ".", "*%s" % self.fileio.file_extension))
        if filename == "": return #cancel
        self.fileio.read(filename)


MyPlotMainWindow().start()