繁体   English   中英

PyQt Slider小部件对齐问题

[英]PyQt Slider widget alignment issue

我有一个滑块,其刻度线应带有年份的名称。 下面的代码有效,但是刻度线的标签未正确对齐。 每年的数字都应在刻度旁。

class Slider(QWidget):
    def __init__(self, minimum, maximum, parent=None):
        super(Slider, self).__init__(parent=parent)
        container = QtGui.QWidget(self)        
        layout = QHBoxLayout(container)
        self.sl = QSlider(Qt.Vertical)
        self.sl.setMinimum(minimum)
        self.sl.setMaximum(maximum)
        self.sl.setValue(minimum)
        self.sl.setTickPosition(QSlider.TicksLeft)
        self.sl.setTickInterval(1)
        self.sl.setSingleStep(1)
        self.sl.valueChanged.connect(self.valuechange)
        self.setLayout(layout)
        self.sl.resize(100,3000)        
        layout.addWidget(self.sl)

        for i in range(minimum, maximum + 1):
            label = QLabel(str(i))
            label.setContentsMargins(0, 0, 0, 0)
            label.setAlignment(QtCore.Qt.AlignLeft)
            layout.addWidget(label)

        container.setStyleSheet("background-color:red;")

此外,调整滑块的大小也不起作用。 我不确定我在这里做错什么。滴答标签目前看起来像这样。

在此处输入图片说明

代码中的主要问题之一是,除了将标签放置在具有取决于最小值的索引的列中之外,而不是从0到所需的数字开始,您将标签水平放置而不是垂直放置,另一个问题是必须从最大值到最小值开始。

import sys
from pyqtgraph.Qt import QtCore, QtGui

class Slider(QtGui.QWidget):
    def __init__(self, minimum, maximum, parent=None):
        super(Slider, self).__init__(parent=parent)
        layout = QtGui.QGridLayout(self)
        self.sl = QtGui.QSlider(QtCore.Qt.Vertical)
        self.sl.setMinimum(minimum)
        self.sl.setMaximum(maximum)
        self.sl.setValue(minimum)
        self.sl.setTickPosition(QtGui.QSlider.TicksLeft)
        self.sl.setTickInterval(1)
        self.sl.setSingleStep(1)

        self.sl.valueChanged.connect(lambda value: print(value))

        for index, value in enumerate(range(maximum, minimum-1, -1)):
            label = QtGui.QLabel("{}".format(value))
            layout.addWidget(label, index, 0, QtCore.Qt.AlignLeft)

        layout.addWidget(self.sl, 0, 1, maximum - minimum + 1, 1, QtCore.Qt.AlignLeft)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = Slider(2015, 2019)
    w.show()
    sys.exit(app.exec_())

在此处输入图片说明

我发现了这个hack ,经过一番混乱之后,我设法进行了一些修改将其翻译为python。 您可以指定方向,也可以给定自定义标签文本数组,而不是整数级别。

需要注意的是,要真正引用QSlider,必须使用slider.sl ,例如, slider.sl.valueChanged.connect(someFunc)

(我使用的是PyQt5,导入与pyqtgraph有点不同。)

import sys
from PyQt5 import QtWidgets
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QStyle, QStyleOptionSlider
from PyQt5.QtCore import QRect, QPoint, Qt


class LabeledSlider(QtWidgets.QWidget):
    def __init__(self, minimum, maximum, interval=1, orientation=Qt.Horizontal,
            labels=None, parent=None):
        super(LabeledSlider, self).__init__(parent=parent)

        levels=range(minimum, maximum+interval, interval)
        if labels is not None:
            if not isinstance(labels, (tuple, list)):
                raise Exception("<labels> is a list or tuple.")
            if len(labels) != len(levels):
                raise Exception("Size of <labels> doesn't match levels.")
            self.levels=list(zip(levels,labels))
        else:
            self.levels=list(zip(levels,map(str,levels)))

        if orientation==Qt.Horizontal:
            self.layout=QtWidgets.QVBoxLayout(self)
        elif orientation==Qt.Vertical:
            self.layout=QtWidgets.QHBoxLayout(self)
        else:
            raise Exception("<orientation> wrong.")

        # gives some space to print labels
        self.left_margin=10
        self.top_margin=10
        self.right_margin=10
        self.bottom_margin=10

        self.layout.setContentsMargins(self.left_margin,self.top_margin,
                self.right_margin,self.bottom_margin)

        self.sl=QtWidgets.QSlider(orientation, self)
        self.sl.setMinimum(minimum)
        self.sl.setMaximum(maximum)
        self.sl.setValue(minimum)
        if orientation==Qt.Horizontal:
            self.sl.setTickPosition(QtWidgets.QSlider.TicksBelow)
            self.sl.setMinimumWidth(300) # just to make it easier to read
        else:
            self.sl.setTickPosition(QtWidgets.QSlider.TicksLeft)
            self.sl.setMinimumHeight(300) # just to make it easier to read
        self.sl.setTickInterval(interval)
        self.sl.setSingleStep(1)

        self.layout.addWidget(self.sl)

    def paintEvent(self, e):

        super(LabeledSlider,self).paintEvent(e)

        style=self.sl.style()
        painter=QPainter(self)
        st_slider=QStyleOptionSlider()
        st_slider.initFrom(self.sl)
        st_slider.orientation=self.sl.orientation()

        length=style.pixelMetric(QStyle.PM_SliderLength, st_slider, self.sl)
        available=style.pixelMetric(QStyle.PM_SliderSpaceAvailable, st_slider, self.sl)

        for v, v_str in self.levels:

            # get the size of the label
            rect=painter.drawText(QRect(), Qt.TextDontPrint, v_str)

            if self.sl.orientation()==Qt.Horizontal:
                # I assume the offset is half the length of slider, therefore
                # + length//2
                x_loc=QStyle.sliderPositionFromValue(self.sl.minimum(),
                        self.sl.maximum(), v, available)+length//2

                # left bound of the text = center - half of text width + L_margin
                left=x_loc-rect.width()//2+self.left_margin
                bottom=self.rect().bottom()

                # enlarge margins if clipping
                if v==self.sl.minimum():
                    if left<=0:
                        self.left_margin=rect.width()//2-x_loc
                    if self.bottom_margin<=rect.height():
                        self.bottom_margin=rect.height()

                    self.layout.setContentsMargins(self.left_margin,
                            self.top_margin, self.right_margin,
                            self.bottom_margin)

                if v==self.sl.maximum() and rect.width()//2>=self.right_margin:
                    self.right_margin=rect.width()//2
                    self.layout.setContentsMargins(self.left_margin,
                            self.top_margin, self.right_margin,
                            self.bottom_margin)

            else:
                y_loc=QStyle.sliderPositionFromValue(self.sl.minimum(),
                        self.sl.maximum(), v, available, upsideDown=True)

                bottom=y_loc+length//2+rect.height()//2+self.top_margin-3
                # there is a 3 px offset that I can't attribute to any metric

                left=self.left_margin-rect.width()
                if left<=0:
                    self.left_margin=rect.width()+2
                    self.layout.setContentsMargins(self.left_margin,
                            self.top_margin, self.right_margin,
                            self.bottom_margin)

            pos=QPoint(left, bottom)
            painter.drawText(pos, v_str)

        return


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    frame=QtWidgets.QWidget()
    ha=QtWidgets.QHBoxLayout()
    frame.setLayout(ha)

    w = LabeledSlider(1999, 2006 , 1, orientation=Qt.Vertical,
            labels=['Y%d' %ii for ii in range(1999,2007)])

    ha.addWidget(w)
    frame.show()
    sys.exit(app.exec_())

和截图:

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM