在PyQT5中创建自定义小部件

Jos*_*rot 5 python qt pyqt python-3.x pyqt5

我想知道如何在pyqt中创建自定义窗口小部件。我见过许多C ++的示例,还有pyqt的两个非描述性示例,但是没有什么能真正解释如何实现和实现它。尤其是没有示例,基本上不只是修改过的qt-designer输出,而且我是从头开始编写代码的,所以这样做不是很有帮助。

到目前为止,我能找到的最好的例子基本上只是一个修改qt-designer代码的人,而没有真正解释它的作用。

有人可以向我展示如何创建自定义小部件的示例吗?

编辑: 我正在尝试创建一个带有嵌入式的窗口小部件QStackedWidget,并在底部单击按钮以循环页面。

我还计划为每个页面使用单独的小部件,但是考虑到我实际上无法完成第一步,我认为当我到达该步骤时,我会越过那座桥梁。

eyl*_*esc 6

下面显示了如何QStackedWidget使用2个按钮实现a ,基本思想是布局设计,为此,我们分析QVBoxLayout必须放置a 来放置QStackedWidgetand布局,第二个布局将是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_())
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明


yur*_*snm 5

这里有一些很好的建议、例子和方法。

我认为您可以通过三种方式划分自定义小部件或任何您想要的自定义“事物”。

  1. 行为:当您使用所需的行为覆盖其默认方法时。
  2. 布局:您在布局中添加的所有 qt 对象(项目或小部件)都将遵循其位置规则及其策略。
  3. StyleSheet:对于设置 Widget 样式的 Widget 对象,为了简洁起见,我们可以说设置其“CSS”。以下是一些参考资料示例

注意:如果是非 Widget 对象,您将无法设置样式表,因此您必须重写一些绘制方法,创建自己的 Painters 等。


以下是一些随机示例,其中包含一些针对我上面提到的 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_())
Run Code Online (Sandbox Code Playgroud)

尖端:

您还可以在小部件中使用蒙版,以“疯狂”的方式更改其格式。例如,如果您需要一个空心环形小部件,您可以拥有具有这种格式和一定透明度的图像,从中创建一个 QPixMap 并将其作为遮罩应用到您的小部件。这不是一项微不足道的工作,但很酷。

由于我向您展示了没有“TopBar”且没有框架的示例,因此您还可以查看另一个问题,其中我展示了如何创建您自己的顶部栏、移动和调整概念大小。