「C MAGAZINE - Qt GUI プログラミング」のコード移植 第2章
昨日の続きのネタが、仮想マシンのCent OSを起動するのが面倒になったので、ホストOSのWindows 7にPythonとPyQt4をインストールした。
第2章のサンプル
FindDialog
良くある文字列検索ダイアログ。
from PyQt4.QtCore import * from PyQt4.QtGui import * class FindDialog(QDialog): findNext = pyqtSignal(QString, bool) findPrev = pyqtSignal(QString, bool) def __init__(self, parent=None): super(FindDialog, self).__init__(parent) self.setWindowTitle("Find") self.label = QLabel("Find &what:", self) self.lineEdit = QLineEdit(self) self.label.setBuddy(self.lineEdit) self.caseCheckBox = QCheckBox("Match &case", self) self.backwardCheckBox = QCheckBox("Search &backward", self) self.findButton = QPushButton("&Find", self) self.findButton.setDefault(True) self.findButton.setEnabled(False) self.closeButton = QPushButton("Close", self) self.lineEdit.textChanged.connect(self.enableFindButton) self.findButton.clicked.connect(self.findClicked) self.closeButton.clicked.connect(self.close) topLeftLayout = QHBoxLayout() topLeftLayout.addWidget(self.label) topLeftLayout.addWidget(self.lineEdit) leftLayout = QVBoxLayout() leftLayout.addLayout(topLeftLayout) leftLayout.addWidget(self.caseCheckBox) leftLayout.addWidget(self.backwardCheckBox) rightLayout = QVBoxLayout() rightLayout.addWidget(self.findButton) rightLayout.addWidget(self.closeButton) rightLayout.addStretch(1) mainLayout = QHBoxLayout(self) mainLayout.setMargin(11) mainLayout.setSpacing(6) mainLayout.addLayout(leftLayout) mainLayout.addLayout(rightLayout) def findClicked(self): text = self.lineEdit.text() caseSensitive = self.caseCheckBox.isChecked() if self.backwardCheckBox.isChecked(): self.findPrev.emit(text, caseSensitive) else: self.findNext.emit(text, caseSensitive) def enableFindButton(self, text): self.findButton.setEnabled(text != "") if __name__ == '__main__': def prevSearch(text, caseSensitive): print "prevSearch: %s, %d" % (text, caseSensitive) def nextSearch(text, caseSensitive): print "nextSearch: %s, %d" % (text, caseSensitive) import sys app = QApplication(sys.argv) dialog = FindDialog() dialog.findPrev.connect(prevSearch) dialog.findNext.connect(nextSearch) dialog.show() app.exec_()
Employee
これも良く見る社員管理クラス。GUIには関係なくシグナル/スロットが使える。
from PyQt4.QtCore import * from PyQt4.QtGui import * class Employee(QObject): salaryChanged = pyqtSignal(int) def __init__(self): super(Employee, self).__init__() self.mySalary = 0 def salary(self): return self.mySalary def setSalary(self, newSalary): if newSalary != self.mySalary: self.mySalary = newSalary self.salaryChanged.emit(self.mySalary) if __name__ == '__main__': def print_salary(salary): print "salary: %d\n" % salary import sys app = QApplication(sys.argv) emp = Employee() emp.salaryChanged.connect(print_salary) emp.setSalary(100) emp.setSalary(100)
GotoCellDialogTmpl
Qt Designerで作った初めてのUIテンプレート。
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>GotoCellDialogTmpl</class> <widget class="QDialog" name="GotoCellDialogTmpl"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>260</width> <height>84</height> </rect> </property> <property name="windowTitle"> <string>Go to Cell</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QLabel" name="label"> <property name="text"> <string>&Call Location</string> </property> <property name="buddy"> <cstring>lineEdit</cstring> </property> </widget> </item> <item> <widget class="QLineEdit" name="lineEdit"/> </item> </layout> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>58</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="okButton"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>OK</string> </property> <property name="default"> <bool>true</bool> </property> </widget> </item> <item> <widget class="QPushButton" name="cancelButton"> <property name="text"> <string>Cancel</string> </property> </widget> </item> </layout> </item> </layout> </widget> <tabstops> <tabstop>lineEdit</tabstop> <tabstop>okButton</tabstop> <tabstop>cancelButton</tabstop> </tabstops> <resources/> <connections> <connection> <sender>okButton</sender> <signal>clicked()</signal> <receiver>GotoCellDialogTmpl</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>116</x> <y>59</y> </hint> <hint type="destinationlabel"> <x>129</x> <y>41</y> </hint> </hints> </connection> <connection> <sender>cancelButton</sender> <signal>clicked()</signal> <receiver>GotoCellDialogTmpl</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>207</x> <y>59</y> </hint> <hint type="destinationlabel"> <x>129</x> <y>41</y> </hint> </hints> </connection> </connections> </ui>
GotoCellDialog
任意セルへ移動するためのダイアログ。
pyuic4 -o gotocelldialogtmpl.py gotocelldialogtmpl.ui
コンパイルしたコードを使用したダイアログ。
from PyQt4.QtCore import * from PyQt4.QtGui import * from gotocelldialogtmpl import * class GotoCellDialog(QDialog, Ui_GotoCellDialogTmpl): def __init__(self, parent=None): super(GotoCellDialog, self).__init__(parent) self.setupUi(self) self.lineEdit.textChanged.connect(self.enableOkButton) regExp = QRegExp("[A-Za-z][1-9][0-9]{0,2}") self.lineEdit.setValidator(QRegExpValidator(regExp, self)) def enableOkButton(self): self.okButton.setEnabled(self.lineEdit.hasAcceptableInput()) if __name__ == "__main__": import sys app = QApplication(sys.argv) dialog = GotoCellDialog() dialog.show() app.exec_()
SortDialogTmpl
並べ替えダイアログのUIテンプレート。
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>SortDialog</class> <widget class="QDialog" name="SortDialog"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>283</width> <height>340</height> </rect> </property> <property name="mouseTracking"> <bool>false</bool> </property> <property name="windowTitle"> <string>Sort</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <property name="sizeConstraint"> <enum>QLayout::SetFixedSize</enum> </property> <item row="0" column="0"> <widget class="QGroupBox" name="primaryGroupBox"> <property name="title"> <string>&Primary Key</string> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QLabel" name="primaryColumLabel"> <property name="text"> <string>Column</string> </property> </widget> </item> <item row="0" column="1" rowspan="2"> <widget class="QComboBox" name="primaryColumnCombo"> <item> <property name="text"> <string>None</string> </property> </item> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="primaryOrderLabel"> <property name="text"> <string>Order</string> </property> </widget> </item> <item row="0" column="2"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>33</width> <height>20</height> </size> </property> </spacer> </item> <item row="3" column="1" colspan="2"> <widget class="QComboBox" name="primaryOrderCombo"> <item> <property name="text"> <string>Ascending</string> </property> </item> <item> <property name="text"> <string>Descending</string> </property> </item> </widget> </item> </layout> </widget> </item> <item row="0" column="1" rowspan="2"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QPushButton" name="okButton"> <property name="text"> <string>OK</string> </property> <property name="default"> <bool>true</bool> </property> </widget> </item> <item> <widget class="QPushButton" name="cancelButton"> <property name="text"> <string>Cancel</string> </property> </widget> </item> <item> <spacer name="verticalSpacer_2"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>18</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="moreButton"> <property name="text"> <string>&More</string> </property> <property name="checkable"> <bool>true</bool> </property> </widget> </item> </layout> </item> <item row="1" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>7</height> </size> </property> </spacer> </item> <item row="2" column="0"> <widget class="QGroupBox" name="secondaryGroupBox"> <property name="title"> <string>&Secondary Key</string> </property> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QLabel" name="secondaryColumnLabel"> <property name="text"> <string>Column</string> </property> </widget> </item> <item row="0" column="1" rowspan="2"> <widget class="QComboBox" name="secondaryColumnCombo"> <item> <property name="text"> <string>None</string> </property> </item> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="sconaryOrderLabel"> <property name="text"> <string>Order</string> </property> </widget> </item> <item row="0" column="2"> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>33</width> <height>20</height> </size> </property> </spacer> </item> <item row="3" column="1" colspan="2"> <widget class="QComboBox" name="secondaryOrderCombo"> <item> <property name="text"> <string>Ascending</string> </property> </item> <item> <property name="text"> <string>Descending</string> </property> </item> </widget> </item> </layout> </widget> </item> <item row="3" column="0"> <widget class="QGroupBox" name="tertiaryGroupBox"> <property name="title"> <string>&Tertiary Key</string> </property> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <widget class="QLabel" name="tertiaryComunLabel"> <property name="text"> <string>Column</string> </property> </widget> </item> <item row="0" column="1" rowspan="2"> <widget class="QComboBox" name="tertiaryColumnCombo"> <item> <property name="text"> <string>None</string> </property> </item> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="tertiaryOrderLabel"> <property name="text"> <string>Order</string> </property> </widget> </item> <item row="0" column="2"> <spacer name="horizontalSpacer_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>33</width> <height>20</height> </size> </property> </spacer> </item> <item row="3" column="1" colspan="2"> <widget class="QComboBox" name="tertiaryOrderCombo"> <item> <property name="text"> <string>Ascending</string> </property> </item> <item> <property name="text"> <string>Descending</string> </property> </item> </widget> </item> </layout> </widget> </item> </layout> </widget> <tabstops> <tabstop>primaryColumnCombo</tabstop> <tabstop>primaryOrderCombo</tabstop> <tabstop>secondaryColumnCombo</tabstop> <tabstop>secondaryOrderCombo</tabstop> <tabstop>tertiaryColumnCombo</tabstop> <tabstop>tertiaryOrderCombo</tabstop> <tabstop>okButton</tabstop> <tabstop>cancelButton</tabstop> <tabstop>moreButton</tabstop> </tabstops> <resources/> <connections> <connection> <sender>okButton</sender> <signal>clicked()</signal> <receiver>SortDialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>230</x> <y>23</y> </hint> <hint type="destinationlabel"> <x>141</x> <y>170</y> </hint> </hints> </connection> <connection> <sender>cancelButton</sender> <signal>clicked()</signal> <receiver>SortDialog</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>230</x> <y>57</y> </hint> <hint type="destinationlabel"> <x>141</x> <y>170</y> </hint> </hints> </connection> <connection> <sender>moreButton</sender> <signal>toggled(bool)</signal> <receiver>secondaryGroupBox</receiver> <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> <x>230</x> <y>108</y> </hint> <hint type="destinationlabel"> <x>94</x> <y>178</y> </hint> </hints> </connection> <connection> <sender>moreButton</sender> <signal>toggled(bool)</signal> <receiver>tertiaryGroupBox</receiver> <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> <x>230</x> <y>108</y> </hint> <hint type="destinationlabel"> <x>94</x> <y>282</y> </hint> </hints> </connection> </connections> </ui>
SortDialog
拡張機能付き検索ダイアログ。
from PyQt4.QtCore import * from PyQt4.QtGui import * from sortdialogtmpl import * class SortDialog(QDialog, Ui_SortDialog): def __init__(self, parent=None): super(SortDialog, self).__init__(parent) self.setupUi(self) self.secondaryGroupBox.hide() self.tertiaryGroupBox.hide() self.setColumnRange('A', 'Z') def setColumnRange(self, first, last): self.primaryColumnCombo.clear() self.secondaryColumnCombo.clear() self.tertiaryColumnCombo.clear() self.secondaryColumnCombo.addItem("None") self.tertiaryColumnCombo.addItem("None") self.primaryColumnCombo.setMinimumSize(self.secondaryColumnCombo.sizeHint()) ch = ord(first) ch_last = ord(last) while ch <= ch_last: s = chr(ch) self.primaryColumnCombo.addItem(s) self.secondaryColumnCombo.addItem(s) self.tertiaryColumnCombo.addItem(s) ch = ch + 1 if __name__ == '__main__': import sys app = QApplication(sys.argv) dialog = SortDialog() dialog.setColumnRange('C', 'F') dialog.show() app.exec_()