PyQt5中JSON加载的data列表在后续代码中为空的问题排查
问题:PyQt5中JSON加载的data在ComboBox选中匹配时为空
我用PyQt5写了个程序,从JSON文件加载data列表填充QComboBox是正常的,但匹配ComboBox选中项时发现data是空的。用CSV加载就没问题,刚学Python找不到原因,相关代码如下:
import os import shutil import sys import csv from PyQt5 import QtCore, QtGui from PyQt5.QtWidgets import QDialog, QApplication,QMessageBox, QInputDialog from PyConWinPy import * import pyperclip import subprocess from easygui import * import json filenamePos = r"C:\Users\MJBmsi\Documents\A_python\QtPyConverter\mjbpos.txt" # desktop filename = r"C:\Users\MJBmsi\Documents\A_python\QtPyConverter\pyCode.json" # desktop data = [] dataPos = [] data2 = [] class MyForm(QDialog): def __init__ (self): super().__init__() self.ui = Ui_mDialog() #change the MDiolod to form name self.ui.setupUi(self) self.ui.comboBox.activated.connect(self.com_index) self.ui.comboBox.addItem("Select Py") self.ui.pushButton.clicked.connect(self.but_Cmd) self.ui.butAdd.clicked.connect(self.butAdd_click) self.ui.butDelete.clicked.connect(self.butDelete_click) self.ui.butBackup.clicked.connect(self.butBackup_click) self.ui.butRestore.clicked.connect(self.butRestore_click) self.ui.butSP.clicked.connect(self.butSP_click) self.show() #revised the window title to show date and time title = "Python Convert -Code Inc. by eeMBee" self.setWindowTitle(title) #open position file and move dialog to that position with open(filenamePos) as f: reader = csv.reader(f) rownum = 0 for row in reader: dataPos.append(row) rownum += 1 f.close() tl = str(dataPos[0]) Lt = int(tl[2: -2]) pt = str(dataPos[1]) Tp = int(pt[2: -2]) self.move(Lt, Tp) # open data file and load array with open(filename, 'r') as fd: data = json.load(fd) global mjb mjb = len(data) fd.close() # load the comboBox - #################THIS WORKS FIN for x in range(mjb): mss = data[x][0] self.ui.comboBox.addItem(mss) # when combobox selection is made load the path and filename def com_index(self): fn = self.ui.comboBox.currentText() global pro pro = fn for z in range(mjb): mss = data[z][0] ##data is empty at this stage and if fn == mss: ##also anywhere farther down in code global ind ind = z self.ui.label.setText(data[z][1]) global pth pth = data[z][2] self.ui.myStatus.setText(pth) #print(pth) # opens the command prompt and loads the 2 commands into the clipboard def but_Cmd(self): s = data[ind][1] sb = "pyuic5 -x " + s + ".ui -o " + s + ".py" ms = pth + " & " + sb pyperclip.copy(ms) proc = subprocess.Popen('cmd.exe /k') sys.exit() # print(pth) #Starts the process to add new projects to the file def butAdd_click(self): newName, ok = QInputDialog.getText( self, "Code Inc. by eeMBee", "Enter the new PROJECT name") print(newName) newFl, ok = QInputDialog.getText( self, "Code Inc. by eeMBee", "Enter the new FILE name") newFile = newFl + "Py" #print(newFile) newPath = diropenbox() #myNewFile = newName + "," + newFile + "," + "cd " + newPath myNewFile = '"' + newName + '"' + "," + '"' + newFile + '",' + '"' + "cd " + newPath + '"' #print(myNewFile) with open(filename, "a") as f: f.write(myNewFile) f.write('\n') f.close() self.ui.myStatus.setText("The new Project is saved to the data file") #opens notepad for deletion # show a Continue/Cancel dialog def butDelete_click(self): button = QMessageBox.question( self, "eeMBee Code Inc.", "Shall I delete the Project " + pro + "?" ) if button == QMessageBox.Yes: with open(filename, 'r') as fd: data = json.load(fd) data[ind][0] = "DELETE" for i in range(mjb): if data[i][0] != "DELETE": data2.append(data[i]) with open(filename, 'w') as fd: json.dump(data2, fd) msg = "the Project " + pro + " was Deleted" self.ui.myStatus.setText(msg) else: msg = "Nothing was Deleted" self.ui.myStatus.setText(msg) #backs up the data file def butBackup_click(self): sor = filename des = r"C:\Users\MJBmsi\Documents\A_python\QtPyConverter\pyCode.bak" shutil.copy(sor, des) self.ui.myStatus.setText("The data file is backed up") # restores the data from the backup file def butRestore_click(self): des = filename sor = r"C:\Users\MJBmsi\Documents\A_python\QtPyConverter\pyCode.bak" shutil.copy(sor, des) self.ui.myStatus.setText("The data file is restored") # saves the position of the form in the window def butSP_click(self): # Get the geometry of the dialog geom = self.geometry () # Get the x and y coordinates of the top-left corner x = left, y = top x = geom.x () y = geom.y () lines = [str(x), str(y)] with open(filenamePos, 'w') as f: for line in lines: f.write(line) f.write('\n') f.close() #base code_ required for form to appear if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) w = MyForm() w.show() sys.exit(app.exec_())
问题原因与修复方案
核心问题分析
- 变量作用域混乱:
你在类外部定义了全局data,但类内加载JSON时data = json.load(fd)创建的是类级局部变量,不是修改全局data。填充ComboBox时用的是这个局部data,所以正常;但com_index等方法访问的是初始为空的全局data,因此出现空值。 - 类代码结构错误:
加载JSON和填充ComboBox的代码直接写在__init__方法外,属于类定义时执行的顶层代码,逻辑上错误,还会加剧作用域混乱。 - JSON格式破坏:
butAdd_click用追加文本的方式写JSON文件,会破坏JSON的合法结构,导致后续加载失败。
修复步骤
1. 调整代码结构,改用实例变量存储数据
把加载JSON和填充ComboBox的代码移到__init__方法内,用self.data(实例变量)存储数据,避免全局变量问题:
def __init__ (self): super().__init__() self.ui = Ui_mDialog() self.ui.setupUi(self) self.ui.comboBox.activated.connect(self.com_index) self.ui.comboBox.addItem("Select Py") # ... 其他初始化代码 ... # 加载JSON数据到实例变量 with open(filename, 'r') as fd: self.data = json.load(fd) self.mjb = len(self.data) # 填充ComboBox for x in range(self.mjb): mss = self.data[x][0] self.ui.comboBox.addItem(mss)
2. 修改所有方法,改用实例变量
把com_index、but_Cmd等方法里的全局变量(data、mjb、ind等)全部替换为实例变量:
def com_index(self): fn = self.ui.comboBox.currentText() self.pro = fn for z in range(self.mjb): mss = self.data[z][0] if fn == mss: self.ind = z self.ui.label.setText(self.data[z][1]) self.pth = self.data[z][2] self.ui.myStatus.setText(self.pth) def but_Cmd(self): s = self.data[self.ind][1] sb = f"pyuic5 -x {s}.ui -o {s}.py" ms = f"{self.pth} & {sb}" pyperclip.copy(ms) subprocess.Popen('cmd.exe /k')
3. 修复新增数据的JSON格式问题
不能直接追加文本,要先读取现有数据、添加新项后重新写入整个文件:
def butAdd_click(self): newName, ok = QInputDialog.getText(self, "Code Inc. by eeMBee", "Enter the new PROJECT name") if not ok or not newName: return newFl, ok = QInputDialog.getText(self, "Code Inc. by eeMBee", "Enter the new FILE name") if not ok or not newFl: return newFile = newFl + "Py" newPath = diropenbox() if not newPath: return # 创建新项并更新数据 new_item = [newName, newFile, f"cd {newPath}"] with open(filename, 'r') as fd: current_data = json.load(fd) current_data.append(new_item) # 重新写入JSON文件 with open(filename, 'w') as fd: json.dump(current_data, fd, indent=4) self.ui.myStatus.setText("The new Project is saved to the data file") # 可选:实时更新ComboBox和实例数据 self.data = current_data self.mjb = len(self.data) self.ui.comboBox.addItem(newName)
4. 删除冗余全局变量
删除类外部的data、mjb等全局变量,彻底避免作用域冲突。
内容的提问来源于stack exchange,提问作者mike brault
相关产品推荐
相关产品推荐

