PyQt导入CSV填充QTableWidget实现及报错问题排查
问题描述
作为Python及程序开发初学者,在搭建PyQt GUI应用时,需要将多个CSV文件的数据展示在界面中,最初尝试使用Python内置csv模块实现加载逻辑,初始代码片段如下:
def loadCsvFile(self, test.csv): with open(test.csv, "r") as stream: for row in csv.reader(stream):
目标是将CSV内容填充到名为Xerox_work_centre_db的表格控件中,更新代码后运行触发如下报错:
File "C:\Temp\GitHub\CSV_to_UI\main.py", line 176, in loadCsv self.model.appendRow(items) AttributeError: 'MainWindow' object has no attribute 'model'
相关UI代码(ui_interface.py)片段:
self.verticalLayout_13.addWidget(self.Monitor_header, 0, Qt.AlignTop) self.Monitor_main_content = QFrame(self.Monitor) self.Monitor_main_content.setObjectName(u"Monitor_main_content") sizePolicy.setHeightForWidth(self.Monitor_main_content.sizePolicy().hasHeightForWidth()) self.Monitor_main_content.setSizePolicy(sizePolicy) self.Monitor_main_content.setFrameShape(QFrame.StyledPanel) self.Monitor_main_content.setFrameShadow(QFrame.Raised) self.verticalLayout_18 = QVBoxLayout(self.Monitor_main_content) self.verticalLayout_18.setSpacing(0) self.verticalLayout_18.setObjectName(u"verticalLayout_18") self.verticalLayout_18.setContentsMargins(0, 0, 0, 0) ####################################### ### CSV CONTENT self.model = QStandardItemModel(MainWindow) self.Xerox_workcentre_db = QTableView(self.Monitor_main_content) self.Xerox_workcentre_db.setObjectName(u"Xerox_workcentre_db") self.Xerox_workcentre_db.setModel(self.model) self.Xerox_workcentre_db.horizontalHeader().setStretchLastSection(True) self.verticalLayout_18.addWidget(self.Xerox_workcentre_db) #######################################
相关主逻辑代码(main.py)片段:
## MAIN WINDOW CLASS ######################################################################## class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.shadow = QGraphicsDropShadowEffect(self) self.shadow.setBlurRadius(50) self.shadow.setXOffset(0) self.shadow.setYOffset(0) self.shadow.setColor(QColor(0, 92, 157, 550)) self.ui.centralwidget.setGraphicsEffect(self.shadow) self.setWindowIcon(QIcon("")) # Set window tittle self.setWindowTitle("Printer Monitoring v1.0") QSizeGrip(self.ui.size_grip) ####################################################################### ## Button for loadCsv self.ui.Xerox_workcentre_button.clicked.connect(self.loadCsv) ####################################################################### self.ui.minimize_window_button.clicked.connect(lambda: self.showMinimized()) self.ui.close_window_button.clicked.connect(lambda: self.close()) self.ui.exit_button.clicked.connect(lambda: self.close()) self.ui.restore_window_button.clicked.connect(lambda: self.restore_or_maximize_window()) def moveWindow(e): if self.isMaximized() == False: # Not maximized if e.buttons() == Qt.LeftButton: self.move(self.pos() + e.globalPos() - self.clickPosition) self.clickPosition = e.globalPos() e.accept() self.ui.header_frame.mouseMoveEvent = moveWindow self.ui.open_close_side_bar_btn.clicked.connect(lambda: self.slideLeftMenu()) self.show() def slideLeftMenu(self): # Get current left menu width width = self.ui.slide_menu_container.width() # If minimized if width == 0: # Expand menu newWidth = 200 self.ui.open_close_side_bar_btn.setIcon(QIcon(u":/icons/icons/chevron-left-solid-white.svg")) # If maximized else: # Restore menu newWidth = 0 self.ui.open_close_side_bar_btn.setIcon(QIcon(u":/icons/icons/bars-solid-white.svg")) # Animate the transition self.animation = QPropertyAnimation(self.ui.slide_menu_container, b"minimumWidth") # Animate minimumWidth self.animation.setDuration(350) self.animation.setStartValue(width) # Start value is the current menu width self.animation.setEndValue(newWidth) # end value is the new menu width self.animation.setEasingCurve(QEasingCurve.InOutQuart) self.animation.start() def mousePressEvent(self, event): self.clickPosition = event.globalPos() def restore_or_maximize_window(self): # If window is maximized if self.isMaximized(): self.showNormal() # Change Icon self.ui.restore_window_button.setIcon(QIcon(u":/icons/icons/window-maximize-regular-white.svg")) else: self.showMaximized() self.ui.restore_window_button.setIcon(QIcon(u":/icons/icons/window-restore-solid-white.svg")) ####################################################################### # CALL XEROX CSV FUNCTION def loadCsv(self): fileName= 'Xerox_workcentre_test.csv' with open(fileName, "r") as fileInput: for row in csv.reader(fileInput): items = [ QtGui.QStandardItem(field) for field in row ] self.model.appendRow(items)
报错原因
model属性定义在Ui_MainWindow类实例下,挂载在self.ui对象上,并非MainWindow类自身的直接属性,直接调用self.model无法找到对应属性,因此抛出AttributeError。- 初始csv加载函数的参数写法
test.csv不符合Python语法,函数参数名不能包含.特殊字符。 - 加载CSV前没有清空原有模型数据,重复点击加载按钮会导致数据重复追加。
- 打开文件时未指定编码,遇到中文等非ASCII字符时可能触发编码报错。
修复方案
1. 修正属性调用路径
将loadCsv方法中所有对self.model的调用改为self.ui.model,指向UI实例下的模型对象。
2. 优化CSV加载逻辑
加载前先清空模型原有数据,避免重复加载导致数据冗余;如果CSV第一行是表头,可单独提取设置为表格表头;打开文件时指定通用编码避免乱码。
3. 修正后的loadCsv代码
import csv from PyQt5 import QtGui def loadCsv(self): fileName = 'Xerox_workcentre_test.csv' # 加载前清空原有模型数据 self.ui.model.clear() # 指定utf-8编码打开文件,适配多语言字符 with open(fileName, "r", encoding='utf-8') as fileInput: csv_reader = csv.reader(fileInput) # 读取第一行作为表头,若CSV无表头可删除以下两行 headers = next(csv_reader) self.ui.model.setHorizontalHeaderLabels(headers) # 逐行加载数据 for row in csv_reader: items = [ QtGui.QStandardItem(field) for field in row ] self.ui.model.appendRow(items) # 可选:加载完成后自动调整列宽适配内容 self.ui.Xerox_workcentre_db.resizeColumnsToContents()
补充:QTableWidget原生加载方案
如果不需要使用Model/View架构,直接用最初的QTableWidget控件加载CSV,可参考以下逻辑:
from PyQt5.QtWidgets import QTableWidgetItem import csv def loadCsvToTableWidget(self): fileName = 'Xerox_workcentre_test.csv' table = self.ui.Xerox_workcentre_db table.clear() with open(fileName, "r", encoding='utf-8') as fileInput: csv_reader = list(csv.reader(fileInput)) row_count = len(csv_reader) col_count = len(csv_reader[0]) if row_count > 0 else 0 table.setRowCount(row_count) table.setColumnCount(col_count) for row_idx, row in enumerate(csv_reader): for col_idx, cell_value in enumerate(row): table.setItem(row_idx, col_idx, QTableWidgetItem(cell_value)) table.resizeColumnsToContents()
内容的提问来源于stack exchange,提问作者TranquiloRL
相关产品推荐
相关产品推荐

