【问题标题】:Create a DB Browser style QHeaderview in PyQt5在 PyQt5 中创建一个 DB Browser 样式的 QHeaderview
【发布时间】:2020-06-02 10:45:52
【问题描述】:

我想在 PyQt5 中创建一个 QHeaderView,就像在这个项目中使用的一样(SQLite 的 DB 浏览器)。问题是我不懂 C++,也不明白类和小部件是如何从 GitHub 上的源代码创建的。有人如何在 python 中模拟这个过滤器头吗?

https://github.com/sqlitebrowser/sqlitebrowser/blob/master/src/FilterTableHeader.h

【问题讨论】:

    标签: python pyqt pyqt5 qheaderview


    【解决方案1】:

    这是该方法的一个非常基本的实现。

    这个概念是为标题提供正确的sizeHint(标题的默认提示加上行编辑的高度)并使用setViewportMargins确保标题具有文本字段使用的底部边距.

    class Header(QtWidgets.QHeaderView):
        filterChanged = QtCore.pyqtSignal(int, str)
        fieldsVisible = True
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.fields = []
            self.sectionCountChanged.connect(self.generateFields)
            self.sectionResized.connect(self.updateFields)
            self.parent().horizontalScrollBar().valueChanged.connect(self.updateFields)
            self.parent().verticalScrollBar().valueChanged.connect(self.updateFields)
    
        def setFieldsVisible(self, visible):
            if visible == self.fieldsVisible:
                return
            self.fieldsVisible = visible
            self.generateFields()
    
        def generateFields(self):
            while self.fields:
                self.fields.pop().deleteLater()
            if self.fieldsVisible:
                for s in range(self.count()):
                    edit = QtWidgets.QLineEdit(self)
                    edit.show()
                    self.fields.append(edit)
                    edit.textChanged.connect(lambda text, s=s: self.filterChanged.emit(s, text))
                self.updateFields()
            self.updateGeometries()
    
        def updateFields(self):
            offset = self.offset()
            y = QtWidgets.QHeaderView.sizeHint(self).height()
            for section, field in enumerate(self.fields):
                field.move(self.sectionPosition(section) - offset, y)
                field.resize(self.sectionSize(section), field.sizeHint().height())
    
        def updateGeometries(self):
            if self.fields:
                self.setViewportMargins(0, 0, 0, self.fields[0].sizeHint().height())
            else:
                self.setViewportMargins(0, 0, 0, 0)
            super().updateGeometries()
            # ensure that the parent view updates correctly
            self.parent().updateGeometries()
            self.updateFields()
    
        def sizeHint(self):
            hint = super().sizeHint()
            if self.fields:
                hint.setHeight(hint.height() + self.fields[0].sizeHint().height())
            return hint
    
    
    class SearchTable(QtWidgets.QTableView):
        def __init__(self):
            super().__init__()
            model = QtGui.QStandardItemModel()
            for row in range(8):
                model.appendRow([QtGui.QStandardItem('Item {} {}'.format(row, i)) for i in range(8)])
            self.setModel(model)
            self.setHorizontalHeader(Header(QtCore.Qt.Horizontal, self))
    

    请注意,此示例未考虑移动部分的可能性,如果您想实现多列过滤器,则需要 QSortFilterProxyModel 的子类(例如,提供的here)。我提供了一个基本信号 (filterChanged),它将返回该部分并更改文本。

    【讨论】:

    • 谢谢!我会尽快尝试的。过滤器不是问题,因为它们当前正在使用 QSqlmodel 工作。问题是我无法将过滤器的宽度调整为列的宽度。当我认为我拥有它时,我遇到了一个新问题。
    • 我有一个疑问,您也许可以解决,您知道为什么有时当我在行中写一些东西时,列名会从过滤器中消失吗?而且,你知道如何设置列的名称吗?我之前是用 model.setHeaderData() 做的(因为我要显示的列的名称与 SQL 表上的不同)。非常感谢,除此之外一切正常!
    • 我不确定你的意思,使用 setHeaderData 不应该受到这个实现的影响。如果您对此有疑问,我建议您创建一个新问题。
    • 好的,我试试,如果不行,我会再回答一次。非常感谢您的宝贵时间,您真的帮助了我!
    猜你喜欢
    • 1970-01-01
    • 2020-09-03
    • 2014-11-26
    • 1970-01-01
    • 2012-09-10
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多