python - 如何在没有可见空白的情况下扩展/缩小 QTable View

标签 python pyqt pyqt5 qtableview qlayout

我有一个子类QAbstractTableModel
在不滚动的情况下以全尺寸显示 TableView 中的数据我已经关闭了滚动条
为了摆脱表格 View 周围的空白,我将垂直/水平表格长度设置为特定值。

enter image description here
问题是 我在模型中添加了一个添加/删除行方法,因此 TableView 现在可以扩展/缩小
调整表格 View 行为以全尺寸显示数据并且没有空白我已将水平标题设置为 table_view.horizo​​ntalHeader().setStretchLastSection(True)
正确切断水平方向的空白
对空白的垂直标题切割也进行相同的操作,但会过度拉伸(stretch)最后一行

overstretching

我尝试将每一行设置为默认大小

table_view.verticalHeader().setSectionResizeMode(qtw.QHeaderView.Fixed)
        table_view.verticalHeader().setDefaultSectionSize(40)

但这会再次打开空白区域

简而言之:我正在寻找一种方法来在 TableView 中以全尺寸显示模型数据而没有空白,同时能够删除/插入行


代码示例

#!/usr/bin/env python

"""

"""

import sys
import re


from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5.QtCore import Qt

from PyQt5 import QtGui as qtg


class ViewModel(qtc.QAbstractTableModel):

    def __init__(self, input_data=None):
        super().__init__()

        self.input_data = input_data or [["data","data","data","data"],["data","data","data","data"]]

    #

    def data(self, index, role):  # parameter index, role are needed !
        """

        """
        if role == qtc.Qt.DisplayRole:
            try:
                text = self.input_data[index.row()][index.column()]
            except IndexError:
                text = None

            return text

    def rowCount(self, index=qtc.QModelIndex()):
        return 0 if index.isValid() else len(self.input_data)


    def columnCount(self, index):
        return len(self.input_data[0])


    def insertRows(self, position, rows, parent=qtc.QModelIndex()):

        print(position) # -1
        position = (position + self.rowCount()) if position < 0 else position
        start = position

        end = position + rows - 1

        if end <= 8:
            self.beginInsertRows(parent, start, end)
            self.input_data.append([])
            self.endInsertRows()
            return True
        else:
            return False


    def removeRows(self, position, rows, parent=qtc.QModelIndex()):
        position = (position + self.rowCount()) if position < 0 else position

        start = position

        end = position + rows - 1

        if end >= 1:
            self.beginRemoveRows(parent, start, end)
            del self.input_data[start:end + 1]
            self.endRemoveRows()
            return True
        else:
            return False



    def headerData(self, section, orientation, role):

        if role == qtc.Qt.DisplayRole:

            if orientation == qtc.Qt.Horizontal:
                return "hight " + str(section+1) + " /mm"
            if orientation == qtc.Qt.Vertical:
                return "width " + str(section+1)


    def flags(self, index):
        return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    def setData(self, index, value, role=qtc.Qt.EditRole):
        if role == qtc.Qt.EditRole:
            try:
                row = index.row()
                column = index.column()

                pattern = '^[\d]+(?:,[\d]+)?$'


                if re.fullmatch(pattern, value, flags=0):
                    print("true")
                    self.input_data[row][column] = value  # float

                else:
                    print("nope")
                    pass

                return True

            except ValueError:
                print("not a number")
                return False


    def display_model_data(self):
        print(self.input_data)


class MainWindow(qtw.QWidget):
    def __init__(self):
        super().__init__()

        # geometry
        self.setGeometry(900, 360, 700, 800)


        # View
        table_view = qtw.QTableView()



        # done # turn scroll bars off
        table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        table_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)





        self.model = ViewModel()
        table_view.setModel(self.model)




        table_view.horizontalHeader().setStretchLastSection(True)
        # table_view.verticalHeader().setStretchLastSection(True)

        table_view.verticalHeader().setSectionResizeMode(qtw.QHeaderView.Fixed)
        table_view.verticalHeader().setDefaultSectionSize(24)

        table_view.verticalHeader().setStretchLastSection(True)
        #     verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
        # verticalHeader->setDefaultSectionSize(24);



        # widgets
        self.insert_row_button = qtw.QPushButton("insert row")
        self.deleate_row_button = qtw.QPushButton("deleate row")

        # layout
        layout = qtw.QVBoxLayout()
        layout.addWidget(table_view)
        layout.addWidget(self.insert_row_button)
        layout.addWidget(self.deleate_row_button)


        self.setLayout(layout)
        self.show()

        # function
        self.insert_row_button.clicked.connect(lambda: self.model.insertRows(-1, 1))
        self.deleate_row_button.clicked.connect(lambda: self.model.removeRows(-1, 1))


if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

最佳答案

空间不会神奇地消失。假设表格的总高度是 600。如果表格中有两行,第一行是 40。那么,第二行是 600 - 40 = 560 如果你不想在表格底部留空.如果将每行的高度设置为 40,则空白区域的高度将为 600 - 2 * 40 = 520。你不能要求(总高度 600)+(两行,每行 40)+(无空白底部的空间)。

所以,让我猜猜,你想要 (a. 底部没有空格) + (b, 空格被均匀地分成行,这样最后一行就不会看起来很奇怪。)。如果是这样的话,我已将您的代码编辑到下面,解释了所有内容:

"""

"""

import sys
import re


from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5.QtCore import Qt

from PyQt5 import QtGui as qtg


class ViewModel(qtc.QAbstractTableModel):

    def __init__(self, input_data=None):
        super().__init__()

        self.input_data = input_data or [["data","data","data","data"],["data","data","data","data"]]

    #

    def data(self, index, role):  # parameter index, role are needed !
        """

        """
        if role == qtc.Qt.DisplayRole:
            try:
                text = self.input_data[index.row()][index.column()]
            except IndexError:
                text = None

            return text

    def rowCount(self, index=qtc.QModelIndex()):
        return 0 if index.isValid() else len(self.input_data)


    def columnCount(self, index):
        return len(self.input_data[0])


    def insertRows(self, position, rows, parent=qtc.QModelIndex()):

        print(position) # -1
        position = (position + self.rowCount()) if position < 0 else position
        start = position

        end = position + rows - 1

        if end <= 8:
            self.beginInsertRows(parent, start, end)
            self.input_data.append([])
            self.endInsertRows()
            return True
        else:
            return False


    def removeRows(self, position, rows, parent=qtc.QModelIndex()):
        position = (position + self.rowCount()) if position < 0 else position

        start = position

        end = position + rows - 1

        if end >= 1:
            self.beginRemoveRows(parent, start, end)
            del self.input_data[start:end + 1]
            self.endRemoveRows()
            return True
        else:
            return False



    def headerData(self, section, orientation, role):

        if role == qtc.Qt.DisplayRole:

            if orientation == qtc.Qt.Horizontal:
                return "hight " + str(section+1) + " /mm"
            if orientation == qtc.Qt.Vertical:
                return "width " + str(section+1)


    def flags(self, index):
        return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    def setData(self, index, value, role=qtc.Qt.EditRole):
        if role == qtc.Qt.EditRole:
            try:
                row = index.row()
                column = index.column()

                pattern = '^[\d]+(?:,[\d]+)?$'


                if re.fullmatch(pattern, value, flags=0):
                    print("true")
                    self.input_data[row][column] = value  # float

                else:
                    print("nope")
                    pass

                return True

            except ValueError:
                print("not a number")
                return False


    def display_model_data(self):
        print(self.input_data)


class NoBlankSpaceAtBottomEnvenlySplitTableView(qtw.QTableView):
    def sizeHintForRow(self, row):
        row_count = self.model().rowCount()
        height = self.viewport().height()
        row_height = int(height/row_count)
        if row < row_count - 1:
            return row_height
        else:
            return super().sizeHintForRow(row)


class MainWindow(qtw.QWidget):
    def __init__(self):
        super().__init__()

        # geometry
        self.setGeometry(900, 360, 700, 800)


        # View
        # table_view = qtw.QTableView()
        table_view = NoBlankSpaceAtBottomEnvenlySplitTableView()



        # done # turn scroll bars off
        table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        table_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)





        self.model = ViewModel()
        table_view.setModel(self.model)




        table_view.horizontalHeader().setStretchLastSection(True)
        table_view.verticalHeader().setStretchLastSection(True)

        # table_view.verticalHeader().setSectionResizeMode(qtw.QHeaderView.Fixed)
        #table_view.verticalHeader().setDefaultSectionSize(24)
        table_view.verticalHeader().setSectionResizeMode(
            qtw.QHeaderView.ResizeToContents)  # Add this line

        table_view.verticalHeader().setStretchLastSection(True)
        #     verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
        # verticalHeader->setDefaultSectionSize(24);



        # widgets
        self.insert_row_button = qtw.QPushButton("insert row")
        self.deleate_row_button = qtw.QPushButton("deleate row")

        # layout
        layout = qtw.QVBoxLayout()
        layout.addWidget(table_view)
        layout.addWidget(self.insert_row_button)
        layout.addWidget(self.deleate_row_button)


        self.setLayout(layout)
        self.show()

        # function
        self.insert_row_button.clicked.connect(lambda: self.model.insertRows(-1, 1))
        self.deleate_row_button.clicked.connect(lambda: self.model.removeRows(-1, 1))


if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

编辑:表格根据行自动调整高度

import sys
import re


from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QSizePolicy

from PyQt5 import QtGui as qtg


class ViewModel(qtc.QAbstractTableModel):

    def __init__(self, input_data=None):
        super().__init__()

        self.input_data = input_data or [["data","data","data","data"],["data","data","data","data"]]

    #

    def data(self, index, role):  # parameter index, role are needed !
        """

        """
        if role == qtc.Qt.DisplayRole:
            try:
                text = self.input_data[index.row()][index.column()]
            except IndexError:
                text = None

            return text

    def rowCount(self, index=qtc.QModelIndex()):
        return 0 if index.isValid() else len(self.input_data)


    def columnCount(self, index):
        return len(self.input_data[0])


    def insertRows(self, position, rows, parent=qtc.QModelIndex()):

        print(position) # -1
        position = (position + self.rowCount()) if position < 0 else position
        start = position

        end = position + rows - 1

        if end <= 8:
            self.beginInsertRows(parent, start, end)
            self.input_data.append([])
            self.endInsertRows()
            return True
        else:
            return False


    def removeRows(self, position, rows, parent=qtc.QModelIndex()):
        position = (position + self.rowCount()) if position < 0 else position

        start = position

        end = position + rows - 1

        if end >= 1:
            self.beginRemoveRows(parent, start, end)
            del self.input_data[start:end + 1]
            self.endRemoveRows()
            return True
        else:
            return False



    def headerData(self, section, orientation, role):

        if role == qtc.Qt.DisplayRole:

            if orientation == qtc.Qt.Horizontal:
                return "hight " + str(section+1) + " /mm"
            if orientation == qtc.Qt.Vertical:
                return "width " + str(section+1)


    def flags(self, index):
        return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    def setData(self, index, value, role=qtc.Qt.EditRole):
        if role == qtc.Qt.EditRole:
            try:
                row = index.row()
                column = index.column()

                pattern = '^[\d]+(?:,[\d]+)?$'


                if re.fullmatch(pattern, value, flags=0):
                    print("true")
                    self.input_data[row][column] = value  # float

                else:
                    print("nope")
                    pass

                return True

            except ValueError:
                print("not a number")
                return False


    def display_model_data(self):
        print(self.input_data)


class AutoExpandingTableView(qtw.QTableView):
    # def sizeHintForRow(self, row):
    #     row_count = self.model().rowCount()
    #     height = self.viewport().height()
    #     row_height = int(height/row_count)
    #     if row < row_count - 1:
    #         return row_height
    #     else:
    #         return super().sizeHintForRow(row)

    def sizeHint(self):
        viewport_size_hint = self.viewportSizeHint()
        return QSize(
            self.width(),
            viewport_size_hint.height()
        )


class MainWindow(qtw.QWidget):
    def __init__(self):
        super().__init__()

        # geometry
        self.setGeometry(900, 360, 700, 800)


        # View
        # table_view = qtw.QTableView()
        table_view = AutoExpandingTableView()
        table_view.setSizePolicy(
            QSizePolicy.Expanding,
            QSizePolicy.Preferred
        )

        # done # turn scroll bars off
        table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        table_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.model = ViewModel()
        table_view.setModel(self.model)
        table_view.model().rowsInserted.connect(table_view.adjustSize)
        table_view.model().rowsRemoved.connect(table_view.adjustSize)

        table_view.horizontalHeader().setStretchLastSection(True)
        # table_view.verticalHeader().setStretchLastSection(True)

        # table_view.verticalHeader().setSectionResizeMode(qtw.QHeaderView.Fixed)
        #table_view.verticalHeader().setDefaultSectionSize(24)
        table_view.verticalHeader().setSectionResizeMode(
            qtw.QHeaderView.ResizeToContents)  # Add this line

        # widgets
        self.insert_row_button = qtw.QPushButton("insert row")
        self.deleate_row_button = qtw.QPushButton("deleate row")

        # layout
        layout = qtw.QVBoxLayout()
        layout.addWidget(table_view)
        layout.addStretch()
        layout.addWidget(self.insert_row_button)
        layout.addWidget(self.deleate_row_button)


        self.setLayout(layout)
        self.show()

        # function
        self.insert_row_button.clicked.connect(lambda: self.model.insertRows(-1, 1))
        self.deleate_row_button.clicked.connect(lambda: self.model.removeRows(-1, 1))


if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

关于python - 如何在没有可见空白的情况下扩展/缩小 QTable View,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62327585/

相关文章:

python - 如何从 .csv 文件加载数据而不导入 .csv 模块/库

python - python 中最好的有序 dict 实现是什么?

python - 将 stdout 和 stderr 从辅助线程重定向到 PyQt4 QTextEdit

python:使用 PyCharm 和 PyQt5 时,进程已完成,退出代码为 1

python - Pandas Groupby 日名称

python - SVM 在我的数据中提供了错误的结果。怎么修?

java - 创建一个简单的表单应用程序来编辑文本文件

python - 在 QListFiew 中过滤/搜索 QFileSystemModel(可能是 QSortFilterProxyModel)

python - 在运行时验证 MathText 字符串

python - QLineEdit PyQT5 输入上的火柴盒键盘