python - 如何在没有可见空白的情况下扩展/减少 QTable 视图
问题描述
我有一个子类QAbstractTableModel
,可以在不滚动的情况下以全尺寸显示表格视图中的数据我已经关闭滚动条
以消除表格视图周围的空白我已将垂直/水平表格长度设置为特定值。
问题是我已经向模型添加了一个添加/删除行方法,因此表视图现在扩展/缩小
以调整表视图行为以显示完整大小的数据并且没有空白我已经设置了水平标题,
table_view.horizontalHeader().setStretchLastSection(True)
它会被截断水平方向上的空白区域正确地
对空白区域的垂直标题切割进行相同的操作,但会过度拉伸最后一行
我尝试将每一行设置为默认大小
table_view.verticalHeader().setSectionResizeMode(qtw.QHeaderView.Fixed)
table_view.verticalHeader().setDefaultSectionSize(40)
但这会再次打开空白
简而言之:我正在寻找一种方法来在表格视图中以全尺寸显示模型数据而没有空白,同时能够删除/插入一行
代码示例
#!/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_())
推荐阅读
- java - 从 Soap Envelope 获取 X509 证书别名
- spring - Spring Kafka 2.6.x ErrorHandler 和 DeadLetterPublishingRecoverer 与 ConcurrentKafkaListenerContainerFactory
- mongodb - 如何使用 Talend Open Studio 处理数百万条 MongoDB 记录并将其插入 Postgres
- c# - 我怎样才能使 .net5 C#9 默认目标框架 VS2019
- html - 为什么我的下拉菜单显示在顶部?
- javascript - 将具有嵌套数组的对象转换为 FormData
- node.js - 您如何对 Dynamodb 触发器“问题:函数调用失败”或 Lambda“配置中缺少凭据”进行故障排除?
- python - Python 使用 Lucas-Lehmer 序列查找梅森素数并存储它们
- rust - 如何将任意就地操作应用于 &mut 引用?
- flutter - 在警报对话框窗口中分隔两个组件