PySide2をゼロから学んでいく～#6 コンボボックス～

https://qiita.com/karakuri-t910/items/c5dbd714cd54520f415d

* [#0 環境構築](https://qiita.com/karakuri-t910/items/f0736a322a6ba217a36c)
* [#1 ウィンドウ](https://qiita.com/karakuri-t910/items/7d2aac29d979f2413162)
* [#2 ボタン](https://qiita.com/karakuri-t910/items/5aae0ba3bed05eeb5109)
* [#3 ラベル](https://qiita.com/karakuri-t910/items/1bdbcbf8b4b92555c123)
* [#4 ラジオボタン](https://qiita.com/karakuri-t910/items/e54e771c576d2a0aa11a)
* [#5 チェックボックス](https://qiita.com/karakuri-t910/items/03debf242efd944eecc2)
* [#6 コンボボックス ← ここ](https://qiita.com/karakuri-t910/items/bfd18dffbe2674a3b478)


# はじめに

PythonでGUI開発をするためのライブラリ「PySide2」の基本的な使い方を、いくつかの段階に分けて説明していきます。

当ページではPySide2のコンボボックスについて説明しています。

# 公式リファレンス
[QComboBox](https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QComboBox.html)

# 環境
以下の通りになります。

* Windows 10
* Python 3.8以降

# ベースプログラム
以下のウィンドウを表示するだけのプログラムをベースにして実装していきます。

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能（今はウィンドウだけ）
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

# PySide2でコンボボックス

## コンボボックスの表示
3つ選択肢を持ったコンボボックスを表示してみます。

### サンプルプログラム
```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        combobox.addItems(["One", "Two", "Three"])


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
![000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/11c6b55f-7f7b-d654-9aef-94cef0ea68bb.png)

### プログラム解説

<details><summary>解説を見る</summary><div>
<b>● コンボボックスを表示</b>
`QtWidgets.QComboBox()`クラスを用いてコンボボックスを表示させることができます。

```
書式:
    QtWidgets.QComboBox(window_object)
引数:
    window_object:
        コンボボックスを表示させるウィンドウ
```

ボタンやラベルを表示させる時と同様に、コンボボックスを表示させたいウィンドウオブジェクトを引数に指定します。

基本的に自身のウィンドウに表示させるので`self`を指定すればOKです。

```python
# コンボボックスオブジェクトの生成
combobox = QtWidgets.QComboBox(self)
```

<b>● コンボボックスの選択肢を追加</b>
`QtWidgets.QComboBox()`だけでは何も選択することのできない空のコンボボックスが表示されるだけなので、選択肢を追加する必要があります。

コンボボックスに選択肢を追加するには`addItems()`または`addItem()`メソッドを使用します。

```
書式:
    一つ追加
        QtWidgets.QComboBox.addItem(string)
    複数追加
        QtWidgets.QComboBox.addItems([string1, string2, string3, ...])
引数:
    string:
        コンボボックスに登録する選択肢
        複数追加する場合はリストまたはタプルで引数を指定する
```

引数`string`は文字列で指定します。

またコンボボックスの表示順は`addItem()`・`addItems()`で登録した順、またはリスト・タプルの並び順になります。

```python
# コンボボックスの選択肢を追加
combobox.addItems(["One", "Two", "Three"])
```
</div>

## コンボボックスの選択肢の数を取得
コンボボックスの選択肢の数を取得してみます。ループ処理をさせる場合に使用できそうですね。

### サンプルプログラム

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        combobox.addItems(["One", "Two", "Three"])

        # コンボボックスの選択数を取得
        print(combobox.count())


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/f041c680-dd76-5bc9-b23c-3eff9135ec90.png)

### プログラム解説

<details><summary>解説を見る</summary><div>
<b>● コンボボックスの選択肢の数を取得</b>
`QtWidgets.QComboBox()`クラスが持っている`count()`メソッドを用いてコンボボックスの選択肢の数を取得できます。

```
書式:
     QtWidgets.QComboBox.count()
引数:
    なし
```

サンプルプログラムでは以下のカ所で選択肢の数を取得しています。`addItems()`メソッドで登録した選択肢の数を表示しています。

```python
# コンボボックスの選択数を取得
print(combobox.count())
```
</div>

## 選択中の値を取得
コンボボックスで選択されている値を取得してみます。

* コンボボックスから取得できる値
    * 文字列
    * ID

### サンプルプログラム

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        combobox.addItems(["One", "Two", "Three"])

        # 選択中の文字列を取得
        print(combobox.currentText())

        # IDを取得
        print(combobox.currentIndex())


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/4a86d5f3-0514-07be-feef-0c7db59c6520.png)

### プログラム解説

<details><summary>解説を見る</summary><div>
<b>● 文字列を取得</b>
`QtWidgets.QComboBox()`クラスには選択中のコンボボックスの文字列を取得する`currentText()`メソッドがあります。

```
書式:
     QtWidgets.QComboBox.currentText()
引数:
    なし
```

サンプルプログラムでは以下のように現在選択中のコンボボックスの文字列を取得しています。

```python
# 選択中の文字列を取得
print(combobox.currentText())
```

<b>● IDを取得</b>
`QtWidgets.QComboBox()`クラスには選択中のコンボボックスのIDを取得する`currentIndex()`メソッドがあります。

```
書式:
     QtWidgets.QComboBox.currentIndex()
引数:
    なし
```

サンプルプログラムのように現在選択中のコンボボックスのIDを取得しています。

```python
# IDを取得
print(combobox.currentIndex())
```

サンプルプログラムを実行した結果、`0`というIDを取得できましたが、コンボボックスの各々の選択肢にはどのようなIDが割り振られているのでしょうか？

そんなに難しくはないのですが、単純に選択肢の<font color="red">上から順に0から始まり、1、2、3、…とインクリメントされて番号付けされています</font>。

以下の図のようなイメージです。

![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/d3eaaa22-cdb0-0974-b96b-c50c779b1c26.png)


</div>

## 選択肢を削除する
コンボボックスに登録されている選択肢を削除してみます。

### サンプルプログラム

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        combobox.addItems(["One", "Two", "Three"])

        # 真ん中の選択肢 "Two" を削除 (コンボボックスのIDで指定)
        combobox.removeItem(1)


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/b421ef7d-39f2-2519-f8b0-48a488461c7a.png)

### プログラム解説
<details><summary>解説を見る</summary><div>
<b>● コンボボックスの選択肢を削除</b>
`QtWidgets.QComboBox()`クラスの`removeItem()`メソッドでコンボボックスに登録されている選択肢を削除することができます。

```
書式:
    QtWidgets.QComboBox.removeItem(id)
引数:
    id:
        削除対象となるコンボボックスの選択肢のID
```

コンボボックスの選択肢のIDを`removeIten()`メソッドの引数に指定すれば、そのIDに該当する選択肢を削除することができます。コンボボックスのIDは先頭（一番上）から順に0、1、2、3、…と番号付けされています。また`currentIndex()`メソッドで選択中の選択肢IDを取得できます。

サンプルプログラムでは選択肢の2番目（IDは 1）を削除しています。

```python
# 真ん中の選択肢 "Two" を削除 (コンボボックスのIDで指定)
combobox.removeItem(1)
```
</div>

## コンボボックスの選択欄を入力可能にする
コンボボックスの選択欄を入力可能にしてみます。入力できるようにすると以下のメリットが得られます。

* 入力可能にすることのメリット
    * 選びたい選択肢の検索
    * 項目にはない選択肢の追加

### サンプルプログラム

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        combobox.addItems(["One", "Two", "Three"])

        # コンボボックス欄の入力を有効
        combobox.setEditable(True)


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
ちなみにコンボボックス欄の入力を可能にするだけで、候補検索も自動的にやってくれるようになります。

![000.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/fa62d5ab-e3db-f5ba-4b5a-1d60af033d2f.gif)

### プログラム解説
<details><summary>解説を見る</summary><div>
<b>● コンボボックス欄の入力を可能にする</b>
`QtWidgets.QComboBox()`クラスで作成したコンボボックスオブジェクトには`setEditable()`メソッドがあります。

この`setEditable()`メソッドの引数に`True/False`を指定することでコンボボックス欄の入力可否を設定します。

```
書式:
    QtWidgets.QComboBox.setEditable(bool)
引数:
    bool:
        「True」または「False」を指定。
        入力可能にする場合はTrueを引数に指定。
```

サンプルプログラムでは単にコンボボックスの入力を可能にしているだけです。

```python
# コンボボックス欄の入力を有効
combobox.setEditable(True)
```

<b>● 新しい項目を追加</b>
新規項目を追加する手順は以下になります。

1. コンボボックスに追加したい項目を入力
2. 入力後`Enter`を押して項目の追加が完了

簡単ですね。ただし<font color="red">`Enter`を押さないと項目の追加がされません</font>ので注意を。
実際に追加している様子を以下に掲載しています。

![001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/22977a3d-ad6e-554f-3717-1d7f8984dc10.gif)
</div>

## 選択肢が変更された瞬間に処理を実行する
コンボボックスの選択肢を変更したらある関数を実行してみます。

### サンプルプログラム

```python
# PySide2のモジュールを読み込む
from PySide2 import QtWidgets


# ウィンドウの見た目と各機能
class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # コンボボックスオブジェクトの生成
        self.combobox = QtWidgets.QComboBox(self)

        # コンボボックスの選択肢を追加
        self.combobox.addItems(["One", "Two", "Three"])

        # コンボボックスの選択肢が変更されたら呼び出す関数
        self.combobox.currentIndexChanged.connect(self.notice_changed)

    # 呼び出される関数
    def notice_changed(self):
        print("Changed!!")


# アプリの実行と終了
app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()
```

### 実行結果
![002.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614920/5f57e83d-e9fd-644e-b6b2-d4d992a96bd8.gif)

### プログラム解説

<details><summary>解説を見る</summary><div>
<b>● 選択肢が変更されたら関数を実行</b>
`QtWidgets.QComboBox()`クラスで生成したコンボボックスオブジェクトには`currentIndexChanged`というシグナルがあります。

この`currentIndexChanged`シグナルは、コンボボックスの現在の選択肢が変更されたことを検知し、スロット関数を呼び出します。

スロット関数を呼び出すには`connect()`メソッドを使用します。

書式は以下の通りになります。

```
書式:
QtWidgets.QComboBox.currentIndexChanged.connect(Slot_Function)
引数:
    Slot_Function:
        スロット関数
        コンボボックスの選択肢が変更されたら実行したい関数
```

サンプルプログラムでは選択肢が変更されたらコンソールに「Changed!!」と表示する`notice_changed`関数を呼び出すようにしています。

```python
# コンボボックスの選択肢が変更されたら呼び出す関数
self.combobox.currentIndexChanged.connect(self.notice_changed)
```
</div>