0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PySide6でつくる!リポジトリパターンを採用したGUIファイルマネージャーのベース実装

0
Posted at

PythonでGUIアプリケーションを作成する際、UIの描画ロジックとファイル操作などの実ロジックが密結合になりがちです。今回は、PySide6を用いて、GUI表示ロジックとファイル操作の実ロジックを疎結合に保つクリーンな設計(データモデルとリポジトリパターン)を採用したファイルマネージャーのベース実装を紹介します。

このプロジェクトは、独自のファイル管理ツールや画像ビューア、メディア管理ライブラリなどを開発するための強力な土台となります。

アーキテクチャの全体像

本プロジェクトでは、オブジェクト指向のポリモーフィズムとリポジトリパターンを意識した以下の3層構造を採用しています。

  1. データモデル層 (BaseNodeObject.py)
  2. データアクセス・操作層 (FilerRepository.py)
  3. UI・プレゼンテーション層 (main.py)

これにより、GUI層から osshutil などのOS標準モジュールを直接呼び出すことを避け、テストや機能拡張を容易にしています。


1. データモデル層: UIに必要な情報をカプセル化

ファイルやディレクトリは、共通の基底クラス BaseNodeObject の派生クラスとして表現します。
アイコンの判定、ファイルタイプ名、サイズのフォーマットなど、UI描画に必要なプロパティはすべてモデル内に隠蔽します。

# BaseNodeObject.py (抜粋)
from PySide6.QtCore import QObject, Signal
import os

class BaseNodeObject(QObject):
    """ファイルやディレクトリのベースとなるデータオブジェクト"""
    updated = Signal(object) # 状態が変わったらGUIに通知する信号

    def __init__(self, path: str):
        super().__init__()
        self.path = os.path.abspath(path)
        self.name = os.path.basename(path)
        self._is_selected = False

    @property
    def exists(self) -> bool:
        return os.path.exists(self.path)
    
    # ... その他の共通プロパティ (modified_time, created_timeなど)

class FileNodeObject(BaseNodeObject):
    """ファイルを表すオブジェクト"""
    def __init__(self, path: str):
        super().__init__(path)
        self.size = os.path.getsize(path) if os.path.exists(path) else 0
        self.extension = os.path.splitext(self.name)[1]

    @property
    def icon(self) -> str:
        # 拡張子に応じた絵文字アイコンを返す
        ext = self.extension.lower()
        if ext in ['.png', '.jpg', '.jpeg']: return "🖼️"
        elif ext in ['.py', '.js', '.html']: return "⚙️"
        return "📄"

class DirectoryNodeObject(BaseNodeObject):
    """ディレクトリを表すオブジェクト"""
    def __init__(self, path: str):
        super().__init__(path)
        self.children: list[BaseNodeObject] = []

    @property
    def icon(self) -> str:
        return "📁"

このようにすることで、GUI側は「アイコンは何かな?」と各ノードの icon プロパティを呼び出すだけでよくなり、UI側に条件分岐の判定ロジックを書く必要がなくなります。


2. データアクセス層: リポジトリパターンの適用

FilerRepository は、ファイルシステムの読み書きをカプセル化します。GUI側はこのリポジトリを介してのみファイルシステムへの操作を行います。

# FilerRepository.py (抜粋)
import os
import shutil
from BaseNodeObject import DirectoryNodeObject, FileNodeObject

class FilerRepository:
    """ローカルのファイルシステムからノードを取得し、操作するラッパー"""
    
    def get_directory_node(self, dir_path: str) -> DirectoryNodeObject:
        """指定されたパスのディレクトリノードを作成し、中身のノード群を詰めて返す"""
        dir_node = DirectoryNodeObject(dir_path)
        
        if not os.path.isdir(dir_path):
            return dir_node

        try:
            for entry in os.scandir(dir_path):
                if entry.is_dir():
                    dir_node.children.append(DirectoryNodeObject(entry.path))
                else:
                    dir_node.children.append(FileNodeObject(entry.path))
        except PermissionError:
            pass
            
        return dir_node

    def rename_node(self, node_path: str, new_name: str) -> bool:
        """ノードの名前を変更する"""
        # (実装省略)
    
    def delete_node(self, node_path: str) -> bool:
        """ノードを削除する"""
        # (実装省略)

os.scandir を用いてディレクトリ内を走査し、先ほど定義した FileNodeObjectDirectoryNodeObject のインスタンスに変換して返却している点がポイントです。


3. UI・プレゼンテーション層

GUIは main.py で PySide6 を用いて構築されています。
GUIコンポーネント(例えばファイルのリストを表示するTableViewなど)は、FilerRepository.get_directory_node() を呼び出して DirectoryNodeObject を取得し、その中に入っている children をループして描画するだけです。

「戻る」「進む」などのナビゲーション機能や、右クリックのコンテキストメニューからリポジトリのメソッド(名前変更、削除など)を呼び出すように構築することで、シンプルかつメンテナブルなUIコードを維持できます。

応用例・まとめ

このベースクラス群を活用すれば、用途に合わせた様々なツールを素早く開発できます。

  • プレビュー機能の追加: FileNodeObject に画像やテキストのプレビューデータを返すメソッドを追加すれば、詳細パネルにプレビューを表示するのも簡単です。
  • 仮想ファイルシステム: FilerRepository を差し替えることで、クラウドストレージ(S3やGoogle Driveなど)上のファイルを操作するGUIマネージャーへの拡張も可能です(GUI側のインターフェースを変えずに実装可能)。

ファイル操作を伴うGUIアプリを作成する際は、ぜひこのような「データモデルの分離」と「リポジトリパターンの導入」を試してみてください!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?