循环从按钮更改多种小部件样式

时间:2019-05-12 02:22:01

标签: pyqt5 python-3.7

我正在使用PyQt5制作一个GUI,此GUI在页面顶部有几个按钮,可根据选择更改较低StackedWidget的索引。单击该按钮时,所选按钮会将所选按钮的样式表更改为selected_style,但将所有其他样式更改为unselected_style。我读到最简单,最通用的方法是每行添加单个动作。但这已经变得非常多余,最终导致行数过多。目前,这是由单行实现的,例如:

self.pshBtn_1.clicked.connect(lambda: self.stckWdgt.setCurrentIndex(0))
self.pshBtn_1.clicked.connect(lambda: self.pshBtn_1.setStyleSheet(selected)
self.pshBtn_1.clicked.connect(lambda: self.pshBtn_2.setStyleSheet(unselected)
self.pshBtn_1.clicked.connect(lambda: self.pshBtn_3.setStyleSheet(unselected)

self.pshBtn_2.clicked.connect(lambda: self.stckWdgt.setCurrentIndex(1))
self.pshBtn_2.clicked.connect(lambda: self.pshBtn_2.setStyleSheet(selected)
self.pshBtn_2.clicked.connect(lambda: self.pshBtn_1.setStyleSheet(unselected)
self.pshBtn_2.clicked.connect(lambda: self.pshBtn_3.setStyleSheet(unselected)

# And so on, and so on, and so on

我试图遍历self下函数中的按钮名称列表,但是我一直以NameErrors结尾。像这样:

self.pshBtn_1.clicked.connect(self.set_btn_style, pshBtn_1)
self.pshBtn_2.clicked.connect(self.set_btn_style, pshBtn_2)
self.pshBtn_3.clicked.connect(self.set_btn_style, pshBtn_3)

btn_dict = {pshBtn_1 : 0, pshBtn_2: 1, pshBtn_3: 2} #Button Name, Stacked Widget Index

def set_btn_style(self, var_name):
    for i, j in btn_dict:
        btn_name = i
        idx = j
        if btn_name  == var_name:
            self.keyname.setStyleSheet(button_selected)
            self.stckWdgt.setCurrentIndex(idx))
        else:
            self.btn.setStyleSheet(button_unselected)

我猜这里最大的问题是如何让几个按钮或GUI动作使用一个函数,但是将特定的tableWidget,stackWidget等作为参数传递,所以我不必重复某些函数10我想使用该功能的每个按钮的次数。谢谢。

2 个答案:

答案 0 :(得分:2)

最简单的方法是启用QPushButtons的checkable属性,然后将其用作Qt样式表中的过滤器,而不是每次按下按钮时都设置样式表。要更改页面并仅选择一个页面,请使用QButtonGroup。

from PyQt5 import QtCore, QtWidgets


QSS = """
Button {
  background-color: #00ff00;
}

Button:checked {
  background-color: #ff0000;
}
"""


class Button(QtWidgets.QPushButton):
    pass


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        page1 = QtWidgets.QLabel("page1", alignment=QtCore.Qt.AlignCenter)
        page2 = QtWidgets.QLabel("page2", alignment=QtCore.Qt.AlignCenter)
        page3 = QtWidgets.QLabel("page3", alignment=QtCore.Qt.AlignCenter)

        options = ["Page1", "Page2", "Page3"]
        stackedwidget = QtWidgets.QStackedWidget()

        hlay = QtWidgets.QHBoxLayout()
        group = QtWidgets.QButtonGroup(self)
        group.buttonClicked[int].connect(stackedwidget.setCurrentIndex)

        for i, (option, widget) in enumerate(zip(options, (page1, page2, page3))):
            button = Button(text=option, checkable=True)
            ix = stackedwidget.addWidget(widget)
            group.addButton(button, ix)
            hlay.addWidget(button)
            if i == 0:
                button.setChecked(True)

        vbox = QtWidgets.QVBoxLayout(self)
        vbox.addLayout(hlay)
        vbox.addWidget(stackedwidget)


if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("fusion")
    app.setStyleSheet(QSS)
    w = Widget()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

答案 1 :(得分:1)

我经常遇到这个问题,我想将小部件名称传递给另一个函数。我可以通过制作一个嵌套的字典来解决此问题,该字典将一个项目链接到我想传递的小部件名称。该函数在主类的for循环中调用。在函数中,我使用self.sender()sending_button.objectName()来获取用于启动函数的项目的名称。

class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Ui_MainWindow, self).__init__(parent)
        self.setupUi(self)

        # ^^ Up here would be a bunch of buttons I want to do something with

        # Make a nested Dictionary to hold the string name of button, 
        # the actual widget name, and the stacked widget index it corresponds to.

        self.btn_change_sel = {'pushButton_1': {self.pushButton_1: 0},
                              'pushButton_2': {self.pushButton_2: 1} }

        # if any button is pressed, launch function.
        for item in self.btn_change_sel.keys():
            for button in self.btn_change_sel[item].keys():
                button.clicked.connect(self.btn_style_change)  


    def btn_style_change(self):
        sending_button = self.sender()
        check_sender = str(sending_button.objectName())  # Get the string name of sender button
        for sender_name in self.btn_change_sel.keys():   # Get string name to match

            # If the clicked button matches the string value, do some stuff
            if check_sender == sender_name:
                for btn_item in self.btn_change_sel[sender_name].keys():
                    btn_item.setStyleSheet(self.button_selected)
                for stack_idx in self.btn_change_sel[sender_name].values():
                    self.stackedWidget_all.setCurrentIndex(stack_idx)
            # Do something with all other buttons not selected, change to a different style
            if check_sender != sender_name:
                for btn_item2 in self.btn_change_sel[sender_name].keys():
                    btn_item2.setStyleSheet(self.button_unselected)

因此,在此示例中,如果单击的按钮匹配,它将更改样式表并选择与按钮单击相对应的stackedWidget。所有其他人都会收到未选中的样式。这使显示的小部件按钮变得不同,因此您可以轻松分辨出您所在的小部件页面。