QLabelに影を付ける

Tips,PySide,PySide2,Python,Qt,MayaQLabel

Twitterでラベルに影を付けるのは需要があるのかとつぶやいたところ意外と需要があるみたいで今回はラベルに影を付ける方法を書いていきます。

まず、初めにmainWindowになるWindowを作ります。
文字が見えやすいようにQPalette()を使用して背景色を白色にしておきます。
表示位置はsetGeometryで自分の表示したい位置に数値を変更してください。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Qt.QtGui import*
from Qt.QtCore import*
from Qt.QtWidgets import*

import maya.OpenMayaUI as OpenMayaUI

try:
    import shiboken
except:
    import shiboken2 as shiboken

ptr = OpenMayaUI.MQtUtil.mainWindow()
parent = shiboken.wrapInstance(long(ptr), QWidget)

class LabelShadow(QMainWindow):
    def __init__(self):
        super(LabelShadow, self).__init__(parent)
        self.setGeometry(300, 400, 300, 200)
        p = QPalette()
        p.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(p)

def main():
        app = QApplication.instance()
        gui = LabelShadow()
        gui.show()
        sys.exit()
        app.exec_()

if __name__ == '__main__':
        main()

上のコードを実行すると下の画像のように真っ白なWindowが表示されたかと思います
サイトと同化してしまうので枠線入れてます

次にMainWindowに埋め込む、widgetを作っていきましょう

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")

上のコードのようにwidgetというQWidgetのクラスを用意します。
ラベルを置くとデフォルトが真っ白なのでまずはButtonを用意します。

class LabelShadow(QMainWindow):
    def __init__(self):
        super(LabelShadow, self).__init__(parent)
        self.setGeometry(300, 400, 300, 200)
        self.setCentralWidget(widget())
        p = QPalette()
        p.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(p)

そして上のコードのように記述すると下の画像のように真っ白いWindowのなかにボタンがぽつーんとしたwindowが表示されます

これでは少し見た目が微妙なので位置を調整します。
今回はQVBoxLayoutを使って位置を調整したいと思います。
QVBoxLayoutの説明はざっくりとこんな感じです。
PySide.QtGui.QVBoxLayoutクラスはウィジェットを垂直方向に並べるクラスで、垂直ボックスレイアウトオブジェクトを構築するために使います。
最も簡単な使い方は、レイアウトに必要なウィジェットを用意し、PySide.QtGuiを作成します。
次にQVBoxLayoutオブジェクトを作成し、ウィジェットをレイアウトに追加します。
最後にQWidget.setLayout()を呼び出して、PySide.QtGuiをインストールします。

window =  QWidget()
button1 =  QPushButton("One")
button2 =  QPushButton("Two")
button3 =  QPushButton("Three")
button4 =  QPushButton("Four")
button5 =  QPushButton("Five")

layout =  QVBoxLayout()

layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(button3)
layout.addWidget(button4)
layout.addWidget(button5)

window.setLayout(layout)
window.show()

上のコードを実行すると下の画像のようなボタンが大量にレイアウトされたwindowが表示されると思います

先のことを踏まえたうえでQVBoxLayoutを設定していきます。

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")
        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")
        VBox.addWidget(Button)
        self.setLayout(VBox)

上のコードを追記して実行すると下の画像のようにボタンがセンターに表示されたwindowが表示されます

補足
QVBoxLayoutのほかにQHBoxLayoutQGridLayoutなどのレイアウトがあるので試してみてください。

さて、題名の通りラベルに影をつけるのでQLabelを使ってLabelを用意していきたいと思います。
今回は四種類のラベルを用意します。
もちろんラベルをそのまま用意するだけではだめなのでレイアウトも同時に設定していきます。
いつもは内包表記を使うのですが見た目の都合上for文で用意しました。
内包表記でQtGuiを用意するのは便利なのでぜひ使ってみてください
複雑なものになっていくとコードがとても長くなります。

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")
        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")
        Labels = []
        Label = ["Red alpha: 50", "Green alpha: 127",
        "Blue alpha: 255", "steelblue"]
        for i in range(len(Label)):
            Labels.append(QLabel("%s" % (Label[i]), self))
            VBox.addWidget(Labels[i])

        VBox.addWidget(Button)
        self.setLayout(VBox)

上のコードを実行すると下の画像のようにとにかくまっしろ文字も真っ白、このままでは白過ぎてこまる!というようなものが表示されてしまいます

ということでsetStyleSheetを使ってフォントに色、
そして、細すぎても見にくいので太さ、そしてfontサイズを設定していきましょう。

.setStyleSheet("""
    QLabel{
        color: #303030;
        font-weight: bold;
        font-size: 16px;
    }""")

よくsetStyleSheetを使用して上のコードのような記述で書かれているものがあるのですが個人的にはあまりお勧めしてません。
というのも統一感を出したりするときにこのコードで直接書いてしまうとコードが長くなってしまうのと
一つ変更したときにすべて変更するのがすごくめんどくさくなるからです。

LabelQSS = ("""
    QLabel{
        color: #303030;
        font-weight: bold;
        font-size: 16px;
    }""")

個人的には上のように関数にまとめてコードを記述したものを用意して、setStyleSheetに読み込めば後で変更する際にもとても簡単に一括変更することができます。

QLabel{
    background-color: #5285a6;
    color: #303030;
    font-weight: bold;
    font-size: 16px;
}

一番おすすめする方法はCSSのようにstylesheet.qssというようなファイルを用意してQtGui.QApplication自体にsetStyleSheetしても変更できます。
個人的に上の方法が好きなので専用の.qssを用意しています。
今回はそこまで複雑なものではないのでclass LabelShadow(QMainWindow):の上らへんに関数LabelQSSを記述しておきましょう。

LabelQSS = ("""
QLabel{
    color: #303030;
    font-weight: bold;
    font-size: 16px;
}
""")
class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")
        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")
        Labels = []
        Label = ["Red alpha: 50", "Green alpha: 127",
        "Blue alpha: 255", "steelblue"]
        for i in range(len(Label)):
            Labels.append(QLabel("%s" % (Label[i]), self))
            Labels[i].setStyleSheet(LabelQSS)
            VBox.addWidget(Labels[i])
        VBox.addWidget(Button)
        self.setLayout(VBox)

さて、うまく太文字で出たでしょうか?

ここでやっと本題の影!
どうやって影を付けていくのかというとQGraphicsDropShadowEffectというものを使います。
まあその名の通りドロップシャドウ効果が使えます。

QGraphicsDropShadowEffectの説明はざっくりとこんな感じです。
PySide.QtGui.QGraphicsDropShadowEffectクラスはドロップシャドウ効果を使えます。
ドロップシャドウエフェクトはソースをドロップシャドウでレンダリングしています。
ドロップシャドウの色は、PySide.QtGui.QGraphicsDropShadowEffect.setColor()で
変化させることができます。
ドロップシャドウのオフセットは、PySide.QtGui.QGraphicsDropShadowEffect.setOffset()
ドロップシャドウのぼかしの半径は、PySide.QtGui.QGraphicsDropShadowEffect.setBlurRadius()
で変化させることができます。

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")
        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")
        Labels = []
        Label = ["Red alpha: 50", "Green alpha: 127",
        "Blue alpha: 255", "steelblue"]
        for i in range(len(Label)):
            Labels.append(QLabel("%s" % (Label[i]), self))
            Labels[i].setStyleSheet(LabelQSS)
            VBox.addWidget(Labels[i])
        VBox.addWidget(Button)
        Shadow = QGraphicsDropShadowEffect(self)
        Shadow.setBlurRadius(1)
        Shadow.setColor(QColor (63, 63, 63, 180))
        Shadow.setOffset(20, 20)
        Labels[0].setGraphicsEffect(Shadow)
        self.setLayout(VBox)

とりあえず、上のコードのようにLabels[0]とLabels[1]に設定して実行すると影が出ます。

しかし、Labels[0]とLabels[1]に設定したはずがLabels[1]にしか設定できていません。
じつはQGraphicsDropShadowEffect一つのオブジェクトに対して1ずつしかセットできないのです。
ですのでループを使って必要な分だけ用意しましょう。
せっかくなのでボタンにも影を付けていきたいと思います。

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")

        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")

        Labels = []
        Label = ["Red alpha: 50", "Green alpha: 127",
        "Blue alpha: 255", "steelblue"]
        for i in range(len(Label)):
            Labels.append(QLabel("%s" % (Label[i]), self))
            Labels[i].setStyleSheet(LabelQSS)
            VBox.addWidget(Labels[i])

        VBox.addWidget(Button)
        Shadows = []
        for i in range(5):
            Shadows.append(QGraphicsDropShadowEffect(self))
            Shadows[i].setBlurRadius(10 * i)
            Shadows[i].setOffset(5 * i + 5, 2 * i + 5)
            if i == 4:
                Button.setGraphicsEffect(Shadows[i])
            else:
                Labels[i].setGraphicsEffect(Shadows[i])

        Shadows[0].setColor(QColor(227, 71, 126, 50))
        Shadows[1].setColor(QColor(86, 161, 62, 127))
        Shadows[2].setColor(QColor(61, 158, 199, 255))
        Shadows[3].setColor(QColor("steelblue"))
        Shadows[4].setColor(QColor("#774b75"))
        self.setLayout(VBox)

上のコードを実行すると下の画像のようにカラフルな影がついたwindowが表示されます

以上がLabelに色を付ける方法です!

これを使えばちょっとおしゃれなUIが作れるかも?ぜひ、試してください。

今回使ったフルソースです。


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Qt.QtGui import*
from Qt.QtCore import*
from Qt.QtWidgets import*

import maya.OpenMayaUI as OpenMayaUI

try:
    import shiboken
except:
    import shiboken2 as shiboken

ptr = OpenMayaUI.MQtUtil.mainWindow()
parent = shiboken.wrapInstance(long(ptr), QWidget)

LabelQSS = ("""QLabel{
                    color: #303030;
                    font-weight: bold;
                    font-size: 16px;
                    }""")

class LabelShadow(QMainWindow):
    def __init__(self):
        super(LabelShadow, self).__init__(parent)
        self.setGeometry(300, 400, 300, 200)
        self.setCentralWidget(widget())
        p = QPalette()
        p.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(p)

class widget(QWidget):
    def __init__(self, parent=None):
        super(widget, self).__init__(parent)
        Button = QPushButton(self)
        Button.setText("Text Button")
        VBox = QVBoxLayout()
        VBox.setObjectName("VLayout")
        Labels = []
        Label = ["Red alpha: 50", "Green alpha: 127",
        "Blue alpha: 255", "steelblue"]
        for i in range(len(Label)):
            Labels.append(QLabel("%s" % (Label[i]), self))
            Labels[i].setStyleSheet(LabelQSS)

            VBox.addWidget(Labels[i])
        VBox.addWidget(Button)
        Shadows = []
        for i in range(5):
            Shadows.append(QGraphicsDropShadowEffect(self))
            Shadows[i].setBlurRadius(10 * i)
            Shadows[i].setOffset(5 * i + 5, 2 * i + 5)
            if i == 4:
                Button.setGraphicsEffect(Shadows[i])
            else:
                Labels[i].setGraphicsEffect(Shadows[i])

        Shadows[0].setColor(QColor(227, 71, 126, 50))
        Shadows[1].setColor(QColor(86, 161, 62, 127))
        Shadows[2].setColor(QColor(61, 158, 199, 255))
        Shadows[3].setColor(QColor("steelblue"))
        Shadows[4].setColor(QColor("#774b75"))
        self.setLayout(VBox)

def main():
        app = QApplication.instance()
        ex = LabelShadow()
        ex.show()
        sys.exit()
        app.exec_()

if __name__ == '__main__':
        main()

詳しく
QGraphicsColorizeEffect: 色を付けるエフェクト
QGraphicsOpacityEffect: 不透明のエフェクト

上記のようなエフェクトがあります。また、フェードイン、アウトさせたり、色を変化させたりすることができる。