PyQt5とpython3によるGUIプログラミング［２］

#**Buttonについて**
横一列にレイアウトしたボタンのサンプルです。
グループ化しています。
setFocusPolicy(Qt.NoFocus)でどれにもフォーカスをあてずにフラットにしています。
button1.setCheckable(True)としているものは、トグルボタンとして振舞います。
button1.setCheckable(True)がコメントになっているものは普通のボタンです。

```python:ButtonTest01.py
import sys

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class FormTest(QDialog):
    def __init__(self, parent=None):
        super(FormTest, self).__init__(parent)

        button1 = QPushButton("一")
        #button1.setCheckable(True)
        button1.setFocusPolicy(Qt.NoFocus)

        button2 = QPushButton("二")
        #button2.setCheckable(True)
        button2.setFocusPolicy(Qt.NoFocus)

        button3 = QPushButton("三")
        #button3.setCheckable(True)
        button3.setFocusPolicy(Qt.NoFocus)

        button4 = QPushButton("四")
        button4.setCheckable(True)
        button4.setFocusPolicy(Qt.NoFocus)

        button5 = QPushButton("五")
        button5.setCheckable(True)
        button5.setFocusPolicy(Qt.NoFocus)

        self.group = QButtonGroup()
        self.group.addButton(button1,1)
        self.group.addButton(button2,2)
        self.group.addButton(button3,3)
        self.group.addButton(button4,4)
        self.group.addButton(button5,5)

        self.label = QLabel("ラジオボタンをクリックしてください")

        #QHboxLayout()は、Horizonal(水平方向に)レイアウトします
        layout = QHBoxLayout()

        layout.addWidget(button1)
        layout.addWidget(button2)
        layout.addWidget(button3)
        layout.addWidget(button4)
        layout.addWidget(button5)


        #QVBoxLayout()は、vertical（垂直方向）にレイアウトします
        Vlayout = QVBoxLayout()

        Vlayout.addWidget(self.label)
        Vlayout.addLayout(layout)

        self.setLayout(Vlayout)

        button1.clicked.connect(self.clicked)
        button2.clicked.connect(self.clicked)
        button3.clicked.connect(self.clicked)
        button4.clicked.connect(self.clicked)
        button5.clicked.connect(self.clicked)

    def clicked(self):
        button = self.sender()
        if button is None or not isinstance(button,QPushButton):
            return
        self.label.setText("あなたは '%s' のラジオボタンをクリックしました" % button.text())

app = QApplication(sys.argv)
formtest = FormTest()
formtest.show()
app.exec_()
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/16347122-f0f9-889f-89f6-253eca060d5f.png)


#**RadioButtonの場合**
RadioButtonになっていること以外は、上のButtonの場合と同じです。

```python:rdiobutton01.py
import sys

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class FormTest(QDialog):
    def __init__(self, parent=None):
        super(FormTest, self).__init__(parent)

        radiobutton1 = QRadioButton("一")
        radiobutton1.setCheckable(True)
        radiobutton1.setFocusPolicy(Qt.NoFocus)

        radiobutton2 = QRadioButton("二")
        radiobutton2.setCheckable(True)
        radiobutton2.setFocusPolicy(Qt.NoFocus)

        radiobutton3 = QRadioButton("三")
        radiobutton3.setCheckable(True)
        radiobutton3.setFocusPolicy(Qt.NoFocus)

        radiobutton4 = QRadioButton("四")
        radiobutton4.setCheckable(True)
        radiobutton4.setFocusPolicy(Qt.NoFocus)

        radiobutton5 = QRadioButton("五")
        radiobutton5.setCheckable(True)
        radiobutton5.setFocusPolicy(Qt.NoFocus)

        self.group = QButtonGroup()
        self.group.addButton(radiobutton1,1)
        self.group.addButton(radiobutton2,2)
        self.group.addButton(radiobutton3,3)
        self.group.addButton(radiobutton4,4)
        self.group.addButton(radiobutton5,5)

        self.label = QLabel("ラジオボタンをクリックしてください")

        layout = QHBoxLayout()

        layout.addWidget(radiobutton1)
        layout.addWidget(radiobutton2)
        layout.addWidget(radiobutton3)
        layout.addWidget(radiobutton4)
        layout.addWidget(radiobutton5)

        Vlayout = QVBoxLayout()

        Vlayout.addWidget(self.label)
        Vlayout.addLayout(layout)

        self.setLayout(Vlayout)

        radiobutton1.clicked.connect(self.clicked)
        radiobutton2.clicked.connect(self.clicked)
        radiobutton3.clicked.connect(self.clicked)
        radiobutton4.clicked.connect(self.clicked)
        radiobutton5.clicked.connect(self.clicked)

    def clicked(self):
        radiobutton = self.sender()
        if radiobutton is None or not isinstance(radiobutton,QRadioButton):
            return
        self.label.setText("あなたは '%s' のラジオボタンをチェックしました" % radiobutton.text())

app = QApplication(sys.argv)
formtest = FormTest()
formtest.show()
app.exec_()
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/8f1e56c8-3766-79d1-217e-6e9fb6bb4c16.png)


#**ComboBoxの場合**
ここで注目は、activated[str]の部分です、スロットが文字列を受け取るということです。

```python:ComboTest01.py
import sys
from PyQt5.QtWidgets import *

class ComboTest01(QWidget):
    def __init__(self, parent=None):
        super(ComboTest01, self).__init__(parent)
        self.initUI()

    def initUI(self):
        self.label = QLabel("東京",self)
        combo = QComboBox(self)
        combo.addItem("東京")
        combo.addItem("足立区")
        combo.addItem("台東区")
        combo.addItem("千代田区")
        combo.addItem("品川区")
        combo.addItem("隅田区")
        combo.move(50,50)
        self.label.move(50,150)
        combo.activated[str].connect(self.onActivated)
        self.setGeometry(300,300,300,200)
        self.setWindowTitle("QComboBox")

    def onActivated(self,text):
        self.label.setText(text)
        self.label.adjustSize()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = ComboTest01()
    win.show()
    sys.exit(app.exec_())
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/408bc872-513f-1e92-e2f2-5cd14bab5fc6.png)


#**ファイルオープンダイアログのサンプル**
[Dialogs](http://http://zetcode.com/gui/pyqt5/dialogs/)こちらを参考に、プレーンテキスト等の拡張子限定でファイルを選択するようにしています。
実際のオープンとリードはpython3のコンポーネントを使用しているので日本語も文字化けしません。

```python:File_Open_Test01.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon


class FileOpenTest(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):

        self.textEdit = QTextEdit()
        self.setCentralWidget(self.textEdit)
        self.statusBar()

        openFile = QAction(QIcon('open.png'), '開く', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('新しいファイルを開く')
        openFile.triggered.connect(self.showDialog)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&ファイル')
        fileMenu.addAction(openFile)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('ファイルダイアログ')


    def showDialog(self):
        fname = QFileDialog.getOpenFileName(self,'Open file', '/', filter="Image Files (*.csv *.txt *.html *.xml *.py *.pyw)")

        if fname[0]:
            f = open(fname[0], 'r')

            with f:
                data = f.read()
                self.textEdit.setText(data)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = FileOpenTest()
    win.show()
    sys.exit(app.exec_())
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/3c7e41a8-9659-cf35-2d82-04448b307efa.png)


#**QTableWidgetでテーブルを作ってみる**
table = tableTest01(data, 3, 5)の部分書き換えて、data項目をセットすれば拡張できます。

```python:tableTest01.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

data = [['AAA', '東京', '東'],['BBB', '渋谷', '南西'],['CCC', '新宿', '西'],['DDD', '日暮里', '北'],['EEE', '秋葉原', '北東']]
class tableTest01(QTableWidget):
    def __init__(self, data, *args):
        QTableWidget.__init__(self, *args)
        self.data = data
        self.setdata()
        self.resizeColumnsToContents()
        self.resizeRowsToContents()

    def setdata(self):
        #ヘッダーを作成
        horHeaders = ['列1','列2','列3','列4','列5']
        self.setHorizontalHeaderLabels(horHeaders)
        #テーブルにデータをセット
        for n in range(len(self.data)):
            print("n=%d" % n)
            for m in range(len(self.data[n])):
                print("m=%d" % m)
                newitem = QTableWidgetItem(data[n][m])
                self.setItem(m, n, newitem)

def main():
    app = QApplication(sys.argv)
    table = tableTest01(data, 3, 5)
    table.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/f66c3a81-082b-fb8d-4ce7-b2baa63124fb.png)

tableTest01.pyの列と行の並びがあまりよくないので、tableTest02.pyで横一のならびに変えてみます。classのコードも少し変えました。

```python:tableTest02.py
import sys
from PyQt5.QtWidgets import *

data = [['AAA', '東京', '東'],['BBB', '渋谷', '南西'],['CCC', '新宿', '西']]

class TableWindow(QWidget):

    def __init__(self, parent=None):
        super(TableWindow, self).__init__(parent)
        colcnt = len(data[0])
        rowcnt = len(data)
        self.tablewidget = QTableWidget(rowcnt, colcnt)

        #ヘッダー設定
        horHeaders = ['列1','列2','列3']
        self.tablewidget.setHorizontalHeaderLabels(horHeaders)
        verHeaders = ['行1','行2','行3']
        self.tablewidget.setVerticalHeaderLabels(verHeaders)

        #テーブルの中身作成
        for n in range(rowcnt):
            for m in range(colcnt):
                item = QTableWidgetItem(str(data[n][m]))
                self.tablewidget.setItem(n, m, item)

        #レイアウト
        layout = QHBoxLayout()
        layout.addWidget(self.tablewidget)
        self.setLayout(layout)
        self.setWindowTitle('tableサンプル')

def main():
    app = QApplication(sys.argv)
    widget = TableWindow()
    widget.show()
    widget.raise_()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
```

![image](https://qiita-image-store.s3.amazonaws.com/0/124460/f6bc0c49-4dc0-6fe1-6db3-179c4fb80a01.png)

#tablewidgetのセルの色を変えてみる

```python:TableBackColor.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import *

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self,parent)
        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.setCentralWidget(self.table)
        data1 = [['行A','行B','行C','行D'],['行A','行B','行C','行D']]
        colcnt = len(data1[0])
        rowcnt = len(data1)


        self.table.setRowCount(4)

        for n in range(rowcnt):
            for m in range(colcnt):
                item1 = QTableWidgetItem(str(data1[n][m]))
                if n == 1:
                    item1.setBackground(QColor(Qt.yellow))
                self.table.setItem(n, m, item1)
        self.table.item(1, 0).setBackground(QColor(100, 10, 125))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
```

<img width="368" alt="スクリーンショット 2016-09-24 13.09.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/124460/00f80fd6-6bef-ae32-00bc-2372edf83848.png">




#デジタル時計を表示

```python:TestTimer.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class TestTimer(QWidget):

    def __init__(self, parent=None):

        super(TestTimer, self).__init__(parent)
        self.setWindowTitle('Digital Clock')
        timer = QTimer(self)

        timer.timeout.connect(self.updtTime)
        self.testTimeDisplay = QLCDNumber(self)
        self.testTimeDisplay.setSegmentStyle(QLCDNumber.Filled)
        self.testTimeDisplay.setDigitCount(8)
        self.testTimeDisplay.resize(500, 150)
        self.updtTime()
        timer.start(1000)

    def updtTime(self):

        currentTime = QDateTime.currentDateTime().toString('hh:mm:ss')
        self.testTimeDisplay.display(currentTime)

if __name__ == '__main__':

    myApp = QApplication(sys.argv)
    myWindow = TestTimer()
    myWindow.show()
    myApp.exec_()
    sys.exit()

```

![デジタル時計.png](https://qiita-image-store.s3.amazonaws.com/0/124460/bd4671e2-6032-f76b-9448-30a27346d7c7.png)

#Windowのstyleを変えてみる

```python:styleFactory.py
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class winStyle_test(QWidget):
    def __init__(self, parent=None):
        super(winStyle_test, self).__init__(parent)

        self.originalPalette = QApplication.palette()

        horizontalLayout = QHBoxLayout()

        self.styleLabel = QLabel("Window Style:")
        self.styleComboBox = QComboBox()

        # QStyleFactoryからリストセット
        self.styleComboBox.addItems(QStyleFactory.keys())
        print(QStyleFactory.keys())
        
        # カレントのstyleを検索
        index = self.styleComboBox.findText(qApp.style().objectName(), Qt.MatchFixedString)
        
        # styleをセット
        self.styleComboBox.setCurrentIndex(index)

        # styleがchangeしたら
        self.styleComboBox.activated[str].connect(self.windStyleChanged)

        # windowのpalette
        self.useStylePaletteCheckBox = QCheckBox("&style standard palette")
        self.useStylePaletteCheckBox.setChecked(True)
        self.useStylePaletteCheckBox.toggled.connect(self.changePalette)

        horizontalLayout.addWidget(self.styleLabel)
        horizontalLayout.addWidget(self.styleComboBox)
        horizontalLayout.addWidget(self.useStylePaletteCheckBox)
        self.setLayout(horizontalLayout)

    def changePalette(self):
        if (self.useStylePaletteCheckBox.isChecked()):
            QApplication.setPalette(QApplication.style().standardPalette())
        else:
            QApplication.setPalette(self.originalPalette)


    def windStyleChanged(self, style):
        qApp.setStyle(style)

if __name__ == "__main__":

    app = QApplication(sys.argv)
    w = winStyle_test()
    QApplication.setPalette(QApplication.style().standardPalette())
    w.show()
    sys.exit(app.exec_())
```
<img width="516" alt="スクリーンショット 2016-07-17 14.09.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/124460/43c9c5e0-c5e4-ab06-775b-12b13289029a.png">


#standardIconについて

https://joekuan.wordpress.com/2015/09/23/list-of-qt-icons/

Qtでデフォルトで使用可能な組み込みアイコンを表示するためにこんなのを作ったみたいです。

![screen3.png](https://qiita-image-store.s3.amazonaws.com/0/124460/07ee7d07-b4d1-9b7d-81a5-6387af88e6d7.png)

でもIconが小さいのとテキストを拾うのがめんどいので、こんな感じにしてみました。

```python:iconList.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__()

        icons = [
            'SP_ArrowBack',
            'SP_ArrowDown',
            'SP_ArrowForward',
            'SP_ArrowLeft',
            'SP_ArrowRight',
            'SP_ArrowUp',
            'SP_BrowserReload',
            'SP_BrowserStop',
            'SP_CommandLink',
            'SP_ComputerIcon',
            'SP_CustomBase',
            'SP_DesktopIcon',
            'SP_DialogApplyButton',
            'SP_DialogCancelButton',
            'SP_DialogCloseButton',
            'SP_DialogDiscardButton',
            'SP_DialogHelpButton',
            'SP_DialogNoButton',
            'SP_DialogOkButton',
            'SP_DialogOpenButton',
            'SP_DialogResetButton',
            'SP_DialogSaveButton',
            'SP_DialogYesButton',
            'SP_DirClosedIcon',
            'SP_DirHomeIcon',
            'SP_DirIcon',
            'SP_DirLinkIcon',
            'SP_DirOpenIcon',
            'SP_DockWidgetCloseButton',
            'SP_DriveCDIcon',
            'SP_DriveDVDIcon',
            'SP_DriveFDIcon',
            'SP_DriveHDIcon',
            'SP_DriveNetIcon',
            'SP_FileDialogBack',
            'SP_FileDialogContentsView',
            'SP_FileDialogDetailedView',
            'SP_FileDialogEnd',
            'SP_FileDialogInfoView',
            'SP_FileDialogListView',
            'SP_FileDialogNewFolder',
            'SP_FileDialogStart',
            'SP_FileDialogToParent',
            'SP_FileIcon',
            'SP_FileLinkIcon',
            'SP_MediaPause',
            'SP_MediaPlay',
            'SP_MediaSeekBackward',
            'SP_MediaSeekForward',
            'SP_MediaSkipBackward',
            'SP_MediaSkipForward',
            'SP_MediaStop',
            'SP_MediaVolume',
            'SP_MediaVolumeMuted',
            'SP_MessageBoxCritical',
            'SP_MessageBoxInformation',
            'SP_MessageBoxQuestion',
            'SP_MessageBoxWarning',
            'SP_TitleBarCloseButton',
            'SP_TitleBarContextHelpButton',
            'SP_TitleBarMaxButton',
            'SP_TitleBarMenuButton',
            'SP_TitleBarMinButton',
            'SP_TitleBarNormalButton',
            'SP_TitleBarShadeButton',
            'SP_TitleBarUnshadeButton',
            'SP_ToolBarHorizontalExtensionButton',
            'SP_ToolBarVerticalExtensionButton',
            'SP_TrashIcon',
            'SP_VistaShield'
        ]

        self.le = QLineEdit('')
        self.le.setText('')

        self.lab = QPushButton()


        layout = QVBoxLayout()

        self.comb = QComboBox(self)
        self.comb.addItem('')

        count = 0
        for i in icons:
            print(i)
            self.comb.insertItem(count, i)

            self.comb.setItemIcon(count, self.style().standardIcon(getattr(QStyle, i)))

            count += 1

        layout.addWidget(self.comb)
        layout.addWidget(self.le)
        layout.addWidget(self.lab)
        self.lab.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        self.comb.activated[str].connect(self.onActivated)

        self.setLayout(layout)


    def onActivated(self, text):

        self.le.setText(text)
        print(text)

        self.lab.setIcon(self.style().standardIcon(getattr(QStyle,text)))
        self.lab.setIconSize(QSize(200, 200))


if __name__ == '__main__':
    app = QApplication(sys.argv)

    dialog = Window()
    dialog.resize(300, 350)
    dialog.setWindowTitle("standardIcon List")
    dialog.show()

    sys.exit(app.exec_())
```
<img width="447" alt="スクリーンショット 2016-07-17 19.59.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/124460/731fcf64-d43f-0d18-edd1-f795810db327.png">
ただ、拡大できないアイコンもあるらしい。
<img width="447" alt="スクリーンショット 2016-07-17 19.59.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/124460/bcef775c-e305-fc78-dca4-8bd5fcc21de0.png">

#QGraphicsSceneに楕円と矩形を置いてマウスで移動可能にする

```python:MyFrame.py
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class MyFrame(QGraphicsView):
    def __init__( self, parent = None ):
        super(MyFrame, self).__init__(parent)

        #シーン作成
        self.scene = QGraphicsScene(self)

        #シーンをセット
        self.scene.setSceneRect(0, 0, 500, 500)
        self.setScene(self.scene)

        #pen = QPen(QColor(Qt.green))

        #ブラシ（Brush）をセット
        brush = QBrush(Qt.red, Qt.CrossPattern)

        #楕円作成
        item = self.scene.addEllipse(30, 30, 50, 50, Qt.red, brush)
        #矩形作成
        item2 = self.scene.addRect(70, 70, 50, 50, Qt.green, QBrush(Qt.green, Qt.CrossPattern))

        #選択と移動を可能にする
        item.setFlag(QGraphicsItem.ItemIsSelectable)
        item.setFlag(QGraphicsItem.ItemIsMovable)

        #移動を可能にする
        item2.setFlag(QGraphicsItem.ItemIsMovable)

if ( __name__ == '__main__' ):
    app = QApplication([])
    f = MyFrame()
    f.show()
    app.exec_()
```

<img width="612" alt="スクリーンショット 2016-09-12 22.33.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/124460/5cbef573-dd68-a1fc-2a5f-805e61dd0dc1.png">

ブラシに色と塗りを設定する以下の部分が肝です。
QBrush(Qt.green, Qt.CrossPattern)

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-84964934-1', 'auto');
  ga('send', 'pageview');

</script>