Pyqtでカスタムウィジェットを作成する方法を知りたいです。 C++のさまざまな例と、pyqtの説明のない例をいくつか見てきましたが、それを実行して実装する方法を実際に説明するものは何もありません。特に、基本的にqt-designerの出力を変更しただけではない例はありません。コードを最初から作成しているため、あまり役に立ちません。
これまでのところ、私が見つけた最良の例は 基本的にはqt-designerコードを変更する誰か であり、それが何をしているのかを実際には説明していません。
カスタムウィジェットの作成方法の例を教えてもらえますか?
編集:QStackedWidget
が埋め込まれたウィジェットと、ページを循環するための下部のボタンを作成しようとしています。
また、ページごとにウィジェットを分ける予定でしたが、実際にはステップ1を達成できないことを考えると、そこにたどり着いたらその橋を渡ると思いました。
以下に、2つのボタンでQStackedWidget
を実装する方法を示します。基本的な考え方は、デザインをレイアウトすることです。このため、QVBoxLayout
を配置してQStackedWidget
と別のレイアウトの場合、この2番目のレイアウトはボタンを持つQHBoxLayout
になります。次に、ページ間の遷移を処理する信号を接続します。また、この例では、各ページに配置される3種類のウィジェットを作成しました。
from PyQt5.QtWidgets import *
class Widget1(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent=parent)
lay = QVBoxLayout(self)
for i in range(4):
lay.addWidget(QPushButton("{}".format(i)))
class Widget2(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent=parent)
lay = QVBoxLayout(self)
for i in range(4):
lay.addWidget(QLineEdit("{}".format(i)))
class Widget3(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent=parent)
lay = QVBoxLayout(self)
for i in range(4):
lay.addWidget(QRadioButton("{}".format(i)))
class stackedExample(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent=parent)
lay = QVBoxLayout(self)
self.Stack = QStackedWidget()
self.Stack.addWidget(Widget1())
self.Stack.addWidget(Widget2())
self.Stack.addWidget(Widget3())
btnNext = QPushButton("Next")
btnNext.clicked.connect(self.onNext)
btnPrevious = QPushButton("Previous")
btnPrevious.clicked.connect(self.onPrevious)
btnLayout = QHBoxLayout()
btnLayout.addWidget(btnPrevious)
btnLayout.addWidget(btnNext)
lay.addWidget(self.Stack)
lay.addLayout(btnLayout)
def onNext(self):
self.Stack.setCurrentIndex((self.Stack.currentIndex()+1) % 3)
def onPrevious(self):
self.Stack.setCurrentIndex((self.Stack.currentIndex()-1) % 3)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = stackedExample()
w.show()
sys.exit(app.exec_())
ここにいくつかの素晴らしいアドバイス、例、アプローチがあります。
カスタムウィジェットやカスタムの「もの」を3つの方法で分割できると思います。
注:ウィジェット以外のオブジェクトの場合、スタイルシートを設定できないため、一部のPaintメソッドをオーバーライドし、独自のPainterを作成してなど。
ここに私が上で述べた3つのトピックに近づくことに沿ったいくつかのコメントを伴ういくつかのランダムな例があります:
import random
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
class MovableWidget(QWidget):
def __init__(self):
super(MovableWidget, self).__init__()
#remove the frame
self.setWindowFlags(Qt.CustomizeWindowHint)
self.pressing = False
# overriding the three next methods is a way to customize your Widgets
# not just in terms of appearance but also behavioral.
def mousePressEvent(self, QMouseEvent):
#the pos of the widget when you first pressed it.
self.start = QMouseEvent.pos()
#to make sure you are holding mouse button down
self.pressing = True
def mouseMoveEvent(self, QMouseEvent):
# You can Verify if it's also the left button and some other things
# you need.
if self.pressing : #and QMouseEvent.type() == Qt.LeftButton
self.end = QMouseEvent.pos()
self.delta = self.mapToGlobal(self.end-self.start)
self.move(self.delta)
self.end = self.start
def mouseReleaseEvent(self, QMouseEvent):
self.pressing = False
# inherits from QDialog and from MovableWidget so we can have its properties.
class CustomDialog(QDialog, MovableWidget):
def __init__(self):
super(CustomDialog, self).__init__()
#Make the Dialog transparent
self.setAttribute(Qt.WA_TranslucentBackground)
# the widget will dispose itself according to the layout rules he's
# inserted into.
self.inner_widget = QWidget()
self.inner_widget.setFixedSize(300,300)
self.inner_layout = QHBoxLayout()
self.inner_widget.setLayout(self.inner_layout)
self.btn_change_color = QPushButton("Roll Color")
self.btn_change_color.setStyleSheet("""
background-color: green;
""")
# will connect to a function to be executed when the button is clicked.
self.btn_change_color.clicked.connect(self.change_color)
self.inner_layout.addWidget(self.btn_change_color)
# Choose among many layouts according to your needs, QVBoxLayout,
# QHBoxLayout, QStackedLayout, ... you can set its orientation
# you can set its policies, spacing, margins. That's one of the main
# concepts you have to learn to customize your Widget in the way
# you want.
self.layout = QVBoxLayout()
# stylesheet have basically CSS syntax can call it QSS.
# it can be used only on objects that come from Widgets
# Also one of the main things to learn about customizing Widgets.
# Note: The stylesheet you set in the "father" will be applied to its
# children. Unless you tell it to be applied only to it and/or specify
# each children's style.
# The point I used inside the StyleSheet before the QDialog
# e.g .QDialog and .QWidget says it'll be applied only to that
# instance.
self.setStyleSheet("""
.QDialog{
border-radius: 10px;
}
""")
self.inner_widget.setStyleSheet("""
.QWidget{
background-color: red;
}
""")
self.layout.addWidget(self.inner_widget)
self.setLayout(self.layout)
def change_color(self):
red = random.choice(range(0,256))
green = random.choice(range(0,256))
blue = random.choice(range(0,256))
self.inner_widget.setStyleSheet(
"""
background-color: rgb({},{},{});
""".format(red,green,blue)
)
# since MovableWidget inherits from QWidget it also have QWidget properties.
class ABitMoreCustomizedWidget(MovableWidget):
def __init__(self):
super(ABitMoreCustomizedWidget, self).__init__()
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.custom_button1 = CustomButton("Button 1")
self.custom_button1.clicked.connect(self.btn_1_pressed)
self.custom_button2 = CustomButton("Button 2")
self.custom_button2.clicked.connect(self.btn_2_pressed)
self.layout.addWidget(self.custom_button1)
self.layout.addWidget(self.custom_button2)
def btn_1_pressed(self):
self.custom_button1.hide()
self.custom_button2.show()
def btn_2_pressed(self):
self.custom_button2.hide()
self.custom_button1.show()
class CustomButton(QPushButton):
# it could receive args and keys** so all the QPushButton initializer
# would work for here too.
def __init__(self, txt):
super(CustomButton, self).__init__()
self.setText(txt)
self.setStyleSheet("""
QPushButton{
background-color: black;
border-radius: 5px;
color: white;
}
QPushButton::pressed{
background-color: blue;
}
QPushButton::released{
background-color: gray;
}
""")
if __name__ == "__main__":
app = QApplication(sys.argv)
custom_dialog = CustomDialog()
custom_widget = ABitMoreCustomizedWidget()
custom_dialog.show()
custom_widget.show()
sys.exit(app.exec_())
ウィジェットでマスクを利用して、「クレイジー」な方法でフォーマットを変更することもできます。たとえば、中空のリングウィジェットが必要な場合は、この形式とある程度の透明度を備えた画像を作成し、そこからQPixMapを作成して、ウィジェットにマスクとして適用できます。些細な作業ではありませんが、ちょっとクールです。
フレームのない「TopBar」のない例を示したので、 this 他の質問を見て、独自のトップバーを作成し、移動して、概念のサイズを変更する方法を示します。