无法设置QTableView的行高
Can't set row height of QTableView
我知道这个问题已经有人问过:
如何设置QTableView的行高?
How to set row height of QTableView?
但答案:
QHeaderView *verticalHeader = myTableView->verticalHeader();
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
verticalHeader->setDefaultSectionSize(24);
仍然会生成过高的行。如果我设置任何小于 24 的数字,比如
verticalHeader->setDefaultSectionSize(10)
我得到相同的结果,行仍然太高。
有没有什么方法可以像 QListView 或 QTreeView 默认情况下那样在 QTableView 中设置更小的行高?
我不明白为什么 QTableView 中的行在默认情况下和设计上比 QListView 和 QTreeView 中的行高很多(几乎是两倍)(即使 verticalHeader->setDefaultSectionSize(24)
)。太丑了
调用 verticalHeader->setMinimumSectionSize()
设置该部分的最小行高。调用 verticalHeader->resizeSection(row, height)
设置单个行的高度。
如果有人感兴趣,我创建了一个小型的自我维持的演示程序,它使用了来自 @rob2n 的答案:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtSql import *
class RowHeightSlider(QSlider):
def __init__(self, parent=None):
#QSlider.__init__(self, parent)
super(RowHeightSlider, self).__init__(parent)
self.setOrientation(Qt.Horizontal)
self.setMinimum(4)
self.setMaximum(72)
self.setSingleStep(1)
self.setPageStep(2)
self.setTickPosition(QSlider.TicksAbove)
self.setTickInterval(1)
class Window(QWidget):
def __init__(self, parent=None):
#QWidget.__init__(self, parent)
super(Window, self).__init__(parent)
self.parentModel = QSqlQueryModel(self)
self.refreshParent()
self.parentProxyModel = QSortFilterProxyModel()
self.parentProxyModel.setSourceModel(self.parentModel)
self.parentView = QTableView()
self.parentView.setModel(self.parentProxyModel)
self.parentView.setSelectionMode(QTableView.SingleSelection)
self.parentView.setSelectionBehavior(QTableView.SelectRows)
self.parentView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.parentView.horizontalHeader().setStretchLastSection(True)
self.parentView.verticalHeader().setVisible(False)
self.parentView.setSortingEnabled(True)
self.parentView.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
self.parentView.setAlternatingRowColors(True)
self.parentView.setShowGrid(False)
#self.parentView.verticalHeader().setDefaultSectionSize(24)
self.parentView.setStyleSheet("QTableView::item:selected:!active { selection-background-color:#BABABA; }")
for i, header in enumerate(self.parentHeaders):
self.parentModel.setHeaderData(i, Qt.Horizontal, self.parentHeaders[self.parentView.horizontalHeader().visualIndex(i)])
self.parentView.resizeColumnsToContents()
self.childModel = QSqlQueryModel(self)
self.refreshChild()
self.childProxyModel = QSortFilterProxyModel()
self.childProxyModel.setSourceModel(self.childModel)
self.childView = QTableView()
self.childView.setModel(self.childProxyModel)
self.childView.setSelectionMode(QTableView.SingleSelection)
self.childView.setSelectionBehavior(QTableView.SelectRows)
self.childView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.childView.horizontalHeader().setStretchLastSection(True)
self.childView.verticalHeader().setVisible(False)
self.childView.setSortingEnabled(True)
self.childView.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
self.childView.setAlternatingRowColors(True)
self.childView.setShowGrid(False)
#self.childView.verticalHeader().setDefaultSectionSize(24)
self.childView.setStyleSheet("QTableView::item:selected:!active { selection-background-color:#BABABA; }")
for i, header in enumerate(self.childHeaders):
self.childModel.setHeaderData(i, Qt.Horizontal, self.childHeaders[self.childView.horizontalHeader().visualIndex(i)])
self.childView.resizeColumnsToContents()
self.parentSlider = RowHeightSlider()
self.childSlider = RowHeightSlider()
self.parentRowHeightLabel = QLabel('Row height: 32')
self.childRowHeightLabel = QLabel('Row height: 32')
parentLayout = QVBoxLayout()
parentLayout.addWidget(self.parentSlider)
parentLayout.addWidget(self.parentRowHeightLabel)
parentLayout.addWidget(self.parentView)
childLayout = QVBoxLayout()
childLayout.addWidget(self.childSlider)
childLayout.addWidget(self.childRowHeightLabel)
childLayout.addWidget(self.childView)
layout = QHBoxLayout()
layout.addLayout(parentLayout)
layout.addLayout(childLayout)
self.setLayout(layout)
self.parentView.selectionModel().currentRowChanged.connect(self.parentChanged)
self.parentSlider.valueChanged.connect(self.changeParentRowHeight)
self.childSlider.valueChanged.connect(self.changeChildRowHeight)
self.parentView.setCurrentIndex(self.parentView.model().index(0, 0))
self.parentView.setFocus()
self.parentSlider.setValue(36)
self.childSlider.setValue(36)
def refreshParent(self):
self.parentHeaders = ['Parent']
queryString = "SELECT parent.parent_name FROM parent"
query = QSqlQuery()
query.exec(queryString)
self.parentModel.setQuery(query)
while self.parentModel.canFetchMore():
self.parentModel.fetchMore()
def refreshChild(self, parent_name=''):
self.childHeaders = ['Child']
queryString = ("SELECT child.child_name FROM child "
"WHERE child.parent_name = '{parent_name}'").format(parent_name = parent_name)
query = QSqlQuery()
query.exec(queryString)
self.childModel.setQuery(query)
while self.childModel.canFetchMore():
self.childModel.fetchMore()
def parentChanged(self, index):
if index.isValid():
index = self.parentProxyModel.mapToSource(index)
record = self.parentModel.record(index.row())
self.refreshChild(record.value("parent.parent_name"))
#self.childView.scrollToBottom() # if needed
def changeParentRowHeight(self, rowHeight):
parentVerticalHeader = self.parentView.verticalHeader()
# (any)one of these two rows (or both) has to be uncommented
parentVerticalHeader.setMinimumSectionSize(rowHeight)
#parentVerticalHeader.setMaximumSectionSize(rowHeight)
for section in range(parentVerticalHeader.count()):
parentVerticalHeader.resizeSection(section, rowHeight)
self.displayParentRowHeightLabel(rowHeight)
def changeChildRowHeight(self, rowHeight):
childVerticalHeader = self.childView.verticalHeader()
# (any)one of these two rows (or both) has to be uncommented
childVerticalHeader.setMinimumSectionSize(rowHeight)
#childVerticalHeader.setMaximumSectionSize(rowHeight)
for section in range(childVerticalHeader.count()):
childVerticalHeader.resizeSection(section, rowHeight)
self.displayChildRowHeightLabel(rowHeight)
def displayParentRowHeightLabel(self, rowHeight):
visibleRows = self.parentView.rowAt(self.parentView.height()) - self.parentView.rowAt(0)
if self.parentView.rowAt(self.parentView.height()) == -1:
visibleRowsString = str(self.parentView.model().rowCount()) + '+'
else:
visibleRowsString = str(visibleRows)
self.parentRowHeightLabel.setText('Row height: ' + str(rowHeight) + ', Visible rows: ' + visibleRowsString)
def displayChildRowHeightLabel(self, rowHeight):
visibleRows = self.childView.rowAt(self.childView.height()) - self.childView.rowAt(0)
if self.childView.rowAt(self.childView.height()) == -1:
visibleRowsString = str(self.childView.model().rowCount()) + '+'
else:
visibleRowsString = str(visibleRows)
self.childRowHeightLabel.setText('Row height: ' + str(rowHeight) + ', Visible rows: ' + visibleRowsString)
def resizeEvent(self, event):
# make it resize-friendly
self.displayParentRowHeightLabel(self.parentSlider.value())
self.displayChildRowHeightLabel(self.childSlider.value())
def createFakeData():
parent_names = []
#import random
query = QSqlQuery()
query.exec("CREATE TABLE parent(parent_name TEXT)")
for i in range(1, 101):
parent_num = str(i).zfill(3)
parent_name = 'parent_name_' + parent_num
parent_names.append((parent_name, parent_num))
query.prepare("INSERT INTO parent (parent_name) VALUES(:parent_name)")
query.bindValue(":parent_name", parent_name)
query.exec()
query.exec("CREATE TABLE child(parent_name TEXT, child_name TEXT)")
counter = 1
for parent_name, parent_num in parent_names:
for i in range(1, 101):
child_name = 'child_name_' + parent_num + '_' + str(counter).zfill(5)
counter += 1
query.prepare("INSERT INTO child (parent_name, child_name) VALUES(:parent_name, :child_name)")
query.bindValue(":parent_name", parent_name)
query.bindValue(":child_name", child_name)
query.exec()
def createConnection():
db = QSqlDatabase.addDatabase("QSQLITE")
#db.setDatabaseName("test04.db")
db.setDatabaseName(":memory:")
db.open()
createFakeData()
app = QApplication(sys.argv)
createConnection()
window = Window()
window.resize(800, 600)
#window.show()
window.showMaximized()
app.exec()
滑块可用于在 "live" 模式下更改 QTableViews 的行高。我通过 OpenVpn 使用 PostgreSQL 对其进行了测试,在一个 QTableView 中有 10,000 行,在父视图中有 100 行,在每个父行的子视图中平均有 1,000 行,它就像一个魅力。
我知道这个问题已经有人问过:
如何设置QTableView的行高?
How to set row height of QTableView?
但答案:
QHeaderView *verticalHeader = myTableView->verticalHeader();
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
verticalHeader->setDefaultSectionSize(24);
仍然会生成过高的行。如果我设置任何小于 24 的数字,比如
verticalHeader->setDefaultSectionSize(10)
我得到相同的结果,行仍然太高。
有没有什么方法可以像 QListView 或 QTreeView 默认情况下那样在 QTableView 中设置更小的行高?
我不明白为什么 QTableView 中的行在默认情况下和设计上比 QListView 和 QTreeView 中的行高很多(几乎是两倍)(即使 verticalHeader->setDefaultSectionSize(24)
)。太丑了
调用 verticalHeader->setMinimumSectionSize()
设置该部分的最小行高。调用 verticalHeader->resizeSection(row, height)
设置单个行的高度。
如果有人感兴趣,我创建了一个小型的自我维持的演示程序,它使用了来自 @rob2n 的答案:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtSql import *
class RowHeightSlider(QSlider):
def __init__(self, parent=None):
#QSlider.__init__(self, parent)
super(RowHeightSlider, self).__init__(parent)
self.setOrientation(Qt.Horizontal)
self.setMinimum(4)
self.setMaximum(72)
self.setSingleStep(1)
self.setPageStep(2)
self.setTickPosition(QSlider.TicksAbove)
self.setTickInterval(1)
class Window(QWidget):
def __init__(self, parent=None):
#QWidget.__init__(self, parent)
super(Window, self).__init__(parent)
self.parentModel = QSqlQueryModel(self)
self.refreshParent()
self.parentProxyModel = QSortFilterProxyModel()
self.parentProxyModel.setSourceModel(self.parentModel)
self.parentView = QTableView()
self.parentView.setModel(self.parentProxyModel)
self.parentView.setSelectionMode(QTableView.SingleSelection)
self.parentView.setSelectionBehavior(QTableView.SelectRows)
self.parentView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.parentView.horizontalHeader().setStretchLastSection(True)
self.parentView.verticalHeader().setVisible(False)
self.parentView.setSortingEnabled(True)
self.parentView.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
self.parentView.setAlternatingRowColors(True)
self.parentView.setShowGrid(False)
#self.parentView.verticalHeader().setDefaultSectionSize(24)
self.parentView.setStyleSheet("QTableView::item:selected:!active { selection-background-color:#BABABA; }")
for i, header in enumerate(self.parentHeaders):
self.parentModel.setHeaderData(i, Qt.Horizontal, self.parentHeaders[self.parentView.horizontalHeader().visualIndex(i)])
self.parentView.resizeColumnsToContents()
self.childModel = QSqlQueryModel(self)
self.refreshChild()
self.childProxyModel = QSortFilterProxyModel()
self.childProxyModel.setSourceModel(self.childModel)
self.childView = QTableView()
self.childView.setModel(self.childProxyModel)
self.childView.setSelectionMode(QTableView.SingleSelection)
self.childView.setSelectionBehavior(QTableView.SelectRows)
self.childView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.childView.horizontalHeader().setStretchLastSection(True)
self.childView.verticalHeader().setVisible(False)
self.childView.setSortingEnabled(True)
self.childView.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder)
self.childView.setAlternatingRowColors(True)
self.childView.setShowGrid(False)
#self.childView.verticalHeader().setDefaultSectionSize(24)
self.childView.setStyleSheet("QTableView::item:selected:!active { selection-background-color:#BABABA; }")
for i, header in enumerate(self.childHeaders):
self.childModel.setHeaderData(i, Qt.Horizontal, self.childHeaders[self.childView.horizontalHeader().visualIndex(i)])
self.childView.resizeColumnsToContents()
self.parentSlider = RowHeightSlider()
self.childSlider = RowHeightSlider()
self.parentRowHeightLabel = QLabel('Row height: 32')
self.childRowHeightLabel = QLabel('Row height: 32')
parentLayout = QVBoxLayout()
parentLayout.addWidget(self.parentSlider)
parentLayout.addWidget(self.parentRowHeightLabel)
parentLayout.addWidget(self.parentView)
childLayout = QVBoxLayout()
childLayout.addWidget(self.childSlider)
childLayout.addWidget(self.childRowHeightLabel)
childLayout.addWidget(self.childView)
layout = QHBoxLayout()
layout.addLayout(parentLayout)
layout.addLayout(childLayout)
self.setLayout(layout)
self.parentView.selectionModel().currentRowChanged.connect(self.parentChanged)
self.parentSlider.valueChanged.connect(self.changeParentRowHeight)
self.childSlider.valueChanged.connect(self.changeChildRowHeight)
self.parentView.setCurrentIndex(self.parentView.model().index(0, 0))
self.parentView.setFocus()
self.parentSlider.setValue(36)
self.childSlider.setValue(36)
def refreshParent(self):
self.parentHeaders = ['Parent']
queryString = "SELECT parent.parent_name FROM parent"
query = QSqlQuery()
query.exec(queryString)
self.parentModel.setQuery(query)
while self.parentModel.canFetchMore():
self.parentModel.fetchMore()
def refreshChild(self, parent_name=''):
self.childHeaders = ['Child']
queryString = ("SELECT child.child_name FROM child "
"WHERE child.parent_name = '{parent_name}'").format(parent_name = parent_name)
query = QSqlQuery()
query.exec(queryString)
self.childModel.setQuery(query)
while self.childModel.canFetchMore():
self.childModel.fetchMore()
def parentChanged(self, index):
if index.isValid():
index = self.parentProxyModel.mapToSource(index)
record = self.parentModel.record(index.row())
self.refreshChild(record.value("parent.parent_name"))
#self.childView.scrollToBottom() # if needed
def changeParentRowHeight(self, rowHeight):
parentVerticalHeader = self.parentView.verticalHeader()
# (any)one of these two rows (or both) has to be uncommented
parentVerticalHeader.setMinimumSectionSize(rowHeight)
#parentVerticalHeader.setMaximumSectionSize(rowHeight)
for section in range(parentVerticalHeader.count()):
parentVerticalHeader.resizeSection(section, rowHeight)
self.displayParentRowHeightLabel(rowHeight)
def changeChildRowHeight(self, rowHeight):
childVerticalHeader = self.childView.verticalHeader()
# (any)one of these two rows (or both) has to be uncommented
childVerticalHeader.setMinimumSectionSize(rowHeight)
#childVerticalHeader.setMaximumSectionSize(rowHeight)
for section in range(childVerticalHeader.count()):
childVerticalHeader.resizeSection(section, rowHeight)
self.displayChildRowHeightLabel(rowHeight)
def displayParentRowHeightLabel(self, rowHeight):
visibleRows = self.parentView.rowAt(self.parentView.height()) - self.parentView.rowAt(0)
if self.parentView.rowAt(self.parentView.height()) == -1:
visibleRowsString = str(self.parentView.model().rowCount()) + '+'
else:
visibleRowsString = str(visibleRows)
self.parentRowHeightLabel.setText('Row height: ' + str(rowHeight) + ', Visible rows: ' + visibleRowsString)
def displayChildRowHeightLabel(self, rowHeight):
visibleRows = self.childView.rowAt(self.childView.height()) - self.childView.rowAt(0)
if self.childView.rowAt(self.childView.height()) == -1:
visibleRowsString = str(self.childView.model().rowCount()) + '+'
else:
visibleRowsString = str(visibleRows)
self.childRowHeightLabel.setText('Row height: ' + str(rowHeight) + ', Visible rows: ' + visibleRowsString)
def resizeEvent(self, event):
# make it resize-friendly
self.displayParentRowHeightLabel(self.parentSlider.value())
self.displayChildRowHeightLabel(self.childSlider.value())
def createFakeData():
parent_names = []
#import random
query = QSqlQuery()
query.exec("CREATE TABLE parent(parent_name TEXT)")
for i in range(1, 101):
parent_num = str(i).zfill(3)
parent_name = 'parent_name_' + parent_num
parent_names.append((parent_name, parent_num))
query.prepare("INSERT INTO parent (parent_name) VALUES(:parent_name)")
query.bindValue(":parent_name", parent_name)
query.exec()
query.exec("CREATE TABLE child(parent_name TEXT, child_name TEXT)")
counter = 1
for parent_name, parent_num in parent_names:
for i in range(1, 101):
child_name = 'child_name_' + parent_num + '_' + str(counter).zfill(5)
counter += 1
query.prepare("INSERT INTO child (parent_name, child_name) VALUES(:parent_name, :child_name)")
query.bindValue(":parent_name", parent_name)
query.bindValue(":child_name", child_name)
query.exec()
def createConnection():
db = QSqlDatabase.addDatabase("QSQLITE")
#db.setDatabaseName("test04.db")
db.setDatabaseName(":memory:")
db.open()
createFakeData()
app = QApplication(sys.argv)
createConnection()
window = Window()
window.resize(800, 600)
#window.show()
window.showMaximized()
app.exec()
滑块可用于在 "live" 模式下更改 QTableViews 的行高。我通过 OpenVpn 使用 PostgreSQL 对其进行了测试,在一个 QTableView 中有 10,000 行,在父视图中有 100 行,在每个父行的子视图中平均有 1,000 行,它就像一个魅力。