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.
First, create a test widget that works with PyQt in the designer. The appearance is 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.
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.
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. 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.
signal, property
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.
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 You will be able to specify label_text like this.
Recommended Posts