在 PyQt5 中填充或读取 QTableWidget 的最快方法
Fastest way to fill or read from a QTableWidget in PyQt5
我在 PyQt5 中有一个 QTableWidget
,我从一个 python numpy 数组字典或一个 pandas DataFrame 中填充它。
问题
我想按照对数组而不是行、列值的操作,以 'vectorized' 的方式填充或读取 QTableWidget
。我在这个 post How can I retrieve data from a QTableWidget to Dataframe? 中看到了其他使用 QTableView
的示例,但这仍然对个人值而不是数组或列表进行操作。这可能吗?
通常我在对行、列值进行操作时这样做:
# To Writte
TableWidget.setItem(row, col, tableItem)
# To Read
TableWidget.item(i, j).data()
我想做这样的事情:
# To Writte
TableWidget.setColumn(col, array_items)
# To Read
TableWidget.getColumn(col).data()
我更愿意继续使用 QTableWidget,但我对 QTableView 等其他选项持开放态度。
感谢您的帮助,Marcelo。
可以使用 TableView
和 re-implemented QAbstractTableModel
来做到这一点。您将调用 TableWidget.model().setColumn(col, array_items)
而不是 TableWidget.setColumn(col, array_items)
。原则上让它与 TableWidget 一起工作,你必须 re-implement QTableWidget
class,但我发现没有必要。
在我的示例中,我使用 pandas DataFrame 作为数据容器。您可以使用列名设置和获取数据。
这是完整的示例:
import sys
import typing
import pandas as pd
from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView, QWidget, QGridLayout, QPushButton
class TableModel(QAbstractTableModel):
def __init__(self, table_data, parent=None):
super().__init__(parent)
self.table_data = table_data
def rowCount(self, parent: QModelIndex = ...) -> int:
return self.table_data.shape[0]
def columnCount(self, parent: QModelIndex = ...) -> int:
return self.table_data.shape[1]
def data(self, index: QModelIndex, role: int = ...) -> typing.Any:
if role == Qt.DisplayRole:
return str(self.table_data.loc[index.row()][index.column()])
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return str(self.table_data.columns[section])
def setColumn(self, col, array_items):
"""Set column data"""
self.table_data[col] = array_items
# Notify table, that data has been changed
self.dataChanged.emit(QModelIndex(), QModelIndex())
def getColumn(self, col):
"""Get column data"""
return self.table_data[col]
if __name__ == "__main__":
app = QApplication(sys.argv)
win = QMainWindow()
widget = QWidget()
layout = QGridLayout()
widget.setLayout(layout)
table_data = pd.DataFrame(data={'col1': [1, 2, 3, 4, 5, 6, 7, 8], 'col2': [1, 2, 3, 4, 5, 6, 7, 8]})
table = QTableView()
table.setModel(TableModel(table_data=table_data))
layout.addWidget(table)
button = QPushButton("Set col1")
button.clicked.connect(lambda: table.model().setColumn("col1", [8, 7, 6, 5, 4, 3, 2, 1]))
button_2 = QPushButton("Read col1")
button_2.clicked.connect(lambda: print(table.model().getColumn("col1")))
layout.addWidget(button)
layout.addWidget(button_2)
win.setCentralWidget(widget)
win.show()
app.exec()
我在 PyQt5 中有一个 QTableWidget
,我从一个 python numpy 数组字典或一个 pandas DataFrame 中填充它。
问题
我想按照对数组而不是行、列值的操作,以 'vectorized' 的方式填充或读取 QTableWidget
。我在这个 post How can I retrieve data from a QTableWidget to Dataframe? 中看到了其他使用 QTableView
的示例,但这仍然对个人值而不是数组或列表进行操作。这可能吗?
通常我在对行、列值进行操作时这样做:
# To Writte
TableWidget.setItem(row, col, tableItem)
# To Read
TableWidget.item(i, j).data()
我想做这样的事情:
# To Writte
TableWidget.setColumn(col, array_items)
# To Read
TableWidget.getColumn(col).data()
我更愿意继续使用 QTableWidget,但我对 QTableView 等其他选项持开放态度。 感谢您的帮助,Marcelo。
可以使用 TableView
和 re-implemented QAbstractTableModel
来做到这一点。您将调用 TableWidget.model().setColumn(col, array_items)
而不是 TableWidget.setColumn(col, array_items)
。原则上让它与 TableWidget 一起工作,你必须 re-implement QTableWidget
class,但我发现没有必要。
在我的示例中,我使用 pandas DataFrame 作为数据容器。您可以使用列名设置和获取数据。
这是完整的示例:
import sys
import typing
import pandas as pd
from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView, QWidget, QGridLayout, QPushButton
class TableModel(QAbstractTableModel):
def __init__(self, table_data, parent=None):
super().__init__(parent)
self.table_data = table_data
def rowCount(self, parent: QModelIndex = ...) -> int:
return self.table_data.shape[0]
def columnCount(self, parent: QModelIndex = ...) -> int:
return self.table_data.shape[1]
def data(self, index: QModelIndex, role: int = ...) -> typing.Any:
if role == Qt.DisplayRole:
return str(self.table_data.loc[index.row()][index.column()])
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return str(self.table_data.columns[section])
def setColumn(self, col, array_items):
"""Set column data"""
self.table_data[col] = array_items
# Notify table, that data has been changed
self.dataChanged.emit(QModelIndex(), QModelIndex())
def getColumn(self, col):
"""Get column data"""
return self.table_data[col]
if __name__ == "__main__":
app = QApplication(sys.argv)
win = QMainWindow()
widget = QWidget()
layout = QGridLayout()
widget.setLayout(layout)
table_data = pd.DataFrame(data={'col1': [1, 2, 3, 4, 5, 6, 7, 8], 'col2': [1, 2, 3, 4, 5, 6, 7, 8]})
table = QTableView()
table.setModel(TableModel(table_data=table_data))
layout.addWidget(table)
button = QPushButton("Set col1")
button.clicked.connect(lambda: table.model().setColumn("col1", [8, 7, 6, 5, 4, 3, 2, 1]))
button_2 = QPushButton("Read col1")
button_2.clicked.connect(lambda: print(table.model().getColumn("col1")))
layout.addWidget(button)
layout.addWidget(button_2)
win.setCentralWidget(widget)
win.show()
app.exec()