Instead of using a QLabel I recommend using QGraphicsRectItem with a QGraphicsView since it is specialized in this type of tasks:
from PyQt5 import QtCore, QtGui, QtWidgets class Widget(QtWidgets.QGraphicsView): def __init__(self, parent=None): super(Widget, self).__init__(parent) self.setScene(QtWidgets.QGraphicsScene(self)) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window) self.setBackgroundBrush(brush) rect_item = self.scene().addRect( QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(40, 80)) ) rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) rect_item.setBrush(QtGui.QBrush(QtGui.QColor("red"))) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.setFixedSize(640, 480) w.show() sys.exit(app.exec_())
If you want to just scroll horizontally then overwrite the itemChange method of QGraphicsItem:
from PyQt5 import QtCore, QtGui, QtWidgets class HorizontalItem(QtWidgets.QGraphicsRectItem): def __init__(self, rect, parent=None): super(HorizontalItem, self).__init__(rect, parent) self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True) def itemChange(self, change, value): if ( change == QtWidgets.QGraphicsItem.ItemPositionChange and self.scene() ): return QtCore.QPointF(value.x(), self.pos().y()) return super(HorizontalItem, self).itemChange(change, value) class Widget(QtWidgets.QGraphicsView): def __init__(self, parent=None): super(Widget, self).__init__(parent) self.setScene(QtWidgets.QGraphicsScene(self)) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window) self.setBackgroundBrush(brush) rect_item = HorizontalItem( QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(40, 80)) ) rect_item.setBrush(QtGui.QBrush(QtGui.QColor("red"))) self.scene().addItem(rect_item) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.setFixedSize(640, 480) w.show() sys.exit(app.exec_())
In the following code there is an example similar to what you want:
from PyQt5 import QtCore, QtGui, QtWidgets class HorizontalItem(QtWidgets.QGraphicsRectItem): def __init__(self, rect, parent=None): super(HorizontalItem, self).__init__(rect, parent) self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True) def itemChange(self, change, value): if ( change == QtWidgets.QGraphicsItem.ItemPositionChange and self.scene() ): return QtCore.QPointF(value.x(), self.pos().y()) return super(HorizontalItem, self).itemChange(change, value) class Widget(QtWidgets.QGraphicsView): def __init__(self, parent=None): super(Widget, self).__init__(parent) self.setScene(QtWidgets.QGraphicsScene(self)) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window) self.setBackgroundBrush(brush) self.setFixedSize(640, 480) size = self.mapToScene(self.viewport().rect()).boundingRect().size() r = QtCore.QRectF(QtCore.QPointF(), size) self.setSceneRect(r) rect = QtCore.QRectF( QtCore.QPointF(), QtCore.QSizeF(0.8 * r.width(), 80) ) rect.moveCenter(r.center()) rect_item = self.scene().addRect(rect) rect_item.setBrush(QtGui.QBrush(QtGui.QColor("salmon"))) item = HorizontalItem( QtCore.QRectF( rect.bottomLeft() + QtCore.QPointF(0, 20), QtCore.QSizeF(20, 40) ) ) item.setBrush(QtGui.QBrush(QtGui.QColor("red"))) self.scene().addItem(item) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())