使用QListWidg的PyQt自定义滚动

2024-07-03 06:55:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在设法定制QListWidget的滚动条,使其在QListWidget的上方和下方,而不是普通的垂直和水平滚动条。在

如果你不明白我的意思,请看下面我的例子。
在下面的例子中,我使用QPushButtonsQTimers来控制滚动条来代替滚动条,但是我要找的是像启用菜单滚动时QMenu中的滚动条一样的滚动条。在

如果这不是一个选项,我想知道是否有一个滚动条信号或什么东西,我可以尝试使用,以了解滚动条正常激活的时间?这样我就可以根据需要显示/隐藏按钮。谢谢。在

import sys
from PyQt5.QtCore import pyqtSignal, QTimer, Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, \
    QApplication, QStyle, QListWidget, QStyleOptionButton, QListWidgetItem

class UpBtn(QPushButton):
    mouseHover = pyqtSignal()
    def __init__(self):
        QPushButton.__init__(self)
        self.setMouseTracking(True)
        self.timer = QTimer()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        opt = QStyleOptionButton()
        self.initStyleOption(opt)
        self.style().drawControl(QStyle.CE_ScrollBarSubLine, opt, painter, self)
        painter.end()

    def startScroll(self):
        self.mouseHover.emit()

    def enterEvent(self, event):
        self.timer.timeout.connect(self.startScroll)
        self.timer.start(120)

    def leaveEvent(self, event):
        self.timer.stop()

class DwnBtn(QPushButton):
    mouseHover = pyqtSignal()
    def __init__(self):
        QPushButton.__init__(self)
        self.setMouseTracking(True)
        self.timer = QTimer()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        opt = QStyleOptionButton()
        self.initStyleOption(opt)
        self.style().drawControl(QStyle.CE_ScrollBarAddLine, opt, painter, self)
        painter.end()

    def startScroll(self):
        self.mouseHover.emit()

    def enterEvent(self, event):
        self.timer.timeout.connect(self.startScroll)
        self.timer.start(120)

    def leaveEvent(self, event):
        self.timer.stop()

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.upBtn = UpBtn()
        self.upBtn.setFixedWidth(230)
        self.layout.addWidget(self.upBtn)

        self.listWidget = QListWidget()
        self.listWidget.setFixedWidth(230)
        self.listWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.listWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.layout.addWidget(self.listWidget)

        self.downBtn = DwnBtn()
        self.downBtn.setFixedWidth(230)
        self.layout.addWidget(self.downBtn)

        self.setLayout(self.layout)
        self.upBtn.clicked.connect(self.upBtnClicked)
        self.upBtn.mouseHover.connect(self.upBtnClicked)
        self.downBtn.clicked.connect(self.downBtnClicked)
        self.downBtn.mouseHover.connect(self.downBtnClicked)

        for i in range(100):
            item = QListWidgetItem()
            item.setText("list item " + str(i))
            self.listWidget.addItem(item)

    def upBtnClicked(self):
        cur = self.listWidget.currentRow()
        self.listWidget.setCurrentRow(cur - 1)

    def downBtnClicked(self):
        cur = self.listWidget.currentRow()
        self.listWidget.setCurrentRow(cur + 1)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

编辑: 这是我所说的示例图像。这是一个可滚动的QMenu。在

enter image description here

编辑:
可滚动QMenu代码。
取消注释已注释的部分以获得与图像中相同的固定大小。通常Q菜单滚动仅在菜单项超过屏幕高度时有效。我只是寻找顶部和底部悬停风格的滚动,但要在QListWidget中使用。在

^{pr2}$

Tags: selfeventinitdefconnectoptlayouttimer
1条回答
网友
1楼 · 发布于 2024-07-03 06:55:26

这样做的目的是获得决定按钮是否隐藏的上下元素行,因为我们使用itemAt()方法返回给定几何坐标的项。另一方面,我改进了这种计算方法,每次它们改变QListView中的项数时,我们使用内部模型的信号。在

import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class Button(QtWidgets.QPushButton):
    moveSignal = QtCore.pyqtSignal()
    def __init__(self, *args, **kwargs):
        super(Button, self).__init__(*args, **kwargs)
        self.m_timer = QtCore.QTimer(self, interval=120)
        self.m_timer.timeout.connect(self.moveSignal)
        self.setMouseTracking(True)
        self.setFixedHeight(20)

    def mouseReleaseEvent(self, e):
        super(Button, self).mousePressEvent(e)
        self.setDown(True)

    def enterEvent(self, e):
        self.setDown(True)
        self.m_timer.start()
        super(Button, self).enterEvent(e)

    def leaveEvent(self, e):
        self.setDown(False)
        self.m_timer.stop()
        super(Button, self).leaveEvent(e)


class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setFixedWidth(230)

        icon = self.style().standardIcon(QtWidgets.QStyle.SP_ArrowUp)
        self.upBtn = Button(icon=icon)
        self.upBtn.moveSignal.connect(self.moveUp)
        icon = self.style().standardIcon(QtWidgets.QStyle.SP_ArrowDown)
        self.downBtn = Button(icon=icon)
        self.downBtn.moveSignal.connect(self.moveDown)

        self.listWidget = QtWidgets.QListWidget()
        self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.listWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self.upBtn)
        layout.addWidget(self.listWidget)
        layout.addWidget(self.downBtn)
        self.adjust_buttons()
        self.create_connections()

    def create_connections(self):
        self.listWidget.currentItemChanged.connect(self.adjust_buttons)
        model = self.listWidget.model()
        model.rowsInserted.connect(self.adjust_buttons)
        model.rowsRemoved.connect(self.adjust_buttons)
        model.rowsMoved.connect(self.adjust_buttons)
        model.modelReset.connect(self.adjust_buttons)
        model.layoutChanged.connect(self.adjust_buttons)

    @QtCore.pyqtSlot()
    def adjust_buttons(self):
        first = self.listWidget.itemAt(QtCore.QPoint())
        r = self.listWidget.row(first)
        self.upBtn.setVisible(r != 0 and  r!= -1)
        last = self.listWidget.itemAt(self.listWidget.viewport().rect().bottomRight())
        r = self.listWidget.row(last)
        self.downBtn.setVisible( r != (self.listWidget.count() -1) and r != -1)

    @QtCore.pyqtSlot()
    def moveUp(self):
        ix = self.listWidget.moveCursor(QtWidgets.QAbstractItemView.MoveUp, QtCore.Qt.NoModifier)
        self.listWidget.setCurrentIndex(ix)

    @QtCore.pyqtSlot()
    def moveDown(self):
        ix = self.listWidget.moveCursor(QtWidgets.QAbstractItemView.MoveDown, QtCore.Qt.NoModifier)
        self.listWidget.setCurrentIndex(ix)

    @QtCore.pyqtSlot(str)
    def add_item(self, text):
        item = QtWidgets.QListWidgetItem(text)
        self.listWidget.addItem(item)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    for i in range(100):
        window.add_item("item {}".format(i))
    window.show()
    sys.exit(app.exec_())

相关问题 更多 >