将 QSlider 与上面包含 QPixmap 的 QLabel 对齐
Align QSlider with an above QLabel that contains a QPixmap
我正在尝试对齐 QGridBoxLayout 中的 QSlider 和 QLabel
供参考,这是用于查看视频中的帧,这些帧显示在其他地方。这里的QLabel是用来显示视频的标记部分,绿色部分是"labelled",黑色部分是"not labelled"
我的QSLider初始化为:
self.slider = QSlider(Qt.Horizontal, self)
self.slider.setSingleStep(1)
self.slider.setFocusPolicy(Qt.NoFocus)
self.slider.valueChanged.connect(self.sliderChanged)
self.layout.addWidget(self.slider)
QLabel 包含一个 QPixmap,它有一个从形状为 (100,1000,3) 的 numpy 数组创建的 QImage。这是它的初始化方式:
image = np.zeros((100,1000,3), dtype=np.uint8) #Initialize a black picture
for combo in indices_list:
start, end = combo
start = int(start / self.length * 1000)
end = int(end / self.length * 1000)
image[:,start:end] = [0,255,0] #Label the columns as green
height, width, bytevalue = image.shape
qimage = QImage(image, width, height, bytevalue * width, QImage.Format_RGB888)
pixmap = QPixmap(qimage)
self.label.setPixmap(pixmap)
上面的代码所做的是获取开始和结束索引的列表,然后将该范围内的列更改为绿色。
我遇到的问题是,即使 QSlider 和 QLabel 在 QVBoxLayout 中堆叠在一起,滑块位置并不总是与相应的像素匹配。我相信这是因为滑块 "handle" 的最左侧(我不确定正确的名称)停在滑块的最左侧。它们直接在中心匹配,然后随着你远离中心,匹配越来越少。
我希望手柄的中心位于 QLabel 中当前滑块值对应列的正下方。
我试过将滑块的边距设置为 0,但是没有用。
感谢您的帮助。
编辑:
图片可能会有帮助:
这是整个酒吧的照片:
这是一张没有左对齐的图片:
这是一张没有右对齐的图片:
最后,这是居中对齐的:
要获得水平位置,您必须使用 QStyle::subControlRect()
:
from PyQt5 import QtCore, QtGui, QtWidgets
class Label(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Label, self).__init__(parent)
self._slider = None
self._values = []
def setSlider(self, slider):
self._slider = slider
self.update()
def set_values(self, values):
self._values = values
self.update()
def paintEvent(self, event):
if self._slider is None: return
painter = QtGui.QPainter(self)
X1 = self.get_pos_by_value(self._slider.minimum())
X2 = self.get_pos_by_value(self._slider.maximum())
R = QtCore.QRect(QtCore.QPoint(X1, 0), QtCore.QPoint(X2, self.height()))
painter.fillRect(R, QtGui.QColor("#000000"))
for start, end in self._values:
x1 = self.get_pos_by_value(start)
x2 = self.get_pos_by_value(end)
r = QtCore.QRect(QtCore.QPoint(x1, 0), QtCore.QPoint(x2, self.height()))
painter.fillRect(r, QtGui.QColor("#00ff00"))
def get_pos_by_value(self, value):
opt = QtWidgets.QStyleOptionSlider()
self._slider.initStyleOption(opt)
opt.sliderPosition = value
r = self._slider.style().subControlRect(
QtWidgets.QStyle.CC_Slider,
opt,
QtWidgets.QStyle.SC_SliderHandle,
self._slider
)
return r.center().x()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
length = 1000
indices_list = [(100, 200), (400, 500), (700, 900)]
self.label = Label()
self.slider = QtWidgets.QSlider(
orientation=QtCore.Qt.Horizontal,
minimum = 0,
maximum=length,
singleStep=1,
pageStep=1
)
self.label.setSlider(self.slider)
self.label.set_values(indices_list)
label_value = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
self.slider.valueChanged.connect(label_value.setNum)
label_value.setNum(self.slider.value())
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.label, 1)
lay.addWidget(self.slider)
lay.addWidget(label_value)
self.resize(600, 300)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
w = Widget()
w.show()
sys.exit(app.exec_())
我正在尝试对齐 QGridBoxLayout 中的 QSlider 和 QLabel
供参考,这是用于查看视频中的帧,这些帧显示在其他地方。这里的QLabel是用来显示视频的标记部分,绿色部分是"labelled",黑色部分是"not labelled"
我的QSLider初始化为:
self.slider = QSlider(Qt.Horizontal, self)
self.slider.setSingleStep(1)
self.slider.setFocusPolicy(Qt.NoFocus)
self.slider.valueChanged.connect(self.sliderChanged)
self.layout.addWidget(self.slider)
QLabel 包含一个 QPixmap,它有一个从形状为 (100,1000,3) 的 numpy 数组创建的 QImage。这是它的初始化方式:
image = np.zeros((100,1000,3), dtype=np.uint8) #Initialize a black picture
for combo in indices_list:
start, end = combo
start = int(start / self.length * 1000)
end = int(end / self.length * 1000)
image[:,start:end] = [0,255,0] #Label the columns as green
height, width, bytevalue = image.shape
qimage = QImage(image, width, height, bytevalue * width, QImage.Format_RGB888)
pixmap = QPixmap(qimage)
self.label.setPixmap(pixmap)
上面的代码所做的是获取开始和结束索引的列表,然后将该范围内的列更改为绿色。
我遇到的问题是,即使 QSlider 和 QLabel 在 QVBoxLayout 中堆叠在一起,滑块位置并不总是与相应的像素匹配。我相信这是因为滑块 "handle" 的最左侧(我不确定正确的名称)停在滑块的最左侧。它们直接在中心匹配,然后随着你远离中心,匹配越来越少。
我希望手柄的中心位于 QLabel 中当前滑块值对应列的正下方。
我试过将滑块的边距设置为 0,但是没有用。
感谢您的帮助。
编辑:
图片可能会有帮助:
这是整个酒吧的照片:
这是一张没有左对齐的图片:
这是一张没有右对齐的图片:
最后,这是居中对齐的:
要获得水平位置,您必须使用 QStyle::subControlRect()
:
from PyQt5 import QtCore, QtGui, QtWidgets
class Label(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Label, self).__init__(parent)
self._slider = None
self._values = []
def setSlider(self, slider):
self._slider = slider
self.update()
def set_values(self, values):
self._values = values
self.update()
def paintEvent(self, event):
if self._slider is None: return
painter = QtGui.QPainter(self)
X1 = self.get_pos_by_value(self._slider.minimum())
X2 = self.get_pos_by_value(self._slider.maximum())
R = QtCore.QRect(QtCore.QPoint(X1, 0), QtCore.QPoint(X2, self.height()))
painter.fillRect(R, QtGui.QColor("#000000"))
for start, end in self._values:
x1 = self.get_pos_by_value(start)
x2 = self.get_pos_by_value(end)
r = QtCore.QRect(QtCore.QPoint(x1, 0), QtCore.QPoint(x2, self.height()))
painter.fillRect(r, QtGui.QColor("#00ff00"))
def get_pos_by_value(self, value):
opt = QtWidgets.QStyleOptionSlider()
self._slider.initStyleOption(opt)
opt.sliderPosition = value
r = self._slider.style().subControlRect(
QtWidgets.QStyle.CC_Slider,
opt,
QtWidgets.QStyle.SC_SliderHandle,
self._slider
)
return r.center().x()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
length = 1000
indices_list = [(100, 200), (400, 500), (700, 900)]
self.label = Label()
self.slider = QtWidgets.QSlider(
orientation=QtCore.Qt.Horizontal,
minimum = 0,
maximum=length,
singleStep=1,
pageStep=1
)
self.label.setSlider(self.slider)
self.label.set_values(indices_list)
label_value = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
self.slider.valueChanged.connect(label_value.setNum)
label_value.setNum(self.slider.value())
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.label, 1)
lay.addWidget(self.slider)
lay.addWidget(label_value)
self.resize(600, 300)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
w = Widget()
w.show()
sys.exit(app.exec_())