質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

1222閲覧

PyQtで2つのラベルを一つにまとめたソースコードの添削をお願いいたします

nahon

総合スコア13

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2022/02/11 13:08

イメージ説明

前提・実現したいこと

PyQt5で画像ラベルとテキストラベルを横に並べ、ペアにしてリストのように表示し、
ラベルペアに対して同じ動作をさせたいと思っております。

具体的には、マウスオーバーしたら色を変え、クリックしたらメッセージを表示する、です。

今回ソースコードのような形で実装したのですが、PyQtを触り始めたばかりで無駄が多いのではないかと思っております。
よりきれいなPyQt向きなコードを教えていただけないでしょうか。
よろしくお願いいたします。

該当のソースコード

python

1from PyQt5.QtWidgets import * 2from PyQt5.QtGui import * 3from PyQt5.QtCore import * 4import sys 5 6class LabelTest(QWidget): 7 def __init__(self): 8 super().__init__() 9 self.initUI() 10 11 def initUI(self): 12 # ラベル参照用辞書 13 self.lbl_dict = dict() 14 15 # 背景色 16 tmpWidget = QWidget() 17 self.backGroundColor = tmpWidget.palette().color(QPalette.Window); 18 19 # 設定 20 icosize = 16 21 width = 120 22 23 for i in range(10): 24 # 画像 25 lblImg = QLabel(self) 26 lblImg.setObjectName(str(i)) 27 lblImg.setText( "●" ) #lblImg.setPixmap( QPixmap("D:\\test.ico") ) #16x16 ico 28 lblImg.installEventFilter(self) 29 lblImg.move(0, i*icosize) 30 lblImg.resize(icosize,icosize) 31 32 # テキスト 33 lblText = QLabel(self) 34 lblText.setObjectName(str(i)) 35 lblText.setText("Text") 36 lblText.installEventFilter(self) 37 lblText.move(icosize, i*icosize) 38 lblText.resize(width-icosize,icosize) 39 40 # ラベルペアを参照用辞書に追加 41 self.lbl_dict.setdefault(str(i), (lblImg,lblText)) 42 43 self.show() 44 45 def eventFilter(self, object, event): 46 # マウスオーバーしたラベルペアを黄色にする 47 if event.type()== QEvent.Enter: 48 for key, value in self.lbl_dict.items(): 49 if object.objectName() == key: 50 img, lbl = value 51 52 palette_yellow = QPalette() 53 palette_yellow.setColor(QPalette.Window, Qt.yellow) 54 55 img.setPalette(palette_yellow) 56 img.setAutoFillBackground(True) 57 lbl.setPalette(palette_yellow) 58 lbl.setAutoFillBackground(True) 59 60 return True 61 62 # マウスアウトしたラベルペアを背景色にする 63 elif event.type()== QEvent.Leave: 64 for key, value in self.lbl_dict.items(): 65 if object.objectName() == key: 66 img, lbl = value 67 68 palette_blue = QPalette() 69 palette_blue.setColor(QPalette.Window, self.backGroundColor ) 70 71 img.setPalette(palette_blue) 72 img.setAutoFillBackground(True) 73 lbl.setPalette(palette_blue) 74 lbl.setAutoFillBackground(True) 75 76 return True 77 78 # クリックしたらメッセージを表示する 79 elif event.type() == QEvent.MouseButtonPress: 80 if event.button() == Qt.LeftButton: 81 print(object.objectName(), "clicked!") 82 return True 83 84 return False 85 86if __name__== '__main__': 87 app= QApplication(sys.argv) 88 ex= LabelTest() 89 sys.exit(app.exec_())

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

  • import * は使わない。(理由: PEP8 推奨スタイル)
    デバッグ時に名前空間を見る時、不要な未使用クラスを表示しない。
    個別に列挙が面倒な場合は、IDEやEditorに支援機能があります。
  • QLabel で埋め込み画像を使う。簡易タグ表記
    setPixmap を使う場合、画像かテキストどちらか片方か表示できませんが、
    テキスト内で簡単なタグは使えます。
  • スタイルシートを使う。背景色を変更していたイベント処理を省けます
    但し、マウスカーソルの変更などスタイルでは対応していない項目もあるので、
    全てスタイルシートで済むとは限りません。
  • レイアウトマネージャを使う。→ポジションやサイズ計算
  • initUI() -> _initUI() 外部から呼び出さないメソッド名の慣習。
    メソッド一覧等のドキュメントを生成する際に、プライベートメンバを表示しないように抑制できたりします。
    アンダーバーを2つにすると、外部から呼び出し際にエラーが出るようにもできます。コードの読みやすさと相談。
  • ラベル参照用辞書の撤去。Qt のオブジェクト、生成時に親を指定する事で生存サイクルを管理できます。
    必要があれば、親オブジェクト(ウィジェット) から目的のラベルウィジェットを探索し参照することが可能です。
  • 追記2: ラベルのクリックに対応。イベント通知には Qt ではシグナル・スロットの仕組みを使います。
    イベント自体の処理(マウスの左ボタン判別)と、イベントで起こしたい処理(objectNameを表示)の分離

python

1from PyQt5.QtCore import Qt, pyqtSignal 2from PyQt5.QtWidgets import ( 3 QApplication, 4 QWidget, 5 QLabel, 6 QVBoxLayout, 7) 8 9CUSTOM_CSS = """ 10 QLabel:hover { 11 background: yellow; 12 } 13""" 14 15# ラベルにクリック対応 16# 参考: https://wiki.qt.io/Clickable_QLabel 17class ClickableLabel(QLabel): 18 clicked = pyqtSignal() 19 20 def mousePressEvent(self, event): 21 if event.button() == Qt.LeftButton: 22 self.clicked.emit() 23 24 25class LabelTest(QWidget): 26 def __init__(self, *args, **kw): 27 super().__init__(*args, **kw) 28 self._initUI() 29 30 def _initUI(self): 31 vbox = QVBoxLayout(self) 32 img = '<img width=16 height=16 src="google-chrome-icon.png">' 33 34 for num in range(10): 35 name = f"Test {num:02}" 36 label = ClickableLabel(self, objectName=name) 37 label.setText(f"{img} {name}") 38 label.clicked.connect(self.clicked) 39 vbox.addWidget(label) 40 41 def clicked(self): 42 label = self.sender() 43 name = label.objectName() 44 print(f"{name} clicked") 45 46 47def main(): 48 import sys 49 50 app = QApplication(sys.argv) 51 app.setStyleSheet(CUSTOM_CSS) 52 win = LabelTest() 53 win.show() 54 sys.exit(app.exec_()) 55 56 57if __name__ == '__main__': 58 main()

追記: スタイルシートと埋め込みタグにより不要になりますが、
質問のコードの改善点について。辞書内のオブジェクトを全て走査してますが、
辞書には番号をキーにして、画像・テキストのペアを格納すれば、for 文による走査を省けます。

投稿2022/02/12 04:40

編集2022/02/12 10:33
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

無駄が多いのだろうとは思っていましたが、まさかここまでスッキリするなんて…
目から鱗とはまさにこのことです。

PythonとPyQtの魅力をより感じるようになりました。
素敵なコードを教えていただきまして、本当にありがとうございました。

頑張ってきれいに作り上げたいと思います。

追記 2022-02-13
シグナルとスロットの例までありがとうございます。
一つの関数の中で処理を分けると長くなってしまうことに少し悩んでいたので、
教えていただいたシグナル・スロットの仕組みで書き直したいと思います。

投稿2022/02/12 06:44

編集2022/02/13 07:04
nahon

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問