【问题标题】:How to reverse the Ticklabels for a QSlider element and how to make it clickable?如何反转 QSlider 元素的 Ticklabels 以及如何使其可点击?
【发布时间】:2019-06-20 22:28:09
【问题描述】:

我在 GUI 中插入了一个 QSlider 元素,并手动添加了一些刻度标签。然而我没有设法颠倒标签的顺序,即从 0-5 而不是 5-0。此外,我无法实现一种可以“单击”值的方式。这个问题是几天前另一个问题的扩展 (How to change the text in QPushbutton within a QButtongroup element after some user input?)

我在 QSlider 文档中查找了选项,并尝试更改 create_slider 函数中的 for 循环。我不知何故不明白为什么这不起作用,但也许它太微不足道了。至于使滑块可点击的尝试,我已经看到了一些解决方案,但我没有设法使它们在我的示例中起作用。

import os
from PyQt5 import QtCore, QtGui, QtWidgets

class App(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setGeometry(50, 50, 400, 500)
        self.initUI()

    def initUI(self):
        self.m_buttons = []
        self.s_labels = []

        group = QtWidgets.QButtonGroup(self)
        left_button = QtWidgets.QPushButton("Left", checkable=True)
        left_button.setFixedSize(100, 30)
        right_button = QtWidgets.QPushButton("Right", checkable=True)
        right_button.setFixedSize(100, 30)
        group.addButton(left_button)
        group.addButton(right_button)
        group.buttonClicked[QtWidgets.QAbstractButton].connect(self.update_text)

        label1 = QtWidgets.QLabel("Test1:")
        label2 = QtWidgets.QLabel("Test2:")

        self.m_widget = QtWidgets.QWidget()
        self.create_buttons()

        left_button.click()

        self.s_widget = QtWidgets.QWidget()
        self.create_slider()

        start_button = QtWidgets.QPushButton("Continue")
        start_button.setFixedSize(100, 50)

        check_button = QtWidgets.QPushButton("Check \nrecordings")
        check_button.setFixedSize(120, 50)

        ## start with the layout of the GUI ------------------------------
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        lay_tot = QtWidgets.QVBoxLayout(central_widget)

        h1lay = QtWidgets.QHBoxLayout()
        h1lay.addStretch(1)
        h1lay.addWidget(left_button)
        h1lay.addWidget(right_button)
        h1lay.addStretch(5)
        lay_tot.addLayout(h1lay)

        h2lay = QtWidgets.QHBoxLayout()
        h2lay.addStretch(1)
        h2lay.addWidget(label1)
        h2lay.addStretch(2)
        h2lay.addWidget(label2)
        h2lay.addStretch(1)
        lay_tot.addStretch(1)
        lay_tot.addLayout(h2lay)

        # insert the horizontal third layer (contacts + slider)
        h3lay = QtWidgets.QHBoxLayout()
        h3lay.addStretch(1)
        h3lay.addWidget(self.m_widget, alignment=QtCore.Qt.AlignCenter)
        h3lay.addStretch(2)
        h3lay.addWidget(self.s_widget, alignment=QtCore.Qt.AlignCenter)
        h3lay.addStretch(3)
        lay_tot.addLayout(h3lay)

        h4lay = QtWidgets.QHBoxLayout()
        h4lay.addStretch(5)
        h4lay.addWidget(check_button,2.4)
        h4lay.addWidget(start_button,2.4)
        h4lay.addStretch(1)

        lay_tot.addStretch(2)
        lay_tot.addLayout(h4lay)

    def create_buttons(self):
        coords = [
            (4, 1),
            (3, 0),
            (3, 1),
            (3, 2),
            (2, 0),
            (2, 1),
            (2, 2),
            (0, 1),
        ]
        group = QtWidgets.QButtonGroup(exclusive=True)
        grid = QtWidgets.QGridLayout(self.m_widget)
        for coord in coords:
            btn = QtWidgets.QPushButton(checkable=True)
            btn.setAutoExclusive(True)
            btn.setFixedSize(70, 50)
            grid.addWidget(btn, *coord)
            group.addButton(btn)
            self.m_buttons.append(btn)

        self.m_widget.setFixedSize(self.m_widget.sizeHint())

    @QtCore.pyqtSlot(QtWidgets.QAbstractButton)
    def update_text(self, btn):
        text = btn.text()
        texts = {
            "Left": ["1", "2", "3", "4", "5", "6", "7", "8"],
            "Right": ["9", "10", "11", "12", "13", "14", "15", "16"],
        }
        if text in texts:
            for btn, txt in zip(self.m_buttons, texts[text]):
                btn.setText(txt)
    def create_slider(self):
        # create the slider for the setting of amplitude
        hlay_slide = QtWidgets.QHBoxLayout(self.s_widget)
        slider = QtWidgets.QSlider(QtCore.Qt.Vertical)
        slider.setTickPosition(QtWidgets.QSlider.TicksLeft)
        slider.setTickInterval(1)
        slider.setSingleStep(.5)
        slider.setRange(0, 5)

        vlay_slide = QtWidgets.QVBoxLayout()
        for idx, val in enumerate(range(6, 0, -1)):
            lblSlider = QtWidgets.QLabel(str(idx))
            vlay_slide.addWidget(lblSlider)

        hlay_slide.addLayout(vlay_slide)
        hlay_slide.addWidget(slider)

if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = App()
    w.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python-3.x user-interface slider pyqt5


    【解决方案1】:

    试试看:

    #import os
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Slider(QtWidgets.QSlider):                                         # + <-----
    
        def mousePressEvent(self, event):
            if event.button() == QtCore.Qt.LeftButton:
                val = self.pixelPosToRangeValue(event.pos())
                self.setValue(val)
            super(Slider, self).mousePressEvent(event)           
    
        def pixelPosToRangeValue(self, pos):
            opt = QtWidgets.QStyleOptionSlider()
            self.initStyleOption(opt)
            gr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderGroove, self)
            sr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)
    
            if self.orientation() == QtCore.Qt.Horizontal:
                sliderLength = sr.width()
                sliderMin = gr.x()
                sliderMax = gr.right() - sliderLength + 1
            else:
                sliderLength = sr.height()
                sliderMin = gr.y()
                sliderMax = gr.bottom() - sliderLength + 1;
            pr = pos - sr.center() + sr.topLeft()
            p = pr.x() if self.orientation() == QtCore.Qt.Horizontal else pr.y()
            return QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), p - sliderMin,
                                                   sliderMax - sliderMin, opt.upsideDown)
    
    
    
    class App(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setGeometry(50, 50, 400, 500)
            self.initUI()
    
        def initUI(self):
            self.m_buttons = []
            self.s_labels = []
    
            group = QtWidgets.QButtonGroup(self)
            left_button = QtWidgets.QPushButton("Left", checkable=True)
            left_button.setFixedSize(100, 30)
            right_button = QtWidgets.QPushButton("Right", checkable=True)
            right_button.setFixedSize(100, 30)
            group.addButton(left_button)
            group.addButton(right_button)
            group.buttonClicked[QtWidgets.QAbstractButton].connect(self.update_text)
    
            label1 = QtWidgets.QLabel("Test1:")
            label2 = QtWidgets.QLabel("Test2:")
    
            self.m_widget = QtWidgets.QWidget()
            self.create_buttons()
    
            left_button.click()
    
            self.s_widget = QtWidgets.QWidget()
    
            self.create_slider()
    
            start_button = QtWidgets.QPushButton("Continue")
            start_button.setFixedSize(100, 50)
    
            check_button = QtWidgets.QPushButton("Check \nrecordings")
            check_button.setFixedSize(120, 50)
    
            ## start with the layout of the GUI ------------------------------
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
    
            lay_tot = QtWidgets.QVBoxLayout(central_widget)
    
            h1lay = QtWidgets.QHBoxLayout()
            h1lay.addStretch(1)
            h1lay.addWidget(left_button)
            h1lay.addWidget(right_button)
            h1lay.addStretch(5)
            lay_tot.addLayout(h1lay)
    
            h2lay = QtWidgets.QHBoxLayout()
            h2lay.addStretch(1)
            h2lay.addWidget(label1)
            h2lay.addStretch(2)
            h2lay.addWidget(label2)
            h2lay.addStretch(1)
            lay_tot.addStretch(1)
            lay_tot.addLayout(h2lay)
    
            # insert the horizontal third layer (contacts + slider)
            h3lay = QtWidgets.QHBoxLayout()
            h3lay.addStretch(1)
            h3lay.addWidget(self.m_widget, alignment=QtCore.Qt.AlignCenter)
            h3lay.addStretch(2)
            h3lay.addWidget(self.s_widget, alignment=QtCore.Qt.AlignCenter)
            h3lay.addStretch(3)
            lay_tot.addLayout(h3lay)
    
            h4lay = QtWidgets.QHBoxLayout()
            h4lay.addStretch(5)
            h4lay.addWidget(check_button,2.4)
            h4lay.addWidget(start_button,2.4)
            h4lay.addStretch(1)
    
            lay_tot.addStretch(2)
            lay_tot.addLayout(h4lay)
    
        def create_buttons(self):
            coords = [
                (4, 1),
                (3, 0),
                (3, 1),
                (3, 2),
                (2, 0),
                (2, 1),
                (2, 2),
                (0, 1),
            ]
            group = QtWidgets.QButtonGroup(exclusive=True)
            grid = QtWidgets.QGridLayout(self.m_widget)
            for coord in coords:
                btn = QtWidgets.QPushButton(checkable=True)
                btn.setAutoExclusive(True)
                btn.setFixedSize(70, 50)
                grid.addWidget(btn, *coord)
                group.addButton(btn)
                self.m_buttons.append(btn)
    
            self.m_widget.setFixedSize(self.m_widget.sizeHint())
    
        @QtCore.pyqtSlot(QtWidgets.QAbstractButton)
        def update_text(self, btn):
            text = btn.text()
            texts = {
                "Left": ["1", "2", "3", "4", "5", "6", "7", "8"],
                "Right": ["9", "10", "11", "12", "13", "14", "15", "16"],
            }
            if text in texts:
                for btn, txt in zip(self.m_buttons, texts[text]):
                    btn.setText(txt)
    
    
        def create_slider(self):
            # create the slider for the setting of amplitude
    
    # -       self.slider = QtWidgets.QSlider(QtCore.Qt.Vertical)
            self.slider = Slider(QtCore.Qt.Vertical)                         # +++
            self.slider.setTickPosition(QtWidgets.QSlider.TicksLeft)
            self.slider.setTickInterval(1)
    #                     setSingleStep(int)        
    # ?       self.slider.setSingleStep(0.5)
            self.slider.setRange(0, 5)
            self.slider.valueChanged.connect(self.valueChangedSlider)
    
            vlay_slide = QtWidgets.QVBoxLayout()
    # -        for idx, val in enumerate(range(6, 0, -1)):
            for idx in range(5, -1, -1):                                     # +++
                lblSlider = QtWidgets.QLabel(str(idx))
                vlay_slide.addWidget(lblSlider)
    
            hlay_slide = QtWidgets.QHBoxLayout(self.s_widget)
            hlay_slide.addLayout(vlay_slide)
            hlay_slide.addWidget(self.slider)
    
    #+++        
        def valueChangedSlider(self, value):
            print("value-> {}".format(value))    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = App()
        w.show()
        sys.exit(app.exec_())
    


    更新

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Slider(QtWidgets.QSlider):                                        
    
        def mousePressEvent(self, event):
            if event.button() == QtCore.Qt.LeftButton:
                val = self.pixelPosToRangeValue(event.pos())
                self.setValue(val)
            super(Slider, self).mousePressEvent(event)           
    
        def pixelPosToRangeValue(self, pos):
            opt = QtWidgets.QStyleOptionSlider()
            self.initStyleOption(opt)
            gr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderGroove, self)
            sr = self.style().subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)
    
            if self.orientation() == QtCore.Qt.Horizontal:
                sliderLength = sr.width()
                sliderMin = gr.x()
                sliderMax = gr.right() - sliderLength + 1
            else:
                sliderLength = sr.height()
                sliderMin = gr.y()
                sliderMax = gr.bottom() - sliderLength + 1;
            pr = pos - sr.center() + sr.topLeft()
            p = pr.x() if self.orientation() == QtCore.Qt.Horizontal else pr.y()
            return QtWidgets.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), p - sliderMin,
                                                   sliderMax - sliderMin, opt.upsideDown)
    
    
    
    class App(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setGeometry(50, 50, 400, 500)
            self.initUI()
    
        def initUI(self):
            self.m_buttons = []
            self.s_labels = []
    
            group = QtWidgets.QButtonGroup(self)
            left_button = QtWidgets.QPushButton("Left", checkable=True)
            left_button.setFixedSize(100, 30)
            right_button = QtWidgets.QPushButton("Right", checkable=True)
            right_button.setFixedSize(100, 30)
            group.addButton(left_button)
            group.addButton(right_button)
            group.buttonClicked[QtWidgets.QAbstractButton].connect(self.update_text)
    
            label1 = QtWidgets.QLabel("Test1:")
            label2 = QtWidgets.QLabel("Test2:")
    
            self.m_widget = QtWidgets.QWidget()
            self.create_buttons()
    
            left_button.click()
    
            self.s_widget = QtWidgets.QWidget()
    
            self.create_slider()
    
            start_button = QtWidgets.QPushButton("Continue")
            start_button.setFixedSize(100, 50)
    
            check_button = QtWidgets.QPushButton("Check \nrecordings")
            check_button.setFixedSize(120, 50)
    
            ## start with the layout of the GUI ------------------------------
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
    
            lay_tot = QtWidgets.QVBoxLayout(central_widget)
    
            h1lay = QtWidgets.QHBoxLayout()
            h1lay.addStretch(1)
            h1lay.addWidget(left_button)
            h1lay.addWidget(right_button)
            h1lay.addStretch(5)
            lay_tot.addLayout(h1lay)
    
            h2lay = QtWidgets.QHBoxLayout()
            h2lay.addStretch(1)
            h2lay.addWidget(label1)
            h2lay.addStretch(2)
            h2lay.addWidget(label2)
            h2lay.addStretch(1)
            lay_tot.addStretch(1)
            lay_tot.addLayout(h2lay)
    
            # insert the horizontal third layer (contacts + slider)
            h3lay = QtWidgets.QHBoxLayout()
            h3lay.addStretch(1)
            h3lay.addWidget(self.m_widget, alignment=QtCore.Qt.AlignCenter)
            h3lay.addStretch(2)
            h3lay.addWidget(self.s_widget, alignment=QtCore.Qt.AlignCenter)
            h3lay.addStretch(3)
            lay_tot.addLayout(h3lay)
    
            h4lay = QtWidgets.QHBoxLayout()
            h4lay.addStretch(5)
            h4lay.addWidget(check_button,2.4)
            h4lay.addWidget(start_button,2.4)
            h4lay.addStretch(1)
    
            lay_tot.addStretch(2)
            lay_tot.addLayout(h4lay)
    
        def create_buttons(self):
            coords = [
                (4, 1),
                (3, 0),
                (3, 1),
                (3, 2),
                (2, 0),
                (2, 1),
                (2, 2),
                (0, 1),
            ]
            group = QtWidgets.QButtonGroup(exclusive=True)
            grid = QtWidgets.QGridLayout(self.m_widget)
            for coord in coords:
                btn = QtWidgets.QPushButton(checkable=True)
                btn.setAutoExclusive(True)
                btn.setFixedSize(70, 50)
                grid.addWidget(btn, *coord)
                group.addButton(btn)
                self.m_buttons.append(btn)
    
            self.m_widget.setFixedSize(self.m_widget.sizeHint())
    
        @QtCore.pyqtSlot(QtWidgets.QAbstractButton)
        def update_text(self, btn):
            text = btn.text()
            texts = {
                "Left": ["1", "2", "3", "4", "5", "6", "7", "8"],
                "Right": ["9", "10", "11", "12", "13", "14", "15", "16"],
            }
            if text in texts:
                for btn, txt in zip(self.m_buttons, texts[text]):
                    btn.setText(txt)
    
    # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv      
    
                    if self.isSignalConnected(btn, 'clicked()'):
                        btn.clicked.disconnect()
                    btn.clicked.connect(self.btnClick)
                    print(f"btn->{btn.text()}")
    
        def btnClick(self):
            sender = self.sender()
            print(f"sender->{sender.text()}")
    
        def isSignalConnected(self, obj, name):
            """ Определите, подключен ли сигнал
            :param obj:        объекты
            :param name:       Имя сигнала, например, clicked()
            """
            index = obj.metaObject().indexOfMethod(name)
            if index > -1:
                method = obj.metaObject().method(index)
                if method:
                    return obj.isSignalConnected(method)
            return False
    
    # +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    
    
        def create_slider(self):
            # create the slider for the setting of amplitude
            self.slider = Slider(QtCore.Qt.Vertical)                         
            self.slider.setTickPosition(QtWidgets.QSlider.TicksLeft)
            self.slider.setTickInterval(1)
            self.slider.setRange(0, 5)
            self.slider.valueChanged.connect(self.valueChangedSlider)
    
            vlay_slide = QtWidgets.QVBoxLayout()
            for idx in range(5, -1, -1):                                    
                lblSlider = QtWidgets.QLabel(str(idx))
                vlay_slide.addWidget(lblSlider)
    
            hlay_slide = QtWidgets.QHBoxLayout(self.s_widget)
            hlay_slide.addLayout(vlay_slide)
            hlay_slide.addWidget(self.slider)
    
        def valueChangedSlider(self, value):
            print("value-> {}".format(value))    
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = App()
        w.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 首先感谢代码。在过去的几天里,我一直试图了解它是如何工作的。但有一件事我无法弄清楚。如何使用文本 1:8 / 9:16 返回第二个按钮组的值。我试图通过 group.buttonClicked[...].connect 获得它,但它不起作用。实际上,按下按钮时没有任何反应。谁能给我一个提示如何设置或问题出在哪里?
    • @umrpedrod 我加了一个例子,试试看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    • 1970-01-01
    • 2012-10-06
    相关资源
    最近更新 更多