mieki256's diary



2016/11/09(水) [n年前の日記]

#1 [python] PySideでツールパネルっぽいソレを作成できないかテスト

Photoshop や GIMP等の、ツールパネル?っぽいソレをPySideで作れるかどうかテスト。…ツールパネルって呼び方でいいのかな? ツールパレット? なんて呼ぶんだろアレ。要は、どれか一つ、ツールを選ぶと ―― どれか一つボタンを押すと、他のボタンがOFFになるアレ。

_Photoshop のツールギャラリー

こんな感じだろうか。

_button_test.py
u"""押したままの状態になるボタンを並べてツールパネル相当を作るテスト."""


import sys
from PySide.QtCore import *  # NOQA
from PySide.QtGui import *  # NOQA


class ToolPanel(QWidget):

    u"""ツールパネル用Widget."""

    button_clicked = Signal(int)  # シグナルを用意

    def __init__(self, *argv, **keywords):
        u"""初期化."""
        super(ToolPanel, self).__init__(*argv, **keywords)
        self.grp = QButtonGroup()
        gb = QGridLayout()
        dt = [
            (0, 0, 0, "Brush"),
            (1, 0, 1, "Erase"),
            (0, 1, 2, "Box"),
            (1, 1, 3, "Box Fill"),
            (0, 2, 4, "Select"),
            (1, 2, 5, "Fill"),
        ]
        for x, y, id, s in dt:
            btn = QPushButton(s, self)
            btn.setCheckable(True)  # トグルボタンにする
            self.grp.addButton(btn, id)  # グループ登録してラジオボタン風に使う
            gb.addWidget(btn, y, x)
        self.setLayout(gb)
        self.grp.setExclusive(True)  # 排他的なボタン処理にする
        self.grp.button(0).setChecked(True)  # 最初のボタンを押しておく
        self.grp.buttonClicked.connect(self.changed_button)

    def changed_button(self):
        u"""ボタンが押された時に呼ばれる処理."""
        self.button_clicked.emit(self.grp.checkedId())  # シグナルを発生

    def get_id(self):
        u"""選択状態(ID)を返す."""
        return self.grp.checkedId()


class MyMainWidget(QWidget):

    u"""メインウインドウ."""

    def __init__(self, *argv, **keywords):
        u"""初期化."""
        super(MyMainWidget, self).__init__(*argv, **keywords)
        self.tb = ToolPanel(self)
        self.tb.button_clicked.connect(self.changed_toolbox)
        self.lbl = QLabel("----", self)
        self.lbl.setText("ID=%d" % self.tb.get_id())
        l = QVBoxLayout()
        l.addWidget(self.tb)
        l.addWidget(self.lbl)
        self.setLayout(l)

    def changed_toolbox(self, id):
        u"""ツールの選択状態が切り替わった時に呼ばれる処理."""
        self.lbl.setText("ID=%d" % id)


def main():
    u"""メイン処理."""
    app = QApplication(sys.argv)
    w = MyMainWidget()
    w.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

button_test_ss01.gif


どれか一つボタンを押すと、他のボタンがOFFになってる。更に、IDも変わってる。目的は果たせそう。

こういう動作にする際は、 _QButtonGroup を使う。 _QPushButton (フツーのボタン)でも、 _QRadioButton (ラジオボタン)でも、とにかく QButtonGroup に追加登録してやれば、こういう動作にすることができる模様。また、各ボタンを登録する際にIDを設定しておいてやると、後で変化があった際、押されたボタンのIDを取得することもできる。

QPushButtonは、そのままだとクリックした時しかONにならないけど。クリックするたびにON/OFFを切り替えるトグルボタン(?)にしたい時は、 _setCheckable(True) を呼んで設定してやる。

それと、最初に QPushButton のどれかしらが既に押されている状態にしたいわけだけど。その場合は、 _setChecked(True) を呼んでやれば、ON状態に設定できる。

QButtonGroup に登録されたボタンの状態が変わったら、QButtonGroup は _buttonClicked というシグナルを出すので、そのシグナルにメソッドを割り当ててやれば、どのIDのボタンが押されたのかが分かる。

アイコン画像を表示してみた。 :

各ボタンにテキストが表示されてる状態ではツールパネルっぽくないので、試しにアイコン画像を表示してみたり。

_button_test_with_icon.py.txt
u"""
押したままの状態になるボタンを並べてツールパネル相当を作るテスト.

アイコン画像をボタン上に表示してみる版。
"""


import sys
from PySide.QtCore import *  # NOQA
from PySide.QtGui import *  # NOQA


class ToolPanel(QWidget):

    u"""ツールパネル用Widget."""

    button_clicked = Signal(int)  # シグナルを用意

    def __init__(self, *argv, **keywords):
        u"""初期化."""
        super(ToolPanel, self).__init__(*argv, **keywords)

        # 画像を読み込んで分割
        im = QImage("./toolbar_32x32x8.png")
        h = im.size().height()
        imgs = []
        for i in range(8):
            imgs.append(im.copy(i * h, 0, h, h))

        self.grp = QButtonGroup()

        gb = QGridLayout()
        gb.setHorizontalSpacing(0)  # GridLayoutの水平余白を設定
        gb.setVerticalSpacing(0)    # GridLayoutの垂直余白を設定
        dt = [
            (0, 0, 0, "Brush"),
            (1, 0, 1, "Erase"),
            (2, 0, 2, "Line"),
            (3, 0, 3, "Box Line"),
            (4, 0, 4, "Box Fill"),
            (0, 1, 5, "Fill"),
            (1, 1, 6, "Text"),
            (2, 1, 7, "Select"),
        ]
        for x, y, id, s in dt:
            icon = QIcon(QPixmap.fromImage(imgs[id]))  # アイコン画像を生成
            btn = QPushButton(icon, "", self)

            # アイコンサイズを画像の元サイズにする
            btn.setIconSize(imgs[id].size())

            btn.setToolTip(s)  # ツールチップを指定

            btn.setCheckable(True)  # トグルボタンにする
            self.grp.addButton(btn, id)  # グループ登録してラジオボタン風に使う
            gb.addWidget(btn, y, x)
        self.setLayout(gb)
        self.grp.setExclusive(True)  # 排他的なボタン処理にする
        self.grp.button(0).setChecked(True)  # 最初のボタンを押しておく
        self.grp.buttonClicked.connect(self.changed_button)

    def changed_button(self):
        u"""ボタンが押された時に呼ばれる処理."""
        self.button_clicked.emit(self.grp.checkedId())  # シグナルを発生

    def get_id(self):
        u"""選択状態(ID)を返す."""
        return self.grp.checkedId()


class MyMainWidget(QWidget):

    u"""メインウインドウ."""

    def __init__(self, *argv, **keywords):
        u"""初期化."""
        super(MyMainWidget, self).__init__(*argv, **keywords)
        self.tb = ToolPanel(self)
        self.tb.button_clicked.connect(self.changed_toolbox)
        self.lbl = QLabel("----", self)
        self.lbl.setText("ID=%d" % self.tb.get_id())
        l = QVBoxLayout()
        l.addWidget(self.tb)
        l.addWidget(self.lbl)
        self.setLayout(l)

    def changed_toolbox(self, id):
        u"""ツールの選択状態が切り替わった時に呼ばれる処理."""
        self.lbl.setText("ID=%d" % id)


def main():
    u"""メイン処理."""
    app = QApplication(sys.argv)
    app.setStyle(QStyleFactory.create("cleanlooks"))
    # app.setStyle(QStyleFactory.create("plastique"))
    # app.setStyle(QStyleFactory.create("windows"))
    # app.setStyle(QStyleFactory.create("windowsvista"))
    w = MyMainWidget()
    w.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
アイコン画像として、以下を自作した。スクリプトソースも含めて、CC0 / Public Domain ってことで。

toolbar_32x32x8.png
_toolbar_32x32x8.png

こんな見た目になった。

button_test_with_icon_ss01.gif

  • アイコンの指定には、QIcon を使う。QPixmap を渡すと作れるっぽいので、元画像が QImage なら、QIcon(QPixmap.fromImage(qimg)) てな記述になる。
  • QIcon は、自動で画像を縮小して適切なサイズにしてしまうので、元画像サイズで表示したい場合は setIconSize() を呼んで元画像サイズを指定してやる。
  • QGridLayout の水平余白、垂直余白は、setHorizontalSpacing()、setVerticalSpacing() で指定できる。
  • ボタン上にマウスカーソルを合わせた際にピョコッと表示されるツールチップは、setToolTip() で指定できる。
  • 各Widgetの全体的な見た目は、QApplication.setStyle() で変更できる。QStyleFactory.create("cleanlooks") や QStyleFactory.create("plastique") を渡してやると見た目が変わる。指定できる文字列としては、windows、motif、cde、plastique、cleanlooks があるらしい。

_QIcon - PySide v1.0.7 documentation
_QGridLayout - PySide v1.0.7 documentation
_QWidget - PySide v1.0.7 documentation
_QApplication - PySide v1.0.7 documentation
_QStyleFactory - PySide v1.0.7 documentation

以上です。

過去ログ表示

Prev - 2016/11 - Next
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project