簡體   English   中英

在PyQT5中創建自定義小部件

[英]Creating a custom widget in PyQT5

我想知道如何在pyqt中創建自定義小部件。 我已經看到了很多不同的C ++示例,以及pyqt的幾個非描述性示例,但沒有真正解釋如何實現它並實現它。 特別是沒有例子基本上不只是修改了qt-designer輸出,而且我從頭開始編寫我的代碼,所以這不是很有用。

到目前為止,我能找到的最好的例子基本上只是修改qt-designer代碼的人,而不是真正解釋其中的任何代碼

有人可以告訴我一個如何創建自定義小部件的示例嗎?

編輯:我正在嘗試創建一個帶有嵌入式QStackedWidget的小部件,以及底部的按鈕來循環頁面。

我還計划為每個頁面創建一個單獨的小部件,但考慮到我實際上無法完成第一步,我認為當我到達它時我會越過那個橋。

下面展示了如何使用2個按鈕實現QStackedWidget ,基本思路是布局設計,為此我們分析必須放置QVBoxLayout來放置QStackedWidget和另一個布局,第二個布局將是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_())

在此輸入圖像描述

在此輸入圖像描述

在此輸入圖像描述

這里有一些很好的建議,例子和方法。

我認為您可以通過三種方式划分自定義窗口小部件或任何自定義“事物”。

  1. 行為 :使用所需的行為覆蓋其默認方法時。
  2. 布局 :您在布局中添加的所有qt對象,項目或窗口小部件都將遵循其位置規則及其策略。
  3. StyleSheet:如果你在Widget對象中設置了Widget的樣式,那就設置它的“CSS”,只是為了簡潔。 以下是一些參考示例

注意:如果是非Widget對象,您將無法設置StyleSheet,因此您必須覆蓋一些繪制方法,創建自己的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_())

提示:

您還可以在窗口小部件中使用蒙版,以“瘋狂”的方式更改其格式。 例如,如果您需要一個空心環狀小部件,您可以使用這種格式和一些透明度的圖像,從中創建一個QPixMap並將其作為掩碼應用於您的小部件。 不是一件微不足道的工作,而是一種很酷的工作。

因為我發現你沒有“頂欄”無邊框的例子,你也可以在看這個的其他問題,我展示了如何創建自己的頂欄,左右移動和調整大小的概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM