Create Qt designer parts in Python (PyQt)

This is a memo of how to create a widget in PyQt and use it on Qt designer. It also includes the implementation of signal and slot as functions. The example uses Qt4, but it's basically the same with Qt5 (although some modifications are needed). I searched on the net, but it didn't hit easily, so I think it will be helpful. Some of the terms have been arbitrarily named by me, so I would appreciate it if you could point out any terms that deviate from the Qt rules.

Things to prepare

  1. Widget that works with PyQt.
  2. Python file for defining plugins Only these two.

Creating widget

First, create a test widget that works with PyQt in the designer. The appearance is preview.png It looks like. QLavel, QTextInput, QPushbutton are laid out in QHBoxLayout. The object name is TextInp. The clicked signal of the QPushButton is connected to the clear of QTextInput and the getPressed slot of Form. The getPressed slot was created on the designer. Save this to the ui_textinp.ui file.


<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>TextInp</class>
 <widget class="QWidget" name="TextInp">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>62</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QWidget" name="horizontalLayoutWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>391</width>
     <height>61</height>
    </rect>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QLabel" name="label">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QLineEdit" name="lineEdit"/>
    </item>
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text">
       <string>PushButton</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>pushButton</sender>
   <signal>clicked()</signal>
   <receiver>lineEdit</receiver>
   <slot>clear()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>358</x>
     <y>31</y>
    </hint>
    <hint type="destinationlabel">
     <x>238</x>
     <y>32</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>pushButton</sender>
   <signal>clicked()</signal>
   <receiver>TextInp</receiver>
   <slot>getPressed()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>383</x>
     <y>31</y>
    </hint>
    <hint type="destinationlabel">
     <x>394</x>
     <y>51</y>
    </hint>
   </hints>
  </connection>
 </connections>
 <slots>
  <slot>getPressed()</slot>
 </slots>
</ui>

This ui file using pyuic4

$ pyuic4 ui_textinp.ui > ui_textinp.py

Convert to. A class named Ui_TextInp will be generated in the generated python file. This name comes from the object name TextInp.

Next, create an application in which this widget works independently. With the name textinp.py

#!/usr/bin/env python

import PyQt4
from PyQt4 import QtCore,QtGui
from PyQt4.QtGui import QApplication,QWidget,QVBoxLayout
 
__version__ = '0.0.1'
 
from ui_textinp import Ui_TextInp
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s
    
class TextInp(QWidget, Ui_TextInp):
    def __init__(self, parent=None):
        super(TextInp, self).__init__(parent)
        self.setupUi(self)
        vBox = QVBoxLayout()
        vBox.addWidget(self.horizontalLayoutWidget)
        self.setLayout(vBox)
    @QtCore.pyqtSlot()
    def getPressed(self):
        print "PRESSED"
if __name__ == '__main__':
    app = QApplication(sys.argv)
    textinp = TextInp()
    textinp.show()
    sys.exit(app.exec_())

I don't think you need much commentary. The TextInp class inherits from Ui_TextInp. Without vBox, the size will not follow when you change the window size. You can see the implementation of slot. When the QPushButton is clicked, the getPressed function is called and the PRSSED string is displayed in the standard output. When you run

$ python textinp.py

The widget as shown above will be displayed, the character string entered in text will be cleared by pressing the button, and PRESSED will be displayed in the standard output.

Creation of plugin definition file

Now you have a widget that you can run with PyQt. You need another python file to import this as a designer part. Let's call this textinpplugin.py. The file is as follows.

#!/usr/bin/env python

"""
polygonwidgetplugin.py

A polygon widget custom widget plugin for Qt Designer.

Copyright (C) 2006 David Boddie <[email protected]>
Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
"""

from PyQt4 import QtGui, QtDesigner
from textinp import TextInp


class TextInpPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin):

    """TextInpPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin)
    Provides a Python custom plugin for Qt Designer by implementing the
    QDesignerCustomWidgetPlugin via a PyQt-specific custom plugin class.
    """

    # The __init__() method is only used to set up the plugin and define its
    # initialized variable.
    def __init__(self, parent=None):
    
        super(TextInpPlugin, self).__init__(parent)

        self.initialized = False

    # The initialize() and isInitialized() methods allow the plugin to set up
    # any required resources, ensuring that this can only happen once for each
    # plugin.
    def initialize(self, core):

        if self.initialized:
            return

        self.initialized = True

    def isInitialized(self):

        return self.initialized

    # This factory method creates new instances of our custom widget with the
    # appropriate parent.
    def createWidget(self, parent):
        return TextInp(parent)

    # This method returns the name of the custom widget class that is provided
    # by this plugin.
    def name(self):
        return "TextInp"

    # Returns the name of the group in Qt Designer's widget box that this
    # widget belongs to.
    def group(self):
        return "Example for Qiita"

    # Returns the icon used to represent the custom widget in Qt Designer's
    # widget box.
    def icon(self):
        return QtGui.QIcon(_logo_pixmap)

    # Returns a short description of the custom widget for use in a tool tip.
    def toolTip(self):
        return ""

    # Returns a short description of the custom widget for use in a "What's
    # This?" help message for the widget.
    def whatsThis(self):
        return ""

    # Returns True if the custom widget acts as a container for other widgets;
    # otherwise returns False. Note that plugins for custom containers also
    # need to provide an implementation of the QDesignerContainerExtension
    # interface if they need to add custom editing support to Qt Designer.
    def isContainer(self):
        return False

    # Returns an XML description of a custom widget instance that describes
    # default values for its properties. Each custom widget created by this
    # plugin will be configured using this description.
    def domXml(self):
        return '<widget class="TextInp" name="textinp" />\n'

    # Returns the module containing the custom widget class. It may include
    # a module path.
    def includeFile(self):
        return "textinp"


# Define the image used for the icon.
_logo_16x16_xpm = [
"16 16 3 1",
"a c #008000",
"# c #0080ff",
". c #ffffff",
"................",
"................",
"..#############.",
"..#############.",
"..#############.",
"..#############.",
"..#############.",
"..#############.",
"................",
"................",
"..aaaaaaaaaaaaa.",
"..aaaaaaaaaaaaa.",
"..aaaaaaaaaaaaa.",
"..aaaaaaaaaaaaa.",
"..aaaaaaaaaaaaa.",
"................"]

_logo_pixmap = QtGui.QPixmap(_logo_16x16_xpm)

I think that it can be applied by rewriting textinp and TextInp. The string returned by def group will be the designer's widget group. Also, the last _logo_16x16_xpm is an xpm format icon.

So far,

textinp.py
ui_textinp.py
textinpplugin.py

Three files are created.

Start designer

Of these, move the widget-related files to the widgets and plugin-related files to a subdirectory called python, define the environment variables PYQTDESIGNERPATH and PYTHONPATH, and start the designer.

$ mv  textinp.py ui_textinp.py widgets
$ mv  textinpplugin.py python
$ export PYQTDESIGNERPATH=python
$ export PYTHONPATH=widgets
$ designer

You should see a widget like the one below in the designer widget box. a.png Congratulations. The widget you created can now be used on the designer as well as any other widget.

Also, the getPressed slot defined above is also valid in the signal / slot editor on the designer. sigslot.png

signal, property

implementation of signal

Oops, I implemented slot, but signal wasn't there yet. Add it to textinp.py earlier. Write to generate (emit) a signal when getPressed is called. Write QtCore.pyqtSignal at the beginning of the class definition and call outText.emit ("TXT") when you want to call it.

class TextInp(QWidget, Ui_TextInp):
    outText=QtCore.pyqtSignal(str)
    def __init__(self, parent=None):
        super(TextInp, self).__init__(parent)
        self.setupUi(self)
        vBox = QVBoxLayout()
        vBox.addWidget(self.horizontalLayoutWidget)
        self.setLayout(vBox)
        self._label_text="Label text"
        self.label.setText(self._label_text)
    @QtCore.pyqtSlot()
    def getPressed(self):
        self.outText.emit(self.lineEdit.text())
        print self.lineEdit.text()

You can see that signal is implemented in the designer. sig2.png

Implementation of property

Textinp.py that implements property.

class TextInp(QWidget, Ui_TextInp):
    outText=QtCore.pyqtSignal(str)
    def __init__(self, parent=None):
        super(TextInp, self).__init__(parent)
        self.setupUi(self)
        vBox = QVBoxLayout()
        vBox.addWidget(self.horizontalLayoutWidget)
        self.setLayout(vBox)
        self._label_text="Label text"
        self.label.setText(self._label_text)
    @QtCore.pyqtSlot()
    def getPressed(self):
        self.outText.emit(self.lineEdit.text())
        print self.lineEdit.text()
    def setLabelText(self,inptxt):
        self._label_text=inptxt
        self.label.setText(self._label_text)
    def getLabelText(self):
        return self._label_text
    label_text=QtCore.pyqtProperty(str, getLabelText, setLabelText)

Define the setLabelText and getLabelText functions in QtCore.pyqtProperty. On the designer property_editor.png You will be able to specify label_text like this.

Recommended Posts

Create Qt designer parts in Python (PyQt)
Create SpatiaLite in Python
Create a function in Python
Create gif video in Python
[GUI in Python] PyQt5 -Widget-
[Maya Python] Display .ui created by Qt Designer in Maya
Introducing GUI: PyQt5 in Python
[GUI in Python] PyQt5 -Event-
Create a DI Container in Python
Create a binary file in Python
Create Gmail in Python without API
Create Python project documentation in Sphinx
Create a Kubernetes Operator in Python
Create a random string in Python
Create and read messagepacks in Python
Create your own Linux commands in Python
Create ScriptableObject in Python when building ADX2
[LLDB] Create your own command in Python
Create a simple GUI app in Python
Create a JSON object mapper in Python
[GPS] Create a kml file in Python
Quadtree in Python --2
CURL in python
Metaprogramming in Python
Create a Vim + Python test environment in 1 minute
Python 3.3 in Anaconda
Geocoding in python
SendKeys in Python
Create a GIF file using Pillow in Python
Meta-analysis in Python
Unittest in python
I want to create a window in Python
How to create a JSON file in Python
Automatically create word and excel reports in python
Create a virtual environment with conda in Python
Discord in Python
Sudoku in Python
DCI in Python
quicksort in python
nCr in python
N-Gram in Python
Programming in python
Create a color bar with Python + Qt (PySide)
Plink in Python
Constant in python
Create an image with characters in python (Japanese)
Create a simple momentum investment model in Python
Lifegame in Python.
FizzBuzz in Python
Sqlite in python
StepAIC in Python
Create a new page in confluence with Python
Create a color-specified widget with Python + Qt (PySide)
Create a datetime object from a string in Python (Python 3.3)
N-gram in python
LINE-Bot [0] in Python
Create a package containing global commands in Python
Csv in python
Disassemble in Python
Reflection in Python
Constant in python