PyQt5+JSON实现小型管理系统(第二弹)

(一)系统界面展示

748f930c7ec34bb8a38e4f527a551eab.png

222f9e8d4eee495ab8e978b81f2d72c9.png

fa441710e1d54a6fb80e833199a71da7.png

(二)开发环境及功能说明

处理器:Apple M1 Max (内存:64G)

系统版本:MacOS Sonoma 14.1.2 

开发环境:Anaconda(Python3.9) + Pycharm + PyQt5(5.15.10) + JSON

程序运行后弹出登录界面,登录成功后转跳系统操作界面,如登录失败给予弹窗提示;进入系统后通过对JSON数据文件操作,实现增删改查的功能;优化代码使用上下文菜单功能删除对应行。在本程序中我将新增,修改,查询共用三个输入框。减去了多线程,详细书写了登录功能。

(三)代码详解

本次程序将代码分为了三部分(两个.py文件,一个JSON文件),其中两个.py文件一个负责逻辑代码,一个负责页面,JSON文件存储数据。目录结构如下

647a148d4af643c8a96f01b90dc9a9c5.png

SystemMain.py代码(页面)

这里我为了方便排版布局方便,使用了Qt Designer 进行布局上的设置,只是布局排版,没有使用槽的连接什么的(悄悄的讲:因为我不会用。。。)只是对主窗口进行布局,登录窗口直接写在了逻辑代码里面

注意:Qt Designer导出的是ui文件,因为没用Qt Designer完整制作只是排版布局,所以像按钮点击事件的连接还是要修改页面上的代码,所以这里要把后缀.ui的文件使用指令转换为.py的文件,方便我们修改点击事件和里面的标语。

ui文件转换为py文件的方法:在ui文件的目录下,使用:pyuic5 -o test.py test.ui

test.py 是转换后的文件名字,test.ui是需要转换的文件名字(这是pyqt5自带的转换工具)

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAbstractItemView

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(535, 397)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.address_input = QtWidgets.QLineEdit(self.centralwidget)
        self.address_input.setGeometry(QtCore.QRect(110, 40, 151, 31))
        self.address_input.setPlaceholderText("请输入注册地址...")  # 设置提示语
        self.address_input.setObjectName("address_input")
        self.username_input = QtWidgets.QLineEdit(self.centralwidget)
        self.username_input.setPlaceholderText("请输入用户名...")  # 设置提示语
        self.username_input.setGeometry(QtCore.QRect(340, 40, 151, 31))
        self.username_input.setObjectName("username_input")
        self.password_input = QtWidgets.QLineEdit(self.centralwidget)
        self.password_input.setPlaceholderText("请输入密码...")  # 设置提示语
        self.password_input.setGeometry(QtCore.QRect(340, 90, 151, 31))
        self.password_input.setObjectName("password_input")
        self.username_lab = QtWidgets.QLabel(self.centralwidget)
        self.username_lab.setGeometry(QtCore.QRect(280, 50, 60, 16))
        self.username_lab.setObjectName("username_lab")
        self.password_lab = QtWidgets.QLabel(self.centralwidget)
        self.password_lab.setGeometry(QtCore.QRect(290, 100, 60, 16))
        self.password_lab.setObjectName("password_lab")
        self.address_lab = QtWidgets.QLabel(self.centralwidget)
        self.address_lab.setGeometry(QtCore.QRect(40, 50, 60, 16))
        self.address_lab.setObjectName("address_lab")
        self.select_btn = QtWidgets.QPushButton(self.centralwidget)
        self.select_btn.setGeometry(QtCore.QRect(150, 90, 113, 32))
        self.select_btn.setObjectName("select_btn")
        self.select_btn.clicked.connect(self.submit_score)
        self.insert_btn = QtWidgets.QPushButton(self.centralwidget)
        self.insert_btn.setGeometry(QtCore.QRect(30, 90, 113, 32))
        self.insert_btn.setObjectName("insert_btn")
        self.insert_btn.clicked.connect(self.add_data)
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(40, 140, 451, 201))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
        # self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.result_lab = QtWidgets.QLabel(self.centralwidget)
        self.result_lab.setGeometry(QtCore.QRect(40, 350, 451, 16))
        self.result_lab.setObjectName("result_lab")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        self.logout_btn = QtWidgets.QPushButton(self.centralwidget)
        self.logout_btn.setGeometry(QtCore.QRect(440, 340, 90, 32))
        self.logout_btn.setObjectName("logout_btn")
        self.logout_btn.clicked.connect(self.logout)
        self.save_btn = QtWidgets.QPushButton(self.centralwidget)
        self.save_btn.setGeometry(QtCore.QRect(360, 340, 90, 32))
        self.save_btn.setObjectName("save_btn")
        self.save_btn.clicked.connect(self.updata)
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.username_lab.setText(_translate("MainWindow", "用户名:"))
        self.password_lab.setText(_translate("MainWindow", "密码:"))
        self.address_lab.setText(_translate("MainWindow", "注册地址:"))
        self.select_btn.setText(_translate("MainWindow", "用户查询"))
        self.insert_btn.setText(_translate("MainWindow", "用户添加"))
        self.result_lab.setText(_translate("MainWindow", "用户提示区"))
        self.logout_btn.setText(_translate("MainWindow", "登出"))
        self.save_btn.setText(_translate("MainWindow", "保存"))

SystemLogic.py代码(逻辑):

导入需要使用的模块

import json
import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QContextMenuEvent
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QMenu, QAction, QMessageBox, QDialog, \
    QLineEdit, QLabel, QPushButton, QVBoxLayout
from SystemMain import Ui_MainWindow

登录功能:

class LoginAndDisplay(QDialog):
    login_successful = pyqtSignal()

    def __init__(self, parent=None):
        super(LoginAndDisplay, self).__init__(parent)

        self.logged_in = False
        self.user_username = "admin"  # 设置用户账号
        self.user_password = "admin"  # 设置用户密码

        self.setWindowTitle('超级管理员登录')
        self.setFixedSize(300, 150)

        self.label_username = QLabel('账号:', self)
        self.input_username = QLineEdit(self)

        self.label_password = QLabel('密码:', self)
        self.input_password = QLineEdit(self)
        self.input_password.setEchoMode(QLineEdit.Password)

        self.btn_login = QPushButton('登录', self)
        self.btn_login.clicked.connect(self.login)

        # -------账号密码免输入--------
        self.input_username.setText(self.user_username)
        self.input_password.setText(self.user_password)

        layout = QVBoxLayout(self)
        layout.addWidget(self.label_username)
        layout.addWidget(self.input_username)
        layout.addWidget(self.label_password)
        layout.addWidget(self.input_password)
        layout.addWidget(self.btn_login)

    # ------------登录功能-------------
    def login(self):
        username_input = self.input_username.text()
        password_input = self.input_password.text()
        if username_input == self.user_username and password_input == self.user_password:
            self.logged_in = True
            self.login_successful.emit()  # 发出登录成功的信号
        else:
            QMessageBox.warning(self, "登录失败", "账号或密码错误!", QMessageBox.Ok)
  1. login_successful = pyqtSignal(): 这是一个 PyQt5 的信号,用于发出登录成功的信号。在后面的代码中,通过连接这个信号和相应的槽函数来实现在登录成功时的一些操作。

  2. __init__(self, parent=None): 类的构造函数,初始化登录界面的各个组件。

  3. login(self): 登录功能的实现方法。在用户点击登录按钮时触发,获取用户输入的用户名和密码,与预设的账号密码进行比对。如果匹配成功,则设置 self.logged_inTrue,并发出 login_successful 信号,表示登录成功。如果匹配失败,则弹出一个警告框提示用户账号或密码错误。

  4. 默认账号和密码:

  5. self.user_username = "admin"  设置默认的用户名为 "admin"。self.user_password = "admin"  设置默认的密码为 "admin"。

  6. 设置输入框内的初始值:(免去了测试时输入账号密码)

    • self.input_username.setText(self.user_username): 将用户名输入框的文本设置为默认的用户名。
    • self.input_password.setText(self.user_password): 将密码输入框的文本设置为默认的密码。

退出功能:

# 用户退出登录
    def logout(self):
        self.close()
        login_and_display.show()
  1. self.close()关闭当前的 UserDisplay 窗口。这个方法用于关闭当前活动的窗口或对话框。

  2. login_and_display.show() 显示登录界面。login_and_display 是一个 LoginAndDisplay 类的实例,通过这个语句,用户退出登录后会返回到登录界面。

读取写入JSON

 # 读取原有数据
 with open('data.json', 'r') as file:
     existing_data = json.load(file)
  1. with open('data.json', 'r') as file: 打开文件 'data.json',并使用 with 语句,确保在读取完数据后正确关闭文件。'r' 参数表示以只读模式打开文件。

  2. existing_data = json.load(file) 使用 Python 的 json 模块中的 load 函数,将打开的文件对象 file 中的 JSON 数据加载到 existing_data 变量中。这样,'data.json' 文件中的原有数据就被读取到一个 Python 数据结构中。

# 将更新后的数据写回文件
with open('data.json', 'w') as file:
    json.dump(existing_data, file, indent=2)
  1. json.dump(existing_data, file, indent=2) 使用 Python 的 json 模块中的 dump 函数,将 existing_data 中的数据写入到文件对象 file 中。参数 indent=2 是为了让写入的 JSON 数据更加可读。这一步实际上是将原有的数据覆盖掉,用更新后的数据进行替换。

查询数据:

# 查询所有数据
    def load_data(self):
        try:
            # 读取原有数据
            with open('data.json', 'r') as file:
                existing_data = json.load(file)

            # 清空表格
            self.tableWidget.setRowCount(0)

            if len(existing_data) == 0:
                self.tableWidget.setRowCount(0)
            else:
                self.tableWidget.setRowCount(len(existing_data))
                self.tableWidget.setColumnCount(3)

                for row, data in enumerate(existing_data):
                    self.tableWidget.setItem(row, 0, QTableWidgetItem(data.get('address')))
                    self.tableWidget.setItem(row, 1, QTableWidgetItem(data.get('username')))
                    self.tableWidget.setItem(row, 2, QTableWidgetItem(data.get('password')))
                # 设置列宽
                self.tableWidget.setColumnWidth(0, 150)
                self.tableWidget.setColumnWidth(1, 140)
                self.tableWidget.setColumnWidth(2, 130)
            # 设置表头标签
            self.tableWidget.setHorizontalHeaderLabels(['address', 'username', 'password'])
        except FileNotFoundError:
            print("File 'data.json' not found.")
            self.result_lab.setText("出错啦!")
        except Exception as e:
            self.result_lab.setText("出错啦!")
            print('Error loading data:', e)
            print('Error loading data:', repr(e))
  1. (1)with open('data.json', 'r') as file:使用 with 语句打开 'data.json' 文件,以只读模式读取文件。

  2. (2)existing_data = json.load(file)使用 json.load 方法将 'data.json' 文件中的 JSON 数据加载到 existing_data 变量中。

  3. (3)self.tableWidget.setRowCount(0)清空表格的行数,以确保在加载新数据之前表格是空的。

  4. (4)if len(existing_data) == 0:检查是否存在数据。如果没有数据,表格行数仍然为0。

  5. (5)self.tableWidget.setRowCount(len(existing_data))设置表格的行数为 existing_data 中的数据项数目。

  6. (6)self.tableWidget.setColumnCount(3)设置表格的列数为3,对应 'address', 'username', 'password'。

  7. (7)使用循环遍历 existing_data 中的每一项,并将其填充到表格的相应位置,使用 QTableWidgetItem

  8. (8)self.tableWidget.setHorizontalHeaderLabels(['address', 'username', 'password'])设置表头标签。

  9. (9)except FileNotFoundError:捕获文件未找到的异常,并打印错误消息。                    except Exception as e:捕获其他可能的异常,并打印错误消息。

删除功能:

    def contextMenuEvent(self, event: QContextMenuEvent):
        # 创建上下文菜单
        context_menu = QMenu(self)

        # 检查表格中是否有选中的项
        selected_items = self.tableWidget.selectedItems()
        if selected_items:
            # 向上下文菜单添加“删除”动作
            delete_action = QAction("删除本行", self)
            delete_action.triggered.connect(self.delete_selected_rows)
            context_menu.addAction(delete_action)
        # 在事件的位置显示上下文菜单
        context_menu.exec_(event.globalPos())

    def delete_selected_rows(self):
        # 获取选中的行并删除它们
        selected_rows = set()
        for item in self.tableWidget.selectedItems():
            selected_rows.add(item.row())

        # 以逆序的方式排序行,以避免删除时的索引问题
        for row in sorted(selected_rows, reverse=True):
            self.tableWidget.removeRow(row)

        # 保存更新后的数据到 JSON 文件
        # 从表格获取数据
        table_data = []
        for row in range(self.tableWidget.rowCount()):
            row_data = {
                'address': self.tableWidget.item(row, 0).text(),
                'username': self.tableWidget.item(row, 1).text(),
                'password': self.tableWidget.item(row, 2).text(),
            }
            table_data.append(row_data)

        # 将数据保存到 JSON 文件
        with open('data.json', 'w', encoding='utf-8') as file:
            json.dump(table_data, file, ensure_ascii=False, indent=2)
        self.result_lab.setText(f"Delect Successful... ")
  1. contextMenuEvent 方法

    • 当右键点击表格时触发,创建一个上下文菜单(QMenu)。
    • 通过检查表格是否有选中的项,决定是否在上下文菜单中添加 "删除本行" 的动作。
    • 通过 context_menu.exec_(event.globalPos()) 在事件的位置显示上下文菜单。
  2. delete_selected_rows 方法

    • 获取选中的行号,并以逆序方式排序,以避免删除时的索引问题。
    • 使用 self.tableWidget.removeRow(row) 删除选中的行。
  3. 保存更新后的数据到 JSON 文件

    • 创建一个列表 table_data,用于存储更新后的数据。
    • 通过遍历表格的每一行,获取每行的数据,添加到 table_data 中。
    • 使用 json.dumptable_data 写入 'data.json' 文件。
    • 在界面上更新 self.result_lab 标签,显示删除成功的消息。

新增功能:

    def add_data(self):
        # 获取输入框中的数据
        address_ = self.address_input.text()
        username_ = self.username_input.text()
        password_ = self.password_input.text()

        new_data = {'address': address_, 'username': username_, 'password': password_}
        # 进行输入校验
        if all(value != '' for value in [address_, username_, password_]):

            # 读取原有数据
            with open('data.json', 'r') as file:
                existing_data = json.load(file)

            # 添加新数据
            existing_data.append(new_data)

            # 将更新后的数据写回文件
            with open('data.json', 'w') as file:
                json.dump(existing_data, file, indent=2)
                self.result_lab.setText(f'New Data Address: {address_}')

            # 清空输入框
            self.address_input.clear()
            self.username_input.clear()
            self.password_input.clear()

            # 重新加载数据
            self.load_data()
        else:
            # 提示用户输入不完整
            QMessageBox.warning(self, '警告', '请填写完整的数据', QMessageBox.Ok)
  1. 获取输入框中的数据

            通过 self.address_input.text()self.username_input.text()self.password_input.text() 获取用户在界面输入框中输入的地址、用户名和密码。
  2. 进行输入校验

             使用 if all(value != '' for value in [address_, username_, password_]): 进行输入校验,确保地址、用户名和密码都不为空。
  3. 读取原有数据

            使用 with open('data.json', 'r') as file: 读取原有的 JSON 数据。
  4. 添加新数据

    • 创建一个字典 new_data 包含新的地址、用户名和密码。
    • 将新数据添加到原有数据的列表 existing_data 中。
  5. 将更新后的数据写回文件

    • 使用 with open('data.json', 'w') as file: 将更新后的数据写回 'data.json' 文件中。
    • 在界面上更新 self.result_lab 标签,显示添加成功的消息。
  6. 清空输入框

            使用 self.address_input.clear()self.username_input.clear()self.password_input.clear() 清空输入框,以便用户输入下一组数据。
  7. 重新加载数据

            使用 self.load_data() 方法重新加载数据,以在表格中显示最新的数据。
  8. 输入不完整的提示

            如果用户未填写完整数据,使用 QMessageBox.warning 显示一个警告框,提示用户需要填写完整数据。

查询功能:

    def submit_score(self):
        try:
            search_address = self.address_input.text()
            if search_address != '':
                # 读取原有数据
                with open('data.json', 'r') as file:
                    existing_data = json.load(file)

                # 查找具有相应注册地址的数据
                search_result = [data for data in existing_data if data.get('address') == search_address]

                if not search_result:  # 如果 search_result 为空
                    self.result_lab.setText("请输入注册地址进行查询...")
                    return

                self.tableWidget.setRowCount(len(search_result))
                for row, data in enumerate(search_result):
                    self.tableWidget.setItem(row, 0, QTableWidgetItem(data.get('address')))
                    self.tableWidget.setItem(row, 1, QTableWidgetItem(data.get('username')))
                    self.tableWidget.setItem(row, 2, QTableWidgetItem(data.get('password')))
            else:
                self.result_lab.setText("暂无查询结果(返回数据总页)")
                self.load_data()
        except FileNotFoundError:
            self.result_lab.setText("文件未找到")
        except Exception as e:
            print(e)
            self.result_lab.setText("出错啦:" + str(e))
        finally:
            self.address_input.clear()
  1. 获取搜索地址

    通过 self.address_input.text() 获取用户在界面输入框中输入的注册地址。
  2. 进行查询

    如果输入的搜索地址不为空,执行以下操作:
    • 使用列表推导式查找具有相应注册地址的数据,保存在 search_result 中。
    • 使用 with open('data.json', 'r') as file: 读取原有的 JSON 数据。
  3. 处理查询结果

    • 如果 search_result 不为空,设置表格的行数,并将查询结果填充到表格中。
    • 如果 search_result 为空,设置界面上的 self.result_lab 标签,显示相应的提示信息。
  4. 处理未输入搜索地址的情况

    • 如果输入的搜索地址为空,设置界面上的 self.result_lab 标签,显示相应的提示信息。
    • 调用 self.load_data() 方法,重新加载所有数据以显示在表格中。
  5. 异常处理

    捕获可能发生的异常,如文件未找到或其他异常,并在界面上显示相应的错误消息。
  6. 清空输入框

    使用 self.address_input.clear() 清空输入框,以便用户输入下一组数据。

更新功能:

 def updata(self):
        # 获取输入框中的数据
        address_ = self.address_input.text()
        username_ = self.username_input.text()
        password_ = self.password_input.text()

        # 读取原有数据
        with open('data.json', 'r', encoding='utf-8') as file:
            existing_data = json.load(file)

        # 根据地址修改数据
        for item in existing_data:
            if item['address'] == address_:
                item['username'] = username_
                item['password'] = password_

        # 将更新后的数据保存回 JSON 文件
        with open('data.json', 'w', encoding='utf-8') as file:
            json.dump(existing_data, file, ensure_ascii=False, indent=2)
            self.result_lab.setText("数据已更新")
        self.load_data()
  1. 获取输入框中的数据

    通过 self.address_input.text()self.username_input.text()self.password_input.text() 获取用户在界面输入框中输入的地址、用户名和密码。
  2. 读取原有数据

    使用 with open('data.json', 'r', encoding='utf-8') as file: 读取原有的 JSON 数据。
  3. 根据地址修改数据

    遍历 existing_data 中的每个字典,如果找到匹配的地址,更新该地址对应的用户名和密码。
  4. 将更新后的数据保存回 JSON 文件

    • 使用 with open('data.json', 'w', encoding='utf-8') as file: 将更新后的数据写回 'data.json' 文件中。
    • 在界面上更新 self.result_lab 标签,显示数据已更新的提示信息。
  5. 重新加载数据

    使用 self.load_data() 方法重新加载数据,以在表格中显示最新的数据。

运行:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    login_and_display = LoginAndDisplay()
    main_window = MainWindow()
    def show_user_display():
        login_and_display.close()
        main_window.show()
        main_window.result_lab.setText("Login System Success...")

    login_and_display.login_successful.connect(show_user_display)
    login_and_display.exec_()
    sys.exit(app.exec_())
  1. 创建 QApplication 对象

    app = QApplication(sys.argv) 创建了一个 Qt 应用程序对象。
  2. 创建 LoginAndDisplay 和 MainWindow 对象

    • login_and_display = LoginAndDisplay() 创建了登录窗口对象。
    • main_window = MainWindow() 创建了主窗口对象。
  3. 定义 show_user_display 函数

    这个函数将在登录成功时被调用,关闭登录窗口,显示主窗口,并在主窗口的 result_lab 标签中显示登录成功的提示信息。
  4. 连接信号和槽

    login_and_display.login_successful.connect(show_user_display) 将登录窗口的登录成功信号连接到 show_user_display 函数。
  5. 显示登录窗口

    login_and_display.exec_() 显示登录窗口并启动应用程序的事件循环。
  6. 退出应用程序

    sys.exit(app.exec_()) 在事件循环结束后,通过 sys.exit 退出应用程序。

(四)完整代码

SystemLogic(逻辑代码)

import json
import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QContextMenuEvent
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QMenu, QAction, QMessageBox, QDialog, \
    QLineEdit, QLabel, QPushButton, QVBoxLayout
from SystemMain import Ui_MainWindow

class LoginAndDisplay(QDialog):
    login_successful = pyqtSignal()

    def __init__(self, parent=None):
        super(LoginAndDisplay, self).__init__(parent)

        self.logged_in = False
        self.user_username = "admin"  # 设置用户账号
        self.user_password = "admin"  # 设置用户密码

        self.setWindowTitle('超级管理员登录')
        self.setFixedSize(300, 150)

        self.label_username = QLabel('账号:', self)
        self.input_username = QLineEdit(self)

        self.label_password = QLabel('密码:', self)
        self.input_password = QLineEdit(self)
        self.input_password.setEchoMode(QLineEdit.Password)

        self.btn_login = QPushButton('登录', self)
        self.btn_login.clicked.connect(self.login)

        # -------账号密码免输入--------
        self.input_username.setText(self.user_username)
        self.input_password.setText(self.user_password)

        layout = QVBoxLayout(self)
        layout.addWidget(self.label_username)
        layout.addWidget(self.input_username)
        layout.addWidget(self.label_password)
        layout.addWidget(self.input_password)
        layout.addWidget(self.btn_login)

    # ------------登录功能-------------
    def login(self):
        username_input = self.input_username.text()
        password_input = self.input_password.text()
        if username_input == self.user_username and password_input == self.user_password:
            self.logged_in = True
            self.login_successful.emit()  # 发出登录成功的信号
        else:
            QMessageBox.warning(self, "登录失败", "账号或密码错误!", QMessageBox.Ok)

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.load_data()

    # 用户退出登录
    def logout(self):
        self.close()
        login_and_display.show()

    # 查询所有数据
    def load_data(self):
        try:
            # 读取原有数据
            with open('data.json', 'r') as file:
                existing_data = json.load(file)

            # 清空表格
            self.tableWidget.setRowCount(0)

            if len(existing_data) == 0:
                self.tableWidget.setRowCount(0)
            else:
                self.tableWidget.setRowCount(len(existing_data))
                self.tableWidget.setColumnCount(3)

                for row, data in enumerate(existing_data):
                    self.tableWidget.setItem(row, 0, QTableWidgetItem(data.get('address')))
                    self.tableWidget.setItem(row, 1, QTableWidgetItem(data.get('username')))
                    self.tableWidget.setItem(row, 2, QTableWidgetItem(data.get('password')))
                # 设置列宽
                self.tableWidget.setColumnWidth(0, 150)
                self.tableWidget.setColumnWidth(1, 140)
                self.tableWidget.setColumnWidth(2, 130)
            # 设置表头标签
            self.tableWidget.setHorizontalHeaderLabels(['address', 'username', 'password'])
        except FileNotFoundError:
            print("File 'data.json' not found.")
            self.result_lab.setText("出错啦!")
        except Exception as e:
            self.result_lab.setText("出错啦!")
            print('Error loading data:', e)
            print('Error loading data:', repr(e))

    def contextMenuEvent(self, event: QContextMenuEvent):
        # 创建上下文菜单
        context_menu = QMenu(self)

        # 检查表格中是否有选中的项
        selected_items = self.tableWidget.selectedItems()
        if selected_items:
            # 向上下文菜单添加“删除”动作
            delete_action = QAction("删除本行", self)
            delete_action.triggered.connect(self.delete_selected_rows)
            context_menu.addAction(delete_action)
        # 在事件的位置显示上下文菜单
        context_menu.exec_(event.globalPos())

    def delete_selected_rows(self):
        # 获取选中的行并删除它们
        selected_rows = set()
        for item in self.tableWidget.selectedItems():
            selected_rows.add(item.row())

        # 以逆序的方式排序行,以避免删除时的索引问题
        for row in sorted(selected_rows, reverse=True):
            self.tableWidget.removeRow(row)

        # 保存更新后的数据到 JSON 文件
        # 从表格获取数据
        table_data = []
        for row in range(self.tableWidget.rowCount()):
            row_data = {
                'address': self.tableWidget.item(row, 0).text(),
                'username': self.tableWidget.item(row, 1).text(),
                'password': self.tableWidget.item(row, 2).text(),
            }
            table_data.append(row_data)

        # 将数据保存到 JSON 文件
        with open('data.json', 'w', encoding='utf-8') as file:
            json.dump(table_data, file, ensure_ascii=False, indent=2)
        self.result_lab.setText(f"Delect Successful... ")


    def add_data(self):
        # 获取输入框中的数据
        address_ = self.address_input.text()
        username_ = self.username_input.text()
        password_ = self.password_input.text()

        new_data = {'address': address_, 'username': username_, 'password': password_}
        # 进行输入校验
        if all(value != '' for value in [address_, username_, password_]):

            # 读取原有数据
            with open('data.json', 'r') as file:
                existing_data = json.load(file)

            # 添加新数据
            existing_data.append(new_data)

            # 将更新后的数据写回文件
            with open('data.json', 'w') as file:
                json.dump(existing_data, file, indent=2)
                self.result_lab.setText(f'New Data Address: {address_}')

            # 清空输入框
            self.address_input.clear()
            self.username_input.clear()
            self.password_input.clear()

            # 重新加载数据
            self.load_data()
        else:
            # 提示用户输入不完整
            QMessageBox.warning(self, '警告', '请填写完整的数据', QMessageBox.Ok)

    # ...
    def submit_score(self):
        try:
            search_address = self.address_input.text()
            if search_address != '':
                # 读取原有数据
                with open('data.json', 'r') as file:
                    existing_data = json.load(file)

                # 查找具有相应注册地址的数据
                search_result = [data for data in existing_data if data.get('address') == search_address]

                if not search_result:  # 如果 search_result 为空
                    self.result_lab.setText("请输入注册地址进行查询...")
                    return

                self.tableWidget.setRowCount(len(search_result))
                for row, data in enumerate(search_result):
                    self.tableWidget.setItem(row, 0, QTableWidgetItem(data.get('address')))
                    self.tableWidget.setItem(row, 1, QTableWidgetItem(data.get('username')))
                    self.tableWidget.setItem(row, 2, QTableWidgetItem(data.get('password')))
            else:
                self.result_lab.setText("暂无查询结果(返回数据总页)")
                self.load_data()
        except FileNotFoundError:
            self.result_lab.setText("文件未找到")
        except Exception as e:
            print(e)
            self.result_lab.setText("出错啦:" + str(e))
        finally:
            self.address_input.clear()

    def updata(self):
        # 获取输入框中的数据
        address_ = self.address_input.text()
        username_ = self.username_input.text()
        password_ = self.password_input.text()

        # 读取原有数据
        with open('data.json', 'r', encoding='utf-8') as file:
            existing_data = json.load(file)

        # 根据地址修改数据
        for item in existing_data:
            if item['address'] == address_:
                item['username'] = username_
                item['password'] = password_

        # 将更新后的数据保存回 JSON 文件
        with open('data.json', 'w', encoding='utf-8') as file:
            json.dump(existing_data, file, ensure_ascii=False, indent=2)
            self.result_lab.setText("数据已更新")
        self.load_data()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    login_and_display = LoginAndDisplay()
    main_window = MainWindow()
    def show_user_display():
        login_and_display.close()
        main_window.show()
        main_window.result_lab.setText("Login System Success...")

    login_and_display.login_successful.connect(show_user_display)
    login_and_display.exec_()
    sys.exit(app.exec_())

SystemMain(页面代码)

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAbstractItemView

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(535, 397)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.address_input = QtWidgets.QLineEdit(self.centralwidget)
        self.address_input.setGeometry(QtCore.QRect(110, 40, 151, 31))
        self.address_input.setPlaceholderText("请输入注册地址...")  # 设置提示语
        self.address_input.setObjectName("address_input")
        self.username_input = QtWidgets.QLineEdit(self.centralwidget)
        self.username_input.setPlaceholderText("请输入用户名...")  # 设置提示语
        self.username_input.setGeometry(QtCore.QRect(340, 40, 151, 31))
        self.username_input.setObjectName("username_input")
        self.password_input = QtWidgets.QLineEdit(self.centralwidget)
        self.password_input.setPlaceholderText("请输入密码...")  # 设置提示语
        self.password_input.setGeometry(QtCore.QRect(340, 90, 151, 31))
        self.password_input.setObjectName("password_input")
        self.username_lab = QtWidgets.QLabel(self.centralwidget)
        self.username_lab.setGeometry(QtCore.QRect(280, 50, 60, 16))
        self.username_lab.setObjectName("username_lab")
        self.password_lab = QtWidgets.QLabel(self.centralwidget)
        self.password_lab.setGeometry(QtCore.QRect(290, 100, 60, 16))
        self.password_lab.setObjectName("password_lab")
        self.address_lab = QtWidgets.QLabel(self.centralwidget)
        self.address_lab.setGeometry(QtCore.QRect(40, 50, 60, 16))
        self.address_lab.setObjectName("address_lab")
        self.select_btn = QtWidgets.QPushButton(self.centralwidget)
        self.select_btn.setGeometry(QtCore.QRect(150, 90, 113, 32))
        self.select_btn.setObjectName("select_btn")
        self.select_btn.clicked.connect(self.submit_score)
        self.insert_btn = QtWidgets.QPushButton(self.centralwidget)
        self.insert_btn.setGeometry(QtCore.QRect(30, 90, 113, 32))
        self.insert_btn.setObjectName("insert_btn")
        self.insert_btn.clicked.connect(self.add_data)
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(40, 140, 451, 201))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
        # self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.result_lab = QtWidgets.QLabel(self.centralwidget)
        self.result_lab.setGeometry(QtCore.QRect(40, 350, 451, 16))
        self.result_lab.setObjectName("result_lab")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        self.logout_btn = QtWidgets.QPushButton(self.centralwidget)
        self.logout_btn.setGeometry(QtCore.QRect(440, 340, 90, 32))
        self.logout_btn.setObjectName("logout_btn")
        self.logout_btn.clicked.connect(self.logout)
        self.save_btn = QtWidgets.QPushButton(self.centralwidget)
        self.save_btn.setGeometry(QtCore.QRect(360, 340, 90, 32))
        self.save_btn.setObjectName("save_btn")
        self.save_btn.clicked.connect(self.updata)
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.username_lab.setText(_translate("MainWindow", "用户名:"))
        self.password_lab.setText(_translate("MainWindow", "密码:"))
        self.address_lab.setText(_translate("MainWindow", "注册地址:"))
        self.select_btn.setText(_translate("MainWindow", "用户查询"))
        self.insert_btn.setText(_translate("MainWindow", "用户添加"))
        self.result_lab.setText(_translate("MainWindow", "用户提示区"))
        self.logout_btn.setText(_translate("MainWindow", "登出"))
        self.save_btn.setText(_translate("MainWindow", "保存"))

JSON文件数据

[
  {
    "address": "rdi@pf.io",
    "username": "\u79b9\u5b97",
    "password": "pwd446"
  },
  {
    "address": "r2ulhht8@hrtnfsic.io",
    "username": "\u6a0a\u5b50",
    "password": "pwd304"
  },
  {
    "address": "evhqx@orv.io",
    "username": "\u6743\u677e\u5357",
    "password": "pwd176"
  },
  {
    "address": "qtq4qybp4j@swtfdk.im",
    "username": "\u59ec\u8fdc",
    "password": "pwd340"
  },
  {
    "address": "oiax41g6j@n4mi.im",
    "username": "\u8a00\u671d",
    "password": "pwd030"
  },
  {
    "address": "vslp7@vc.me",
    "username": "\u53f2\u987a",
    "password": "pwd983"
  },
  {
    "address": "yf8ydn@hfdcq.im",
    "username": "\u51b7\u5a23\u806a",
    "password": "pwd501"
  },
  {
    "address": "5dj3qrym6@g3.cn",
    "username": "\u9ea6\u632f",
    "password": "pwd512"
  },
  {
    "address": "f2w3i0@dn2.cc",
    "username": "\u5b8b\u671d",
    "password": "pwd311"
  },
  {
    "address": "12333",
    "username": "12333",
    "password": "24234"
  }
]

本期的PyQt的程序案例就分享到这了!关注+收藏!关注专栏后期会更新更多PyQt的程序!感谢支持!(平均1-3天更新!)

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RMB Player

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值