You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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_())

问题原因与修复方案

核心问题分析

  1. 变量作用域混乱:
    你在类外部定义了全局data,但类内加载JSON时data = json.load(fd)创建的是类级局部变量,不是修改全局data。填充ComboBox时用的是这个局部data,所以正常;但com_index等方法访问的是初始为空的全局data,因此出现空值。
  2. 类代码结构错误:
    加载JSON和填充ComboBox的代码直接写在__init__方法外,属于类定义时执行的顶层代码,逻辑上错误,还会加剧作用域混乱。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:49:51