はじめに
私向けのメモです。
PySide6でウィジェットを別のクラスにした際に発生した不具合の解決方法を記載しています。
ここではメニューバーをクラス化して分けた場合を記載しています。
テキストボックスやメッセージボックスなど、ほかのウィジェットでも応用可能です。
調べても文献が全く見当たらなかったので、試行錯誤して何とかした記録になります。
他の方々にも参考になれば幸いです。
環境
- Windows 11 Home
- Python 3.9.9
事象
これをソースコードにするとこんな感じになります。
# 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())
このプログラムを実行すると以下のように、各メニュー項目をクリックしたらそれぞれの機能が動きました。
ですがこのまま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())
さぁ実行すっぞ!!と意気揚々とメニューをクリックしたら、何とメニュー項目をクリックしても何も反応がなくなってしまいました。
解決方法
コメント欄に @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())
● 「① 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)
...(略)