python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > PyQt5 JSON快速查看器

使用Python和PyQt5打造一个JSON快速查看器

作者:小庄-Python办公

本文介绍了如何使用PyQt5创建一个简单的JSON文件查看工具,支持从文件拖拽或打开文件加载JSON数据,并通过输入KEY路径快速查看对应的值,工具界面简洁美观,适合日常调试JSON数据,需要的朋友可以参考下

最近写了一个小工具:只要拖入或打开一个 JSON 文件,输入 KEY,就能快速查看对应的值。本文以 d:\测试\Github项目\59-JOSN快速查看器\main.py 为例,完整拆解这个 PyQt5 小工具的实现思路和关键代码。

一、需求与效果

需求非常简单:

最终效果:

二、项目结构与入口

本工具的主体代码全部在一个文件中:

入口函数代码:

def main():
    app = QApplication(sys.argv)
    viewer = JsonViewer()
    viewer.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

这是典型的 PyQt5 应用启动方式:

  1. 创建 QApplication 实例
  2. 实例化主窗口 JsonViewer
  3. 显示窗口
  4. 进入事件循环

三、窗口与整体样式设计

1. 主窗口类与基础设置

主窗口继承自 QMainWindow

class JsonViewer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.data = None
        self.current_path = None
        self.init_ui()

2. 设置窗口大小与全局样式

def init_ui(self):
    self.setWindowTitle("JSON快速查看器")
    self.resize(800, 520)

    self.setStyleSheet(
        """
        QWidget {
            background-color: #f5f5f7;
            font-family: "Microsoft YaHei";
            font-size: 10pt;
        }
        QPushButton {
            background-color: #0078d7;
            color: white;
            border-radius: 4px;
            padding: 6px 14px;
        }
        QPushButton:hover {
            background-color: #0a84ff;
        }
        QPushButton:pressed {
            background-color: #005a9e;
        }
        QLineEdit, QTextEdit {
            background-color: #ffffff;
            border: 1px solid #d0d0d5;
            border-radius: 4px;
        }
        QLineEdit:focus, QTextEdit:focus {
            border: 1px solid #0a84ff;
        }
        """
    )

这里用了一段简单的 Qt 样式表(类似 CSS):

通过一次性设置 QWidget 和各控件的样式,可以避免对每个控件逐个设置属性,代码更简洁,视觉也更统一。

四、布局与控件拆解

1. 主布局与标题区

central_widget = QWidget()
self.setCentralWidget(central_widget)

main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)
main_layout.setContentsMargins(20, 18, 20, 18)
main_layout.setSpacing(12)

self.info_label = QLabel("JSON 快速查看器")
self.info_label.setAlignment(Qt.AlignCenter)
title_font = self.info_label.font()
title_font.setPointSize(14)
title_font.setBold(True)
self.info_label.setFont(title_font)
main_layout.addWidget(self.info_label)

subtitle = QLabel("拖入 JSON 文件到窗口,或点击右侧按钮选择文件")
subtitle.setAlignment(Qt.AlignCenter)
subtitle.setStyleSheet("color: #666666;")
main_layout.addWidget(subtitle)

2. 文件选择行(显示路径 + 打开按钮)

file_layout = QHBoxLayout()
self.file_label = QLabel("未选择文件")
self.file_label.setMinimumWidth(300)
self.file_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
self.file_label.setStyleSheet("color: #555555;")
open_button = QPushButton("打开JSON")
open_button.clicked.connect(self.open_file)
file_layout.addWidget(self.file_label)
file_layout.addWidget(open_button)
main_layout.addLayout(file_layout)

设计要点:

3. KEY 输入行(KEY + 输入框 + 查询按钮)

key_layout = QHBoxLayout()
key_label = QLabel("KEY:")
key_label.setStyleSheet("color: #333333;")
self.key_edit = QLineEdit()
self.key_edit.setPlaceholderText("例如: user.name 或 items.0.id")
key_font = self.key_edit.font()
key_font.setPointSize(10)
self.key_edit.setFont(key_font)
search_button = QPushButton("查询")
search_button.clicked.connect(self.lookup_key)
self.key_edit.returnPressed.connect(self.lookup_key)
key_layout.addWidget(key_label)
key_layout.addWidget(self.key_edit)
key_layout.addWidget(search_button)
main_layout.addLayout(key_layout)

细节设计:

4. 结果显示区与状态栏

self.result_edit = QTextEdit()
self.result_edit.setReadOnly(True)
result_font = self.result_edit.font()
result_font.setFamily("Consolas")
result_font.setPointSize(10)
self.result_edit.setFont(result_font)
main_layout.addWidget(self.result_edit)

self.status_label = QLabel("")
self.status_label.setStyleSheet("color: #2e7d32;")
main_layout.addWidget(self.status_label)

五、拖拽与打开 JSON 文件

1. 开启拖拽支持

self.setAcceptDrops(True)

然后重写两个事件函数:

def dragEnterEvent(self, event):
    if event.mimeData().hasUrls():
        for url in event.mimeData().urls():
            path = url.toLocalFile()
            if path.lower().endswith(".json"):
                event.acceptProposedAction()
                return
    event.ignore()

逻辑:

真正的放下事件:

def dropEvent(self, event):
    for url in event.mimeData().urls():
        path = url.toLocalFile()
        if path.lower().endswith(".json"):
            self.load_json(path)
            break

2. 通过文件选择框打开 JSON

def open_file(self):
    path, _ = QFileDialog.getOpenFileName(
        self,
        "选择 JSON 文件",
        "",
        "JSON Files (*.json);;All Files (*)",
    )
    if path:
        self.load_json(path)

使用 QFileDialog.getOpenFileName

3. 加载 JSON 文件

def load_json(self, path):
    try:
        with open(path, "r", encoding="utf-8") as f:
            self.data = json.load(f)
        self.current_path = path
        self.file_label.setText(path)
        self.status_label.setText("JSON 加载成功")
        self.result_edit.clear()
    except Exception as e:
        self.data = None
        self.current_path = None
        self.file_label.setText("未选择文件")
        self.status_label.setText("加载失败: {0}".format(e))
        self.result_edit.clear()

六、KEY 路径解析与查询逻辑

1. 查询入口函数

def lookup_key(self):
    if self.data is None:
        self.status_label.setText("请先加载 JSON 文件")
        return

    key_path = self.key_edit.text().strip()
    if not key_path:
        self.status_label.setText("请输入 KEY")
        return

    try:
        value = self.get_value_by_path(self.data, key_path)
    except (KeyError, IndexError, TypeError):
        self.status_label.setText("未找到对应的值")
        self.result_edit.clear()
        return

    if isinstance(value, (dict, list)):
        text = json.dumps(value, ensure_ascii=False, indent=2)
    else:
        text = str(value)

    self.result_edit.setPlainText(text)
    self.status_label.setText("查询成功")

逻辑分几步:

  1. 检查是否已加载 JSON
  2. 检查 KEY 是否为空
  3. 调用 get_value_by_path 获取值,捕获各种失败情况
  4. 如果结果是 dictlist,用 json.dumps 美化输出
  5. 否则直接转成字符串显示

2. 路径解析核心函数

def get_value_by_path(self, data, path):
    if not path:
        return data

    current = data
    parts = path.split(".")

    for part in parts:
        if isinstance(current, list) and part.isdigit():
            index = int(part)
            current = current[index]
        elif isinstance(current, dict):
            if part in current:
                current = current[part]
            else:
                raise KeyError(part)
        else:
            raise KeyError(part)

    return current

这个函数支持的语法:

实现方式:

  1. 把路径按 . 切分为列表 ["items", "0", "id"]
  2. 从根对象开始,逐层向下走
  3. 当前对象是 list 且当前 part 是数字时:
    • 解析成 int 下标,访问对应元素
  4. 当前对象是 dict 时:
    • 直接按照键访问
  5. 如果中途类型不匹配或键不存在,就抛异常,由调用方统一处理为「未找到对应的值」

这个函数逻辑简单清晰,但已经覆盖了绝大部分日常 JSON 调试的需求。

七、少量代码实现一个高频小工具

整个 main.py 代码量不大,却完成了:

如果需要扩展,这个工具还可以进一步完善:

八、小结

这篇文章从需求出发,完整拆解了 main.py 中的实现:

如果你也经常需要调试接口或查看复杂 JSON,不妨参考这个实现,按自己的习惯继续扩展,让它成为你日常开发中的一个趁手小工具。

以上就是Python使用PyQt5打造一个JSON快速查看器的详细内容,更多关于PyQt5 JSON快速查看器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文