【PyQt × pySerial】PCに接続されたCOMポート一覧をコンボボックスに表示

# 始めに

![combobox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/0ec226aa-17b7-67f7-5452-8edee23c05e1.png)

このような感じで、PCに接続されたCOMポートを選択できるようなコンボボックスを[PyQt](https://ja.wikipedia.org/wiki/PyQt)で作成します。
PyQt, Qt Designerを使ったGUIアプリの作成方法は[こちら](https://qiita.com/grinpeaceman/items/54b439bfa52640c444e1)を参照。

# 環境
+ Windows 10
+ Python 3.8.5
+ PyQt 5.15.1
+ pyserial 3.4

# インストール
```
$ pip install pyqt5
$ pip install pyserial
```

# ①UIファイルの作成

[Qt Designer](https://doc.qt.io/qt-5/qtdesigner-manual.html)を起動し、Combo Boxを配置したてきとうなWidgetを作成。

![designer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404447/52b7a42b-7ad7-d383-10c2-8586afca65bd.png)

Combo Boxの名前は"portComboBox"としています。

```xml:port_combo_box_sample.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>219</width>
    <height>70</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QComboBox" name="portComboBox">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>20</y>
     <width>171</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

```

# ②UIファイルをPythonファイルに変換

`$ pyuic5 port_combo_box_sample.ui > port_combo_box_sample_ui.py`

```python:port_combo_box_sample_ui.py
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'port_combo_box_sample.ui'
#
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(219, 70)
        self.portComboBox = QtWidgets.QComboBox(Form)
        self.portComboBox.setGeometry(QtCore.QRect(30, 20, 171, 22))
        self.portComboBox.setObjectName("portComboBox")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))

```

# ③メインのGUIファイルを作成

```python:port_combo_box_sample_gui.py
import sys

from PyQt5.QtWidgets import QMainWindow, QApplication
from serial.tools import list_ports

from port_combo_box_sample_ui import Ui_Form


class PortComboBoxSampleGui(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(PortComboBoxSampleGui, self).__init__(parent)
        self.setupUi(self)
        self._init_port_combo_box()

    def _init_port_combo_box(self):
        comports = list_ports.comports()
        if not comports:
            print("ポートが見つかりません")
            return

        for index, comport in enumerate(comports):
            self.portComboBox.addItem(comport.device)


if __name__ == "__main__":
    argvs = sys.argv
    app = QApplication(argvs)
    main_gui = PortComboBoxSampleGui()
    main_gui.show()
    sys.exit(app.exec_())

```