[Python] PySide+CSSでオシャンティなUIを作ろう その1 [PySide]
近頃、TA界隈でPySideを使用したオシャンティなUIを作る動きが賑わっているようなので
私もオシャンティになるべくちまちま作っていこうと思います。
デフォルトだといわゆる古き良きWindowsなUIになってしまうPySideですが
1 Painterで自分で描画して、オリジナルのWidgetを作成する
2 既存のWidgetをCSSでカスタマイズする
このいずれかで見た目のカスタマイズをすることができます。
今回は、この2つのうちの後者 CSSによるカスタマイズをメインにして、オリジナルのWidgetを
作っていく形で作成します。
こちらの利点ですが、複数のデザインの差し替えが容易だったり
デフォルトで用意されているQtDesignerを使用してのレイアウトの作成ができたり
(前者であっても、オリジナルWidgetをDesignerで使用できたりしますが)
すでに作ってあるUIにデザインを乗せることができたりというのがメリットです。当初は描画するよりCSSでやるだけの方が楽かなと言う安易な期待があったけど裏切られた模様
まずは最終目標をざっくり書き出し。
こういうのを書くのにiPad超便利です。
目標は
- FlatなUIデザイン
- 色の変更ができる
- Menu・Mainの構造(Menuはたためる)
- Widgetの見た目をスタイリッシュでオシャンティにする
以上。
Menuには各種ボタンを配置できて、WidgetはMainに配置出来るようにするようにしていきます。
CSSについては、既存でよく使いそうなものから調整していきます。
全体の色ですが
色センス0なので、既存の色パレット作成サービスを利用していきます。
今回は↑を利用して、6色をUI上に配置していく(この6色は簡単に差し替えできるように)
していきます。
というわけで前置き終了で、実際に作っていきます。
まずは全体のベースとなる Main・Menuの構造をつくります。
これには「GroupBox」とLayoutを使用します。
Menu用のGroupBoxとMain用のGroupBoxを配置
このままだと、UIのマージンが多くてフラットじゃないので、全部0にします。
そして、QGroupBoxのTitleを空にします。
そうすると、こんな感じできりわけできます。
次に、menu幅を固定して、色づけします。
menu側のQObject名を「menuBox」として、sizePolicyをHorizontal → FIxed
サイズをとりあえず300にしておきます。
この段階で一度保存して、 .ui を .py に変換します。
1 2 3 |
pyside-uic -o ../PySideTest/ui/solid_ui_test.py solid_ui_test.ui |
コマンドラインで pyside-uic -o <出力先> <.uiファイルのパス> でコンバートできます。
続いて実装側。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# -*- coding: utf-8 -*- import sys import re from PySide import QtGui, QtCore from ui import solid_ui_test class TestWindow(QtGui.QDialog): # http://www.colorblender.com これで6色指定 css_color_setting = { "color_01":"#5283FF", "color_02":"#395CB3", "color_03":"#B8CCFF", "color_04":"#818FB3", "color_05":"#000000", "color_06":"#FFFFFF" } def __init__(self, parent=None): super(TestWindow, self).__init__(parent) self.ui = solid_ui_test.Ui_Form() self.ui.setupUi(self) self.setCSS() def setCSS(self): """ CSSファイルを読み込む。 """ with open("test_css.css", 'r') as f: css_text = "".join(f.readlines()) for key in self.css_color_setting: css_text = re.sub("\$" + key, self.css_color_setting[key], css_text) self.setStyleSheet(css_text) if __name__ == '__main__': app = QtGui.QApplication(sys.argv) a = TestWindow() a.show() sys.exit(app.exec_()) |
とりあえず基本部分のみだとこんな感じになります。
PySideは、setStyleSheetでスタイルシートを適応することが出来ますが、この中に1行づつ書いて行くのはムリがあるので
外部ファイルとして用意してあげてfile_openでロードしてあげるようにします。
色指定はCSSファイル内に書くことが出来ますが、それだと色変更などが若干面倒なので
色指定(基本6色)はメイン処理側で指定出来た方が都合が良いので、Dict型で配列を用意して
置きかえを出来るようにしておきます。
最後にCSSファイル。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* ------------------------------------ CSSのテンプレファイル python側で調整したい値は $~~~~ という値で指定。 ------------------------------------*/ /*全体*/ *{ font : 13px; border : 0px solid; background: $color_06; color : $color_05; } QGroupBox#menuBox{ background-color: $color_02; color :$color_05; border : 0px solid; } |
基本的な書き方は、Web界隈で使用される一般的なスタイルシートの書き方同様です。
Widgetのクラス名#オブジェクト名::サブコントロール:状態{
param : value;
}
PySide的なルールとしては、↑のような形でWidgetを指定することになります。
self.setStyleSheet() は、適応したWidgetとその子Widgetすべてに対して適応されます。
そのため、適応範囲を限定したい場合は、オブジェクト名を指定する必要があります。
今回の場合は、Menu部分にのみMenuの背景色を適応したいので、Designerで指定した
オブジェクト名を、#menuBox という形で指定するようにしています。
サブコントロール というのは、その名の通り変更したいWidgetに付随する
オブション的なコントローラー単位でCSSを適応したい場合に使用します。
詳しくは次回以降に書きますが、TableViewのセルであったり、SpinBoxの↑↓ボタンであったりのように
1つのWidgetの中のパーツを指定して変更したい場合に使用するのがサブコントロールです。
サブコントロールは http://doc.qt.io/qt-5/stylesheet-reference.html 公式サイトにどれにどんな
サブコントロールがあるかが記載されているので、それを参考に指定すればOKです。
色の指定部分の $XXXX は、今回の特殊仕様というか通常の書き方ではなく
Python側でロードしたときにReplaceStringするためのキーワードとして$~~~ という書き方をしています。
これは、css_color_settingのdict型のkeyとvalueと対応しています。
基本6をコレで指定してますが、必要ならばこのdictに要素を追加して
CSS側では$XXX で指定すれば、色の差し替えなどは対応できるようにします。
以上までやると
メニュー部分の土台ができあがりました。
次に、このメニューを閉じられるようにします。
先ほどのDesignerでのUIに、上のようなボタンを作成し、コンバートします。
そして、先ほどのCSSにButton部分の色調整を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/*Buttonの設定*/ QPushButton{ color :$color_06; background-color: $color_02; border : 0px; } QPushButton:hover{ background-color:$color_01; border : 0px; font : bold 14px; } QPushButton:pressed{ background-color: $color_03; color : $color_06; } |
ボタンのように、通常・マウスが乗る(hover)・押す(pressed) のような状態ごとの調整をしたい場合は
クラス:状態 {} のような形で指定します。
最後に、メインのコードも書き換えます。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# -*- coding: utf-8 -*- import sys import re from PySide import QtGui, QtCore from ui import solid_ui_test class TestWindow(QtGui.QDialog): collapse_menu = False padding = 10 menu_min = 30 menu_max = 300 buttons = [] # http://www.colorblender.com これで6色指定 css_color_setting = { "color_01":"#5283FF", "color_02":"#395CB3", "color_03":"#B8CCFF", "color_04":"#818FB3", "color_05":"#000000", "color_06":"#FFFFFF" } def __init__(self, parent=None): super(TestWindow, self).__init__(parent) self.ui = solid_ui_test.Ui_Form() self.ui.setupUi(self) self.ui.minMenuBtn.clicked.connect(self.changeMenuSize) self.setCSS() def setCSS(self): """ CSSファイルを読み込む。 """ with open("test_css.css", 'r') as f: css_text = "".join(f.readlines()) for key in self.css_color_setting: css_text = re.sub("\$" + key, self.css_color_setting[key], css_text) self.setStyleSheet(css_text) def changeMenuSize(self): """ menuを開閉する """ if self.collapse_menu: self.ui.menuBox.setMaximumWidth(self.menu_max) self.ui.menuBox.setMinimumWidth(self.menu_max) self.collapse_menu = False [x.setMinimum() for x in self.buttons] self.ui.minMenuBtn.setText("<<") else: self.ui.menuBox.setMaximumWidth(self.menu_min + self.padding) self.ui.menuBox.setMinimumWidth(self.menu_min + self.padding) self.collapse_menu = True [x.setMinimum() for x in self.buttons] self.ui.minMenuBtn.setText(">>") if __name__ == '__main__': app = QtGui.QApplication(sys.argv) a = TestWindow() a.show() sys.exit(app.exec_()) |
動作させるとこんな感じになります。
やってることは、menuBoxの横サイズを置き換えているだけです。
とりあえずこれでMenu部分の準備が完了して、CSSで調整出来る下地ができました。
ので、次回はMenuのボタンを作成していく所を作ろうと思います。
オシャンティまでの道は長い。。。。。