PySideで始めるPython GUI開発入門

## はじめに

PySideは、PythonでGUIアプリケーションを開発するための強力なツールキットです。QtフレームワークをPythonから利用できるようにしたもので、直感的なAPIと豊富な機能を提供します。この記事では、PySideを使ったGUI開発の基礎から応用までを15章に分けて解説します。

## 第1章: PySideのインストールと基本設定

まずはPySideをインストールしましょう。以下のコマンドでPySide6をインストールできます:

```bash
pip install PySide6
```

インストールが完了したら、以下の簡単なコードで動作確認をしてみましょう:

```python
import sys
from PySide6.QtWidgets import QApplication, QLabel

app = QApplication(sys.argv)
label = QLabel("こんにちは、PySide!")
label.show()
sys.exit(app.exec())
```

このコードを実行すると、「こんにちは、PySide!」というテキストを表示する小さなウィンドウが表示されます。

## 第2章: ウィンドウの作成

GUIアプリケーションの基本はウィンドウです。以下のコードで、タイトルとサイズを指定したウィンドウを作成できます:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("私の最初のPySideアプリ")
        self.setGeometry(100, 100, 300, 200)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

このコードでは、`QMainWindow`クラスを継承して独自のウィンドウクラスを定義しています。`setWindowTitle()`でウィンドウのタイトルを、`setGeometry()`でウィンドウの位置とサイズを設定しています。

## 第3章: ボタンの追加

ウィンドウにボタンを追加してみましょう:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("ボタン付きウィンドウ")
        self.setGeometry(100, 100, 300, 200)

        button = QPushButton("クリックしてね", self)
        button.setGeometry(100, 80, 100, 30)
        button.clicked.connect(self.button_clicked)

    def button_clicked(self):
        print("ボタンがクリックされました!")

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

このコードでは、`QPushButton`を使ってボタンを作成し、`clicked`シグナルを`button_clicked`メソッドに接続しています。ボタンがクリックされると、コンソールにメッセージが表示されます。

## 第4章: レイアウトの使用

ウィジェットを整列させるには、レイアウトを使用するのが便利です。以下は`QVBoxLayout`を使用した例です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("レイアウトの例")

        layout = QVBoxLayout()
        
        button1 = QPushButton("ボタン1")
        button2 = QPushButton("ボタン2")
        button3 = QPushButton("ボタン3")

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

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、`QVBoxLayout`を使って3つのボタンを縦に配置しています。

## 第5章: テキスト入力

ユーザーからの入力を受け取るために、`QLineEdit`ウィジェットを使用できます:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QLineEdit, QPushButton, QVBoxLayout, QWidget

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("テキスト入力")

        layout = QVBoxLayout()

        self.text_input = QLineEdit()
        self.button = QPushButton("送信")
        self.button.clicked.connect(self.on_button_click)

        layout.addWidget(self.text_input)
        layout.addWidget(self.button)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

    def on_button_click(self):
        print(f"入力されたテキスト: {self.text_input.text()}")

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

このコードでは、`QLineEdit`を使ってテキスト入力フィールドを作成し、ボタンがクリックされたときに入力されたテキストを表示します。

## 第6章: メッセージボックス

ユーザーに情報を表示したり、確認を求めたりするためのメッセージボックスを作成できます:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QMessageBox

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("メッセージボックスの例")

        button = QPushButton("メッセージを表示", self)
        button.setGeometry(50, 50, 200, 30)
        button.clicked.connect(self.show_message)

    def show_message(self):
        msg_box = QMessageBox()
        msg_box.setWindowTitle("情報")
        msg_box.setText("これはメッセージボックスです。")
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        
        result = msg_box.exec()
        if result == QMessageBox.Ok:
            print("OKが押されました")
        else:
            print("キャンセルが押されました")

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、ボタンをクリックするとメッセージボックスが表示され、ユーザーの選択に応じて異なる処理を行います。

## 第7章: メニューバーとツールバー

アプリケーションにメニューバーとツールバーを追加することで、より多くの機能にアクセスしやすくなります:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QAction, QToolBar
from PySide6.QtGui import QIcon

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("メニューとツールバーの例")

        # メニューバーの作成
        menu_bar = self.menuBar()
        file_menu = menu_bar.addMenu("ファイル")
        edit_menu = menu_bar.addMenu("編集")

        # アクションの作成
        new_action = QAction("新規", self)
        new_action.setShortcut("Ctrl+N")
        new_action.triggered.connect(self.new_file)

        open_action = QAction("開く", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_file)

        # メニューにアクションを追加
        file_menu.addAction(new_action)
        file_menu.addAction(open_action)

        # ツールバーの作成
        toolbar = QToolBar()
        self.addToolBar(toolbar)
        toolbar.addAction(new_action)
        toolbar.addAction(open_action)

    def new_file(self):
        print("新規ファイルが選択されました")

    def open_file(self):
        print("ファイルを開くが選択されました")

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、メニューバーとツールバーを作成し、それぞれにアクションを追加しています。

## 第8章: ダイアログ

ダイアログを使用して、ユーザーとのインタラクションを強化できます:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QDialog, QVBoxLayout, QLabel, QLineEdit

class CustomDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("カスタムダイアログ")

        layout = QVBoxLayout()
        self.label = QLabel("名前を入力してください:")
        self.input = QLineEdit()
        self.button = QPushButton("OK")
        self.button.clicked.connect(self.accept)

        layout.addWidget(self.label)
        layout.addWidget(self.input)
        layout.addWidget(self.button)

        self.setLayout(layout)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("ダイアログの例")

        button = QPushButton("ダイアログを開く", self)
        button.setGeometry(50, 50, 200, 30)
        button.clicked.connect(self.show_dialog)

    def show_dialog(self):
        dialog = CustomDialog(self)
        if dialog.exec() == QDialog.Accepted:
            name = dialog.input.text()
            print(f"こんにちは、{name}さん!")

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、カスタムダイアログを作成し、メインウィンドウから呼び出しています。

## 第9章: テーブルとリスト

データを表形式で表示するには、`QTableWidget`や`QListWidget`が便利です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("テーブルの例")

        layout = QVBoxLayout()

        table = QTableWidget(5, 3)
        table.setHorizontalHeaderLabels(["名前", "年齢", "職業"])

        data = [
            ("田中太郎", "30", "エンジニア"),
            ("佐藤花子", "25", "デザイナー"),
            ("鈴木一郎", "40", "マネージャー"),
            ("高橋美咲", "35", "営業"),
            ("伊藤健太", "28", "研究員")
        ]

        for row, (name, age, job) in enumerate(data):
            table.setItem(row, 0, QTableWidgetItem(name))
            table.setItem(row, 1, QTableWidgetItem(age))
            table.setItem(row, 2, QTableWidgetItem(job))

        layout.addWidget(table)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、`QTableWidget`を使用してデータをテーブル形式で表示しています。

## 第10章: グラフィックスとアニメーション

PySideを使用して、グラフィックスやアニメーションを作成することもできます:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsEllipseItem
from PySide6.QtCore import QTimer, QPropertyAnimation, QEasingCurve
from PySide6.QtGui import QPen, QBrush, QColor

class AnimatedCircle(QGraphicsEllipseItem):
    def __init__(self, x, y, r):
        super().__init__(0, 0, r*2, r*2)
        self.setPos(x, y)
        self.setBrush(QBrush(QColor(255, 0, 0)))

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("アニメーションの例")

        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.setCentralWidget(self.view)

        self.circle = AnimatedCircle(0, 0, 20)
        self.scene.addItem(self.circle)

        self.animation = QPropertyAnimation(self.circle, b"pos")
        self.animation.setDuration(2000)
        self.animation.setStartValue(self.circle.pos())
        self.animation.setEndValue(self.circle.pos() + self.circle.pos().transposed())
        self.animation.setEasingCurve(QEasingCurve.InOutQuad)

        self.timer = QTimer()
        self.timer.timeout.connect(self.start_animation)
        self.timer.start(3000)

    def start_animation(self):
        self.animation.start()

app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(100, 100, 300, 300)
window.show()
sys.exit(app.exec())
```

## 第11章: イベント処理

PySideでは、イベント処理を通じてユーザーのアクションに応答できます。以下は、マウスイベントを処理する例です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel
from PySide6.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("イベント処理の例")

        self.label = QLabel("ここにマウスの位置が表示されます", self)
        self.label.setAlignment(Qt.AlignCenter)
        self.setCentralWidget(self.label)

    def mouseMoveEvent(self, event):
        x = event.x()
        y = event.y()
        self.label.setText(f"マウスの位置: ({x}, {y})")

app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(100, 100, 400, 300)
window.show()
sys.exit(app.exec())
```

このコードでは、`mouseMoveEvent`メソッドをオーバーライドして、マウスの位置を取得し、ラベルに表示しています。

## 第12章: データバインディング

データバインディングを使用すると、モデルとビューを連携させてデータを表示できます。以下は、`QListView`と`QStringListModel`を使用した例です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QListView, QVBoxLayout, QWidget
from PySide6.QtCore import QStringListModel

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("データバインディングの例")

        layout = QVBoxLayout()

        self.list_view = QListView()
        self.model = QStringListModel(["アイテム1", "アイテム2", "アイテム3"])
        self.list_view.setModel(self.model)

        layout.addWidget(self.list_view)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、`QStringListModel`を使用してデータモデルを作成し、`QListView`にバインドしています。

## 第13章: カスタムウィジェットの作成

PySideでは、独自のウィジェットを作成することもできます。以下は、カスタムウィジェットを作成する例です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel
from PySide6.QtGui import QPainter, QColor

class ColorWidget(QWidget):
    def __init__(self, color, parent=None):
        super().__init__(parent)
        self.color = QColor(color)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(self.rect(), self.color)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("カスタムウィジェットの例")

        layout = QVBoxLayout()

        red_widget = ColorWidget("red")
        green_widget = ColorWidget("green")
        blue_widget = ColorWidget("blue")

        layout.addWidget(red_widget)
        layout.addWidget(green_widget)
        layout.addWidget(blue_widget)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

このコードでは、`ColorWidget`クラスを作成し、指定された色で塗りつぶされたウィジェットを表示しています。

## 第14章: スタイルシートの使用

PySideでは、スタイルシートを使用してウィジェットの外観をカスタマイズできます。以下は、スタイルシートを使用した例です:

```python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("スタイルシートの例")

        layout = QVBoxLayout()

        button1 = QPushButton("ボタン1")
        button2 = QPushButton("ボタン2")
        button3 = QPushButton("ボタン3")

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

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        self.setStyleSheet("""
            QPushButton {
                background-color: #3498db;
                color: white;
                border-radius: 5px;
                padding: 10px;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
        """)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
```

この例では、`QPushButton`の背景色や文字色をスタイルシートでカスタマイズしています。

## 第15章: プロジェクトの構造とデプロイ

最後に、PySideプロジェクトの構造とデプロイ方法について説明します。プロジェクトを整理するために、以下のようなディレクトリ構造を推奨します:

```
my_pyside_app/
│
├── main.py
├── widgets/
│   ├── __init__.py
│   └── custom_widget.py
├── resources/
│   ├── images/
│   └── styles/
└── README.md
```

### デプロイ

アプリケーションをデプロイするには、`PyInstaller`を使用して実行可能ファイルを作成できます。以下のコマンドでインストールできます:

```bash
pip install pyinstaller
```

次に、以下のコマンドで実行可能ファイルを作成します:

```bash
pyinstaller --onefile main.py
```

これにより、`dist`フォルダに実行可能ファイルが生成され、他のユーザーがPython環境を持っていなくてもアプリケーションを実行できるようになります。

---

以上で、PySideを使用したPythonのGUI開発に関する基本的な15章の解説を終わります。このガイドが、PySideを使ったアプリケーション開発の第一歩となることを願っています。興味を持たれた方は、さらに公式ドキュメントや他のリソースを活用して、より高度な機能やカスタマイズに挑戦してみてください。