1
Help us understand the problem. What are the problem?

posted at

updated at

【PySide6】ウィジェットをクラス化したら全く反応しなくなったときの対処法

はじめに

私向けのメモです。

PySide6でウィジェットを別のクラスにした際に発生した不具合の解決方法を記載しています。

ここではメニューバーをクラス化して分けた場合を記載しています。
テキストボックスやメッセージボックスなど、ほかのウィジェットでも応用可能です。

調べても文献が全く見当たらなかったので、試行錯誤して何とかした記録になります。
他の方々にも参考になれば幸いです。

環境

  • Windows 11 Home
  • Python 3.9.9

事象

例えば以下の図のようなメニューを作ってみました。
000.png

これをソースコードにするとこんな感じになります。

# coding: shift-jis
import PySide6
from PySide6.QtGui import (QAction)
from PySide6.QtWidgets import (QApplication,
                               QMenuBar,
                               QWidget)
import os
import sys


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

        self.resize(300, 200)

        self.SetMenubar()

    # メニューバーを生成
    def SetMenubar(self):
        menubar = QMenuBar(self)

        # ファイル(F)
        fileMenu = menubar.addMenu("ファイル(&F)")

        # ファイル(F) → 新規(N)
        fileNew = QAction("新規(&N)", self)
        fileNew.setShortcut("Ctrl+N")
        fileNew.triggered.connect(self.FileNew)
        fileMenu.addAction(fileNew)

        # ファイル(F) → 終了(X)
        fileExit = QAction("終了(&X)", self)
        fileExit.setShortcut("Ctrl+Q")
        fileExit.triggered.connect(self.FileExit)
        fileMenu.addAction(fileExit)

    # ファイル(F) → 新規(N) をクリックしたとき
    def FileNew(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)

    # ファイル(F) → 終了(X) をクリックしたとき
    def FileExit(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    pluginPath = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = pluginPath

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

このプログラムを実行すると以下のように、各メニュー項目をクリックしたらそれぞれの機能が動きました。
001.png

ですがこのままMainWindowクラスに次々とメニューを追加したら、クラスのコードが非常に長ったらしくなり見にくくなっちゃいます。

そこでメニュー項目は別のクラスとしてMenubarに分けてみました。
そのソースコードがこちら。

# coding: shift-jis
import PySide6
from PySide6.QtGui import (QAction)
from PySide6.QtWidgets import (QApplication,
                               QMenuBar,
                               QWidget)
import os
import sys


# メニューバーの処理が多くなったから、別クラスに分けた
class Menubar:
    def __init__(self, mainwindow, menubar):
        # ファイル(F)
        fileMenu = menubar.addMenu("ファイル(&F)")

        # ファイル(F) → 新規(N)
        fileNew = QAction("新規(&N)", mainwindow)
        fileNew.setShortcut("Ctrl+N")
        fileNew.triggered.connect(self.FileNew)
        fileMenu.addAction(fileNew)

        # ファイル(F) → 終了(X)
        fileExit = QAction("終了(&X)", mainwindow)
        fileExit.setShortcut("Ctrl+Q")
        fileExit.triggered.connect(self.FileExit)
        fileMenu.addAction(fileExit)

    # ファイル(F) → 新規(N) をクリックしたとき
    def FileNew(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)

    # ファイル(F) → 終了(X) をクリックしたとき
    def FileExit(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)


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

        self.resize(300, 200)

        # メニューバーを生成
        menubar = QMenuBar(self)
        Menubar(self, menubar)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    pluginPath = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = pluginPath

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

さぁ実行すっぞ!!と意気揚々とメニューをクリックしたら、何とメニュー項目をクリックしても何も反応がなくなってしまいました。

002.png

解決方法

コメント欄に @shiracamus さんより、ナイスなプログラムを書いていただいております。 正直私の書いたコードより参考になります。 みんな、私の書いた記事じゃなくて、私の記事のコメントを・・・見よう。


ナイスなプログラム

この事象は2つの処理を追加するだけで解決します。

MenubarクラスにQMenuBarを継承させる。
Menubarクラスの__init__メソッド内で、親クラスが誰なのかを教えるsuper().__init__(parent)を追加します。

追加したコードがこちらになります。

# coding: shift-jis
import PySide6
from PySide6.QtGui import (QAction)
from PySide6.QtWidgets import (QApplication,
                               QMenuBar,
                               QWidget)
import os
import sys


# メニューバーの処理が多くなったから、別クラスに分けた
class Menubar(QMenuBar):  # ①メニューバーならQMenuBarを継承させる
    def __init__(self, mainwindow, menubar):
        # ②親クラスが誰なのかを教える
        super().__init__(mainwindow)

        # ファイル(F)
        fileMenu = menubar.addMenu("ファイル(&F)")

        # ファイル(F) → 新規(N)
        fileNew = QAction("新規(&N)", mainwindow)
        fileNew.setShortcut("Ctrl+N")
        fileNew.triggered.connect(self.FileNew)
        fileMenu.addAction(fileNew)

        # ファイル(F) → 終了(X)
        fileExit = QAction("終了(&X)", mainwindow)
        fileExit.setShortcut("Ctrl+Q")
        fileExit.triggered.connect(self.FileExit)
        fileMenu.addAction(fileExit)

    # ファイル(F) → 新規(N) をクリックしたとき
    def FileNew(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)

    # ファイル(F) → 終了(X) をクリックしたとき
    def FileExit(self):
        # このメソッド名を表示するだけ
        print(sys._getframe().f_code.co_name)


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

        self.resize(300, 200)

        # メニューバーを生成
        menubar = QMenuBar(self)
        Menubar(self, menubar)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    pluginPath = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = pluginPath

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

動かしてみると、ちゃんと動きました。
003.png

● 「① MenubarクラスにQMenuBarを継承させる。」についてちょっと補足 今回はメニューバーでしたが、テキストボックスならQTextEditを、メッセージボックスならQMessageBoxを継承させます。 (ex 1) QTextEditの場合 class Textbox(QTextEdit): def __init__(self, rootObject): super().__init__(rootObject) ...(略) (ex 2) QMessageBoxの場合 class Messagebox(QMessageBox): def __init__(self, rootObject): super().__init__(rootObject) ...(略)

参考

Flow Layout Example

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?