吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1449|回复: 13
上一主题 下一主题
收起左侧

[Python 原创] Python数据分析平台

  [复制链接]
跳转到指定楼层
楼主
asdf1233124 发表于 2025-4-9 16:00 回帖奖励

Python数据分析平台功能说明

功能概述

本平台是基于PyQt6框架开发的桌面应用程序,提供数据导入/导出、清洗转换、分析计算和可视化功能。

主要功能模块

1. 数据导入/导出

  • 支持CSV/Excel/JSON格式文件导入
  • 支持将处理后的数据导出为多种格式
  • 通过菜单栏或工具栏的"打开"和"保存"按钮操作

2. 数据清洗与转换

  • 数据排序功能
  • 数据筛选功能
  • 复制/粘贴数据功能

3. 数据分析计算

  • 基本统计分析
  • 线性回归分析
  • 数据预处理

4. 数据可视化

  • 基于matplotlib的静态图表
  • 使用seaborn的高级统计图表
  • 通过工具栏"可视化"按钮操作

界面说明

主界面布局

  • 中央区域:数据表格显示区
  • 顶部:菜单栏和工具栏
  • 底部:状态栏显示操作状态

右键菜单功能

  • 在表格区域右键点击可调出上下文菜单
  • 提供复制、粘贴等快捷操作

使用方法

  1. 通过"文件"菜单或工具栏按钮导入数据
  2. 使用编辑功能对数据进行清洗转换
  3. 使用分析功能进行数据计算
  4. 使用可视化功能生成图表
  5. 处理完成后可导出数据

依赖库

  • PyQt6
  • pandas
  • numpy
  • matplotlib
  • seaborn
  • scikit-learn
  • statsmodels



[Python] 纯文本查看 复制代码
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
"""
Python数据分析平台
基于PyQt6框架开发的桌面应用程序,提供数据导入/导出、清洗转换、分析计算和可视化功能
"""
 
# 导入模块
import sys  # 系统相关功能
from PyQt6.QtWidgets import # PyQt6 GUI组件
    QApplication, QMainWindow, QLabel, QStatusBar,
    QToolBar, QTableWidget, QTableWidgetItem, QMenu, QFileDialog,
    QInputDialog, QMessageBox
)
from PyQt6.QtGui import QAction  # 动作类
from PyQt6.QtCore import Qt  # Qt核心功能
import pandas as pd  # 数据处理库,用于CSV/Excel文件读取
import json  # JSON处理模块,用于JSON文件读取
import numpy as np  # 数值计算库
import matplotlib.pyplot as plt  # 数据可视化库,用于创建静态图表
import seaborn as sns  # 基于matplotlib的高级可视化库,提供更美观的统计图表
from sklearn import linear_model, preprocessing  # 机器学习库
import statsmodels.api as sm  # 统计分析库
 
 
class DataAnalysisPlatform(QMainWindow):
    """
    数据分析平台主窗口类
     
    属性:
        table_widget: QTableWidget - 中央数据表格显示区
        status_bar: QStatusBar - 底部状态栏
        toolbar: QToolBar - 主工具栏
    """
     
    def __init__(self):
        """初始化主窗口"""
        super().__init__()
         
        # 设置窗口标题和尺寸
        self.setWindowTitle("Python数据分析平台")
        self.setGeometry(100, 100, 1200, 800# x, y, width, height
         
        # 初始化UI组件
        self._init_ui()
         
    def _init_ui(self):
        """初始化用户界面"""
        # 创建中央表格部件
        self.table_widget = QTableWidget()
        self.setCentralWidget(self.table_widget)
         
        # 创建状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("就绪")
         
        # 创建菜单栏
        self._create_menus()
         
        # 创建工具栏
        self._create_toolbar()
         
        # 设置表格右键菜单
        self.table_widget.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.table_widget.customContextMenuRequested.connect(self._show_context_menu)
         
    def _create_menus(self):
        """创建菜单栏"""
        # 文件菜单
        file_menu = self.menuBar().addMenu("文件")
         
        # 打开动作
        open_action = QAction("打开", self)
        open_action.triggered.connect(self._open_file)
        file_menu.addAction(open_action)
         
        # 保存动作
        save_action = QAction("保存", self)
        save_action.triggered.connect(self._save_file)
        file_menu.addAction(save_action)
         
        # 编辑菜单
        edit_menu = self.menuBar().addMenu("编辑")
         
        # 排序动作
        sort_action = QAction("排序", self)
        sort_action.triggered.connect(self._sort_data)
        edit_menu.addAction(sort_action)
         
        # 筛选动作
        filter_action = QAction("筛选", self)
        filter_action.triggered.connect(self._filter_data)
        edit_menu.addAction(filter_action)
         
        # 帮助菜单
        help_menu = self.menuBar().addMenu("帮助")
         
        # 关于动作
        about_action = QAction("关于", self)
        about_action.triggered.connect(self._show_about)
        help_menu.addAction(about_action)
         
    def _create_toolbar(self):
        """创建工具栏"""
        self.toolbar = QToolBar("主工具栏")
        self.addToolBar(self.toolbar)
         
        # 添加工具按钮
        open_action = QAction("打开", self)
        open_action.triggered.connect(self._open_file)
        self.toolbar.addAction(open_action)
         
        save_action = QAction("保存", self)
        save_action.triggered.connect(self._save_file)
        self.toolbar.addAction(save_action)
         
        self.toolbar.addSeparator()
         
        sort_action = QAction("排序", self)
        sort_action.triggered.connect(self._sort_data)
        self.toolbar.addAction(sort_action)
         
        filter_action = QAction("筛选", self)
        filter_action.triggered.connect(self._filter_data)
        self.toolbar.addAction(filter_action)
         
        self.toolbar.addSeparator()
         
        analyze_action = QAction("分析", self)
        analyze_action.triggered.connect(self._data_analysis)
        self.toolbar.addAction(analyze_action)
         
        # 可视化按钮并连接信号槽
        visualize_action = QAction("可视化", self)
        visualize_action.triggered.connect(self._visualize_data)
        self.toolbar.addAction(visualize_action)
         
    def _copy_data(self):
        """复制选中单元格数据到剪贴板"""
        selected_items = self.table_widget.selectedItems()
        if not selected_items:
            self.status_bar.showMessage("没有选中要复制的数据")
            return
             
        # 获取选中单元格的文本内容
        data = []
        current_row = -1
         
        for item in selected_items:
            if item.row() != current_row:
                data.append([])
                current_row = item.row()
            data[-1].append(item.text())
         
        # 将数据转换为制表符分隔的字符串
        text = "\n".join("\t".join(row) for row in data)
         
        # 复制到剪贴板
        clipboard = QApplication.clipboard()
        clipboard.setText(text)
        self.status_bar.showMessage(f"已复制 {len(selected_items)} 个单元格数据")
         
    def _paste_data(self):
        """从剪贴板粘贴数据到表格"""
        clipboard = QApplication.clipboard()
        text = clipboard.text()
         
        if not text:
            self.status_bar.showMessage("剪贴板中没有数据")
            return
             
        try:
            # 解析剪贴板数据(制表符分隔的行,换行符分隔的列)
            data = [row.split("\t") for row in text.split("\n") if row]
             
            # 获取当前选中单元格位置
            selected_items = self.table_widget.selectedItems()
            start_row = selected_items[0].row() if selected_items else 0
            start_col = selected_items[0].column() if selected_items else 0
             
            # 将数据粘贴到表格中
            for row_idx, row_data in enumerate(data):
                for col_idx, cell_data in enumerate(row_data):
                    target_row = start_row + row_idx
                    target_col = start_col + col_idx
                     
                    # 确保表格有足够的行和列
                    if target_row >= self.table_widget.rowCount():
                        self.table_widget.insertRow(target_row)
                    if target_col >= self.table_widget.columnCount():
                        self.table_widget.insertColumn(target_col)
                     
                    # 设置单元格数据
                    item = QTableWidgetItem(cell_data)
                    self.table_widget.setItem(target_row, target_col, item)
             
            self.status_bar.showMessage(f"已粘贴 {len(data)} 行数据")
        except Exception as e:
            self.status_bar.showMessage(f"粘贴失败: {str(e)}")
         
    def _show_context_menu(self, position):
        """显示表格右键菜单"""
        menu = QMenu()
         
        # 获取当前点击的行
        row = self.table_widget.rowAt(position.y())
        col = self.table_widget.columnAt(position.x())
         
        # 添加菜单项并连接功能
        copy_action = menu.addAction("复制")
        copy_action.triggered.connect(self._copy_data)
         
        paste_action = menu.addAction("粘贴")
        paste_action.triggered.connect(self._paste_data)
         
        menu.addSeparator()
         
        delete_action = menu.addAction("删除行")
        delete_action.triggered.connect(lambda: self._delete_row(row))
         
        insert_action = menu.addAction("插入行")
        insert_action.triggered.connect(lambda: self._insert_row(row))
         
        menu.addSeparator()
         
        add_col_action = menu.addAction("添加列")
        add_col_action.triggered.connect(self._add_column)
         
        remove_col_action = menu.addAction("删除列")
        remove_col_action.triggered.connect(self._remove_column)
         
        # 新增编辑列名功能
        if col >= 0# 确保点击的是有效的列
            edit_col_action = menu.addAction("编辑列名")
            edit_col_action.triggered.connect(lambda: self._edit_column_name(col))
         
        # 显示菜单
        menu.exec(self.table_widget.viewport().mapToGlobal(position))
         
    def _edit_column_name(self, col):
        """编辑指定列的列名"""
        from PyQt6.QtWidgets import QInputDialog
         
        # 获取当前列名
        current_name = self.table_widget.horizontalHeaderItem(col).text()
         
        # 弹出输入对话框
        new_name, ok = QInputDialog.getText(
            self,
            "编辑列名",
            "请输入新的列名:",
            text=current_name
        )
         
        if ok and new_name:
            # 更新列名
            self.table_widget.setHorizontalHeaderItem(col, QTableWidgetItem(new_name))
            self.status_bar.showMessage(f"已更新列名: {current_name} -> {new_name}")
 
    def _add_column(self):
        """在表格末尾添加新列"""
        col = self.table_widget.columnCount()
        self.table_widget.insertColumn(col)
        self.table_widget.setHorizontalHeaderItem(col, QTableWidgetItem(f"列{col+1}"))
        self.status_bar.showMessage(f"已添加第{col+1}列")
         
    def _remove_column(self):
        """删除当前选中列"""
        col = self.table_widget.currentColumn()
        if col >= 0:
            self.table_widget.removeColumn(col)
            self.status_bar.showMessage(f"已删除第{col+1}列")
        else:
            self.status_bar.showMessage("请先选择要删除的列")
         
    def _insert_row(self, row):
        """在指定位置插入新行"""
        self.table_widget.insertRow(row)
        # 初始化新行的单元格
        for col in range(self.table_widget.columnCount()):
            self.table_widget.setItem(row, col, QTableWidgetItem(""))
         
    def _delete_row(self, row):
        """删除指定行"""
        if row >= 0:
            self.table_widget.removeRow(row)
         
    def _open_file(self):
        """
        打开数据文件并加载到表格中
         
        支持格式: CSV/Excel/JSON
        功能: 通过文件对话框选择文件,读取数据并显示在表格中
        """
        from PyQt6.QtWidgets import QFileDialog  # 文件对话框组件
        import pandas as pd  # 数据处理库
        import json  # JSON处理模块
         
        # 设置文件过滤器,支持多种格式
        file_filter = "数据文件 (*.csv *.xlsx *.json);;CSV文件 (*.csv);;Excel文件 (*.xlsx);;JSON文件 (*.json)"
         
        # 弹出文件选择对话框
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "打开数据文件"# 对话框标题
            "",  # 初始目录
            file_filter  # 文件过滤器
        )
         
        # 如果用户选择了文件
        if file_path:
            try:
                # 根据文件扩展名选择不同的读取方式
                if file_path.endswith('.csv'):
                    # 读取CSV文件
                    data = pd.read_csv(file_path)  # 使用pandas读取CSV
                elif file_path.endswith('.xlsx'):
                    # 读取Excel文件
                    data = pd.read_excel(file_path)  # 使用pandas读取Excel
                elif file_path.endswith('.json'):
                    # 读取JSON文件
                    with open(file_path, 'r', encoding='utf-8') as f:
                        json_data = json.load(f)  # 加载JSON数据
                    data = pd.DataFrame(json_data)  # 转换为DataFrame
                else:
                    raise ValueError("不支持的文件格式")
                 
                # 清空现有表格
                self.table_widget.clear()
                 
                # 设置表格行列数
                self.table_widget.setRowCount(data.shape[0])  # 行数为数据行数
                self.table_widget.setColumnCount(data.shape[1])  # 列数为数据列数
                 
                # 设置表头
                self.table_widget.setHorizontalHeaderLabels(data.columns.tolist())
                 
                # 填充表格数据
                for i in range(data.shape[0]):  # 遍历每一行
                    for j in range(data.shape[1]):  # 遍历每一列
                        # 获取单元格值,处理NaN值为空字符串
                        value = str(data.iloc[i, j]) if not pd.isna(data.iloc[i, j]) else ""
                        # 创建表格项并设置值
                        item = QTableWidgetItem(value)
                        self.table_widget.setItem(i, j, item)
                 
                # 显示成功消息
                self.status_bar.showMessage(f"成功加载文件: {file_path}")
                 
            except Exception as e:
                # 显示错误消息
                self.status_bar.showMessage(f"加载文件失败: {str(e)}")
         
    def _save_file(self):
        """
        保存表格数据到文件
         
        支持格式: CSV/Excel/JSON
        功能: 通过文件对话框选择保存路径和格式,将表格数据保存到指定文件
        """
        from PyQt6.QtWidgets import QFileDialog  # 文件对话框组件
        import pandas as pd  # 数据处理库
        import json  # JSON处理模块
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可保存")
            return
         
        # 设置文件过滤器,支持多种格式
        file_filter = "CSV文件 (*.csv);;Excel文件 (*.xlsx);;JSON文件 (*.json)"
         
        # 弹出文件保存对话框
        file_path, selected_filter = QFileDialog.getSaveFileName(
            self,
            "保存数据文件"# 对话框标题
            "",  # 初始目录
            file_filter  # 文件过滤器
        )
         
        # 如果用户选择了保存路径
        if file_path:
            try:
                # 从表格中提取数据
                data = []
                headers = []
                 
                # 获取表头
                for col in range(self.table_widget.columnCount()):
                    header = self.table_widget.horizontalHeaderItem(col)
                    headers.append(header.text() if header else f"Column{col+1}")
                 
                # 获取表格数据
                for row in range(self.table_widget.rowCount()):
                    row_data = []
                    for col in range(self.table_widget.columnCount()):
                        item = self.table_widget.item(row, col)
                        row_data.append(item.text() if item else "")
                    data.append(row_data)
                 
                # 创建DataFrame
                df = pd.DataFrame(data, columns=headers)
                 
                # 根据选择的文件格式保存数据
                if selected_filter == "CSV文件 (*.csv)" or file_path.endswith('.csv'):
                    # 保存为CSV文件
                    df.to_csv(file_path, index=False, encoding='utf-8-sig')
                elif selected_filter == "Excel文件 (*.xlsx)" or file_path.endswith('.xlsx'):
                    # 保存为Excel文件
                    df.to_excel(file_path, index=False)
                elif selected_filter == "JSON文件 (*.json)" or file_path.endswith('.json'):
                    # 保存为JSON文件
                    df.to_json(file_path, orient='records', force_ascii=False, indent=4)
                else:
                    raise ValueError("不支持的文件格式")
                 
                # 显示成功消息
                self.status_bar.showMessage(f"数据已成功保存到: {file_path}")
                 
            except Exception as e:
                # 显示错误消息
                self.status_bar.showMessage(f"保存文件失败: {str(e)}")
         
    def _sort_data(self):
        """
        对表格数据进行多列排序
         
        功能: 弹出对话框让用户选择最多3列进行组合排序,支持升序/降序
        """
        from PyQt6.QtWidgets import (QInputDialog, QDialog, QVBoxLayout,
                                  QLabel, QComboBox, QDialogButtonBox, QHBoxLayout)
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可排序")
            return
             
        # 创建排序对话框
        dialog = QDialog(self)
        dialog.setWindowTitle("多列排序")
        layout = QVBoxLayout()
         
        # 添加最多3个排序条件
        for i in range(3):
            row_layout = QHBoxLayout()
            row_layout.addWidget(QLabel(f"排序条件 {i+1}:"))
             
            # 列选择下拉框
            col_combo = QComboBox()
            col_combo.setObjectName(f"col_combo_{i}")
            col_combo.addItems([self.table_widget.horizontalHeaderItem(j).text()
                              for j in range(self.table_widget.columnCount())])
            row_layout.addWidget(col_combo)
             
            # 排序方式下拉框
            order_combo = QComboBox()
            order_combo.setObjectName(f"order_combo_{i}")
            order_combo.addItems(["升序", "降序"])
            row_layout.addWidget(order_combo)
             
            layout.addLayout(row_layout)
         
        # 添加确定/取消按钮
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                 QDialogButtonBox.StandardButton.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        layout.addWidget(buttons)
         
        dialog.setLayout(layout)
         
        if dialog.exec() == QDialog.DialogCode.Accepted:
            # 获取排序条件并执行排序
            self.status_bar.showMessage("正在排序数据...")
             
            # 获取当前表格数据
            data = []
            for row in range(self.table_widget.rowCount()):
                row_data = []
                for col in range(self.table_widget.columnCount()):
                    item = self.table_widget.item(row, col)
                    row_data.append(item.text() if item else "")
                data.append(row_data)
             
            # 转换为DataFrame以便排序
            headers = [self.table_widget.horizontalHeaderItem(col).text()
                      for col in range(self.table_widget.columnCount())]
            df = pd.DataFrame(data, columns=headers)
             
            # 获取排序条件
            sort_conditions = []
            for i in range(3):
                col_combo = dialog.findChild(QComboBox, f"col_combo_{i}")
                order_combo = dialog.findChild(QComboBox, f"order_combo_{i}")
                 
                if col_combo and col_combo.currentText():
                    ascending = order_combo.currentText() == "升序"
                    sort_conditions.append((col_combo.currentText(), ascending))
             
            # 执行多列排序
            if sort_conditions:
                df = df.sort_values(
                    by=[col for col, _ in sort_conditions],
                    ascending=[asc for _, asc in sort_conditions]
                )
                 
                # 更新表格数据
                self.table_widget.setRowCount(len(df))
                for row in range(len(df)):
                    for col in range(len(df.columns)):
                        self.table_widget.setItem(row, col,
                            QTableWidgetItem(str(df.iloc[row, col])))
                 
            self.status_bar.showMessage(f"已按{len(sort_conditions)}列排序完成")
        else:
            self.status_bar.showMessage("排序已取消")
         
 
         
    def _clean_data(self):
        """
        数据清洗功能
         
        功能: 对表格数据进行清洗处理,包括空值处理和数据整理
        参数: 无
        返回值: 无
        """
        from PyQt6.QtWidgets import QInputDialog, QMessageBox  # 输入对话框和消息框组件
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可清洗")
            return
             
        # 弹出对话框让用户选择清洗选项
        options = ["删除空行", "填充空值", "删除重复行", "数据类型转换"]
        option, ok = QInputDialog.getItem(
            self,
            "选择清洗选项"# 对话框标题
            "请选择要执行的清洗操作:"# 提示文本
            options,  # 选项列表
            0# 默认选中第一项
            False  # 不允许编辑
        )
         
        # 如果用户取消了选择
        if not ok:
            return
             
        # 根据用户选择执行不同的清洗操作
        try:
            if option == "删除空行":
                # 删除所有空行
                rows_to_remove = []
                for row in range(self.table_widget.rowCount()):
                    is_empty = True
                    for col in range(self.table_widget.columnCount()):
                        item = self.table_widget.item(row, col)
                        if item and item.text().strip():
                            is_empty = False
                            break
                    if is_empty:
                        rows_to_remove.append(row)
                 
                # 从后往前删除行,避免索引错乱
                for row in sorted(rows_to_remove, reverse=True):
                    self.table_widget.removeRow(row)
                 
                self.status_bar.showMessage(f"已删除 {len(rows_to_remove)} 个空行")
                 
            elif option == "填充空值":
                # 填充空值
                col, ok = QInputDialog.getInt(
                    self,
                    "选择列",
                    "请输入要填充空值的列号(从1开始):",
                    1# 默认值
                    1# 最小值
                    self.table_widget.columnCount(),  # 最大值
                    1  # 步长
                )
                 
                if not ok:
                    return
                     
                # 获取填充值
                value, ok = QInputDialog.getText(
                    self,
                    "输入填充值",
                    "请输入要填充的值:"
                )
                 
                if not ok:
                    return
                     
                # 填充空值
                col_index = col - 1
                filled_count = 0
                for row in range(self.table_widget.rowCount()):
                    item = self.table_widget.item(row, col_index)
                    if not item or not item.text().strip():
                        self.table_widget.setItem(row, col_index, QTableWidgetItem(value))
                        filled_count += 1
                 
                self.status_bar.showMessage(f"已填充 {filled_count} 个空值")
                 
            elif option == "删除重复行":
                # 删除重复行
                rows_to_remove = []
                seen_rows = set()
                 
                for row in range(self.table_widget.rowCount()):
                    row_data = []
                    for col in range(self.table_widget.columnCount()):
                        item = self.table_widget.item(row, col)
                        row_data.append(item.text() if item else "")
                     
                    row_tuple = tuple(row_data)
                    if row_tuple in seen_rows:
                        rows_to_remove.append(row)
                    else:
                        seen_rows.add(row_tuple)
                 
                # 从后往前删除行
                for row in sorted(rows_to_remove, reverse=True):
                    self.table_widget.removeRow(row)
                 
                self.status_bar.showMessage(f"已删除 {len(rows_to_remove)} 个重复行")
                 
            elif option == "数据类型转换":
                # 数据类型转换
                col, ok = QInputDialog.getInt(
                    self,
                    "选择列",
                    "请输入要转换数据类型的列号(从1开始):",
                    1,
                    1,
                    self.table_widget.columnCount(),
                    1
                )
                 
                if not ok:
                    return
                     
                # 选择目标类型
                types = ["整数", "浮点数", "字符串", "布尔值"]
                target_type, ok = QInputDialog.getItem(
                    self,
                    "选择目标类型",
                    "请选择要转换的数据类型:",
                    types,
                    0,
                    False
                )
                 
                if not ok:
                    return
                     
                # 执行转换
                col_index = col - 1
                converted_count = 0
                for row in range(self.table_widget.rowCount()):
                    item = self.table_widget.item(row, col_index)
                    if item and item.text().strip():
                        try:
                            text = item.text()
                            if target_type == "整数":
                                value = int(text)
                            elif target_type == "浮点数":
                                value = float(text)
                            elif target_type == "布尔值":
                                value = True if text.lower() in ["true", "1", "yes"] else False
                            else# 字符串
                                value = str(text)
                             
                            self.table_widget.setItem(row, col_index, QTableWidgetItem(str(value)))
                            converted_count += 1
                        except ValueError:
                            pass
                 
                self.status_bar.showMessage(f"已转换 {converted_count} 个值为 {target_type}")
                 
        except Exception as e:
            self.status_bar.showMessage(f"数据清洗失败: {str(e)}")
             
    def _filter_data(self):
        """
        对表格数据进行高级筛选
         
        功能: 弹出对话框让用户设置多条件筛选,支持运算符(=,>,<等)和逻辑组合(AND/OR)
        改进: 支持多条件组合筛选,简化操作流程
        """
        from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
                                  QComboBox, QLineEdit, QDialogButtonBox, QPushButton,
                                  QScrollArea, QWidget, QGroupBox)
        from PyQt6.QtCore import Qt
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可筛选")
            return
             
        # 创建筛选对话框
        dialog = QDialog(self)
        dialog.setWindowTitle("高级筛选")
        dialog.resize(500, 400)
        layout = QVBoxLayout()
         
        # 创建滚动区域
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll_content = QWidget()
        scroll_layout = QVBoxLayout(scroll_content)
         
        # 添加条件组
        condition_group = QGroupBox("筛选条件")
        condition_group_layout = QVBoxLayout()
         
        # 初始条件
        condition_widgets = []
         
        def add_condition():
            condition_widget = QWidget()
            condition_layout = QHBoxLayout()
             
            # 列选择下拉框
            col_combo = QComboBox()
            col_combo.addItems([self.table_widget.horizontalHeaderItem(j).text()
                              for j in range(self.table_widget.columnCount())])
            condition_layout.addWidget(col_combo)
             
            # 运算符下拉框
            operator_combo = QComboBox()
            operator_combo.addItems(["=", ">", "<", "<=", ">=", "!=", "包含", "不包含", "开头为", "结尾为", "为空", "不为空"])
            condition_layout.addWidget(operator_combo)
             
            # 值输入框
            value_edit = QLineEdit()
            condition_layout.addWidget(value_edit)
             
            # 删除按钮
            delete_btn = QPushButton("删除")
            delete_btn.clicked.connect(lambda: remove_condition(condition_widget))
            condition_layout.addWidget(delete_btn)
             
            condition_widget.setLayout(condition_layout)
            condition_group_layout.addWidget(condition_widget)
            condition_widgets.append({
                "widget": condition_widget,
                "col_combo": col_combo,
                "operator_combo": operator_combo,
                "value_edit": value_edit
            })
         
        def remove_condition(widget):
            condition_group_layout.removeWidget(widget)
            widget.deleteLater()
            condition_widgets[:] = [cw for cw in condition_widgets if cw["widget"] != widget]
         
        # 添加初始条件
        add_condition()
         
        # 添加条件按钮
        add_btn = QPushButton("添加条件")
        add_btn.clicked.connect(add_condition)
        condition_group_layout.addWidget(add_btn)
         
        condition_group.setLayout(condition_group_layout)
        scroll_layout.addWidget(condition_group)
         
        # 添加逻辑组合选项
        logic_group = QGroupBox("逻辑组合")
        logic_layout = QVBoxLayout()
        logic_combo = QComboBox()
        logic_combo.addItems(["AND", "OR"])
        logic_layout.addWidget(logic_combo)
        logic_group.setLayout(logic_layout)
        scroll_layout.addWidget(logic_group)
         
        scroll.setWidget(scroll_content)
        layout.addWidget(scroll)
         
        # 添加确定/取消按钮
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                 QDialogButtonBox.StandardButton.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        layout.addWidget(buttons)
         
        dialog.setLayout(layout)
         
        if dialog.exec() == QDialog.DialogCode.Accepted:
            # 获取筛选条件并执行筛选
            self.status_bar.showMessage("正在筛选数据...")
             
            # 获取当前表格数据
            data = []
            for row in range(self.table_widget.rowCount()):
                row_data = []
                for col in range(self.table_widget.columnCount()):
                    item = self.table_widget.item(row, col)
                    row_data.append(item.text() if item else "")
                data.append(row_data)
             
            # 转换为DataFrame以便筛选
            headers = [self.table_widget.horizontalHeaderItem(col).text()
                      for col in range(self.table_widget.columnCount())]
            df = pd.DataFrame(data, columns=headers)
             
            # 获取筛选条件
            masks = []
            logic = logic_combo.currentText()
             
            for condition in condition_widgets:
                col_name = condition["col_combo"].currentText()
                operator = condition["operator_combo"].currentText()
                value = condition["value_edit"].text()
                 
                # 构建筛选条件
                if operator == "=":
                    mask = df[col_name] == value
                elif operator == ">":
                    mask = df[col_name] > value
                elif operator == "<":
                    mask = df[col_name] < value
                elif operator == "<=":
                    mask = df[col_name] <= value
                elif operator == ">=":
                    mask = df[col_name] >= value
                elif operator == "!=":
                    mask = df[col_name] != value
                elif operator == "包含":
                    mask = df[col_name].str.contains(value, na=False)
                elif operator == "不包含":
                    mask = ~df[col_name].str.contains(value, na=False)
                elif operator == "开头为":
                    mask = df[col_name].str.startswith(value, na=False)
                elif operator == "结尾为":
                    mask = df[col_name].str.endswith(value, na=False)
                elif operator == "为空":
                    mask = df[col_name].isna() | (df[col_name] == "")
                elif operator == "不为空":
                    mask = ~df[col_name].isna() & (df[col_name] != "")
                 
                masks.append(mask)
             
            # 组合筛选条件
            if masks:
                combined_mask = masks[0]
                for mask in masks[1:]:
                    if logic == "AND":
                        combined_mask &= mask
                    else:
                        combined_mask |= mask
                 
                filtered_df = df[combined_mask]
            else:
                filtered_df = df.copy()
             
            # 更新表格显示
            self.table_widget.setRowCount(len(filtered_df))
            for row in range(len(filtered_df)):
                for col in range(len(filtered_df.columns)):
                    self.table_widget.setItem(row, col,
                        QTableWidgetItem(str(filtered_df.iloc[row, col])))
             
            self.status_bar.showMessage(
                f"已筛选出{len(filtered_df)}条记录 (共{len(df)}条)" +
                f" | 使用{len(condition_widgets)}个条件{logic}组合"
            )
        else:
            self.status_bar.showMessage("筛选已取消")
         
 
         
    def _data_cleaning(self):
        """
        数据清洗功能
         
        功能: 对表格数据进行清洗处理,包括空值处理和数据整理
        参数: 无
        返回值: 无
        """
        from PyQt6.QtWidgets import QInputDialog  # 输入对话框组件
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可清洗")
            return
             
        # 获取所有列名作为选项
        columns = []
        for col in range(self.table_widget.columnCount()):
            header = self.table_widget.horizontalHeaderItem(col)
            columns.append(header.text() if header else f"Column{col+1}")
             
        # 弹出对话框让用户选择清洗列
        column, ok = QInputDialog.getItem(
            self,
            "选择清洗列"# 对话框标题
            "请选择要清洗的列:"# 提示文本
            columns,  # 选项列表
            0# 默认选中第一项
            False  # 不允许编辑
        )
         
        # 如果用户取消了选择
        if not ok:
            return
             
        # 获取列索引
        col_index = columns.index(column)
         
        # 弹出对话框让用户选择清洗方式
        methods = ["删除空值行", "填充默认值", "删除重复行"]
        method, ok = QInputDialog.getItem(
            self,
            "选择清洗方式",
            "请选择清洗方式:",
            methods,
            0,
            False
        )
         
        # 如果用户取消了选择
        if not ok:
            return
             
        # 执行数据清洗
        try:
            if method == "删除空值行":
                # 删除空值行逻辑
                rows_to_keep = []
                for row in range(self.table_widget.rowCount()):
                    item = self.table_widget.item(row, col_index)
                    if item and item.text().strip():  # 检查单元格是否有值
                        rows_to_keep.append(row)
                 
                # 创建新表格数据
                new_data = []
                for row in rows_to_keep:
                    row_data = []
                    for col in range(self.table_widget.columnCount()):
                        item = self.table_widget.item(row, col)
                        row_data.append(item.text() if item else "")
                    new_data.append(row_data)
                 
                # 更新表格
                self._update_table_with_data(new_data)
                 
                self.status_bar.showMessage(f"已删除{self.table_widget.rowCount() - len(rows_to_keep)}条空值行")
                 
            elif method == "填充默认值":
                # 填充默认值逻辑
                default_value, ok = QInputDialog.getText(
                    self,
                    "输入默认值",
                    f"请输入{column}列的默认值:"
                )
                 
                if ok:
                    for row in range(self.table_widget.rowCount()):
                        item = self.table_widget.item(row, col_index)
                        if not item or not item.text().strip():
                            self.table_widget.setItem(row, col_index, QTableWidgetItem(default_value))
                     
                    self.status_bar.showMessage(f"已将{column}列的空值填充为: {default_value}")
                 
            elif method == "删除重复行":
                # 删除重复行逻辑
                unique_values = set()
                rows_to_keep = []
                 
                for row in range(self.table_widget.rowCount()):
                    item = self.table_widget.item(row, col_index)
                    value = item.text() if item else ""
                    if value not in unique_values:
                        unique_values.add(value)
                        rows_to_keep.append(row)
                 
                # 创建新表格数据
                new_data = []
                for row in rows_to_keep:
                    row_data = []
                    for col in range(self.table_widget.columnCount()):
                        item = self.table_widget.item(row, col)
                        row_data.append(item.text() if item else "")
                    new_data.append(row_data)
                 
                # 更新表格
                self._update_table_with_data(new_data)
                 
                self.status_bar.showMessage(f"已删除{self.table_widget.rowCount() - len(rows_to_keep)}条重复行")
                 
        except Exception as e:
            self.status_bar.showMessage(f"数据清洗失败: {str(e)}")
             
    def _update_table_with_data(self, data):
        """
        用新数据更新表格
         
        参数:
            data: list - 二维列表,包含表格数据
        返回值: 无
        """
        # 清空表格内容
        self.table_widget.clearContents()
         
        # 设置新行数
        self.table_widget.setRowCount(len(data))
         
        # 填充新数据
        for row in range(len(data)):
            for col in range(len(data[row])):
                item = QTableWidgetItem(data[row][col])
                self.table_widget.setItem(row, col, item)
                 
    def _visualize_data(self):
        """
        数据可视化功能
         
        功能: 对表格数据进行可视化展示,支持多种图表类型
        参数: 无
        返回值: 无
        """
        from PyQt6.QtWidgets import QInputDialog, QMessageBox  # 输入对话框和消息框组件
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可可视化")
            return
             
        # 获取所有列名作为选项
        columns = []
        for col in range(self.table_widget.columnCount()):
            header = self.table_widget.horizontalHeaderItem(col)
            columns.append(header.text() if header else f"Column{col+1}")
             
        # 弹出对话框让用户选择可视化列
        column, ok = QInputDialog.getItem(
            self,
            "选择可视化列"# 对话框标题
            "请选择要可视化的列:"# 提示文本
            columns,  # 选项列表
            0# 默认选中第一项
            False  # 不允许编辑
        )
         
        # 如果用户取消了选择
        if not ok:
            return
             
        # 获取列索引
        col_index = columns.index(column)
         
        # 弹出对话框让用户选择图表类型
        chart_types = ["柱状图", "折线图", "饼图", "箱线图", "散点图"]
        chart_type, ok = QInputDialog.getItem(
            self,
            "选择图表类型",
            "请选择图表类型:",
            chart_types,
            0,
            False
        )
         
        # 如果用户取消了选择
        if not ok:
            return
             
        # 收集列数据
        numeric_data = []
        labels = []
        for row in range(self.table_widget.rowCount()):
            item = self.table_widget.item(row, col_index)
            if item and item.text().strip():  # 只处理有值的单元格
                try:
                    # 尝试转换为数值
                    value = float(item.text())
                    numeric_data.append(value)
                    labels.append(str(row+1))  # 使用行号作为标签
                except ValueError:
                    # 非数值数据跳过
                    pass
         
        # 如果没有有效数据
        if not numeric_data:
            self.status_bar.showMessage(f"{column}列没有可可视化的数值数据")
            return
             
        # 执行可视化
        try:
            plt.figure(figsize=(8, 6))  # 设置图表大小
             
            if chart_type == "柱状图":
                # 创建柱状图
                plt.bar(labels, numeric_data)
                plt.title(f"{column}列柱状图"# 设置标题
                plt.xlabel("行号"# X轴标签
                plt.ylabel("数值"# Y轴标签
                 
            elif chart_type == "折线图":
                # 创建折线图
                plt.plot(labels, numeric_data, marker='o')
                plt.title(f"{column}列折线图")
                plt.xlabel("行号")
                plt.ylabel("数值")
                 
            elif chart_type == "饼图":
                # 创建饼图
                plt.pie(numeric_data, labels=labels, autopct='%1.1f%%')
                plt.title(f"{column}列饼图")
                 
            elif chart_type == "箱线图":
                # 创建箱线图
                sns.boxplot(data=numeric_data)
                plt.title(f"{column}列箱线图")
                plt.ylabel("数值")
                 
            elif chart_type == "散点图":
                # 创建散点图
                plt.scatter(range(len(numeric_data)), numeric_data)
                plt.title(f"{column}列散点图")
                plt.xlabel("索引")
                plt.ylabel("数值")
                 
            plt.tight_layout()  # 自动调整子图参数
            plt.show()  # 显示图表
             
            self.status_bar.showMessage(f"已生成{column}列的{chart_type}")
             
        except Exception as e:
            self.status_bar.showMessage(f"数据可视化失败: {str(e)}")
             
    def _data_analysis(self):
        """
        数据分析功能
         
        功能: 对表格数据进行基础统计分析
        参数: 无
        返回值: 无
        """
        from PyQt6.QtWidgets import QMessageBox  # 消息框组件
        import numpy as np  # 数值计算库
         
        # 检查表格是否有数据
        if self.table_widget.rowCount() == 0 or self.table_widget.columnCount() == 0:
            self.status_bar.showMessage("表格中没有数据可分析")
            return
             
        # 基础统计分析
        try:
            stats = []
            for col in range(self.table_widget.columnCount()):
                data = []
                for row in range(self.table_widget.rowCount()):
                    item = self.table_widget.item(row, col)
                    if item and item.text().strip():  # 只处理有值的单元格
                        try:
                            value = float(item.text())
                            data.append(value)
                        except ValueError:
                            pass
                 
                if data:
                    header = self.table_widget.horizontalHeaderItem(col)
                    col_name = header.text() if header else f"Column{col+1}"
                     
                    # 计算统计量
                    stats.append(f"{col_name}列统计结果:")
                    stats.append(f"-----------------")
                    stats.append(f"数据个数: {len(data)}")
                    stats.append(f"平均值: {np.mean(data):.2f}")
                    stats.append(f"标准差: {np.std(data):.2f}")
                    stats.append(f"最小值: {min(data):.2f}")
                    stats.append(f"25%分位数: {np.percentile(data, 25):.2f}")
                    stats.append(f"中位数: {np.median(data):.2f}")
                    stats.append(f"75%分位数: {np.percentile(data, 75):.2f}")
                    stats.append(f"最大值: {max(data):.2f}")
                    stats.append("")
             
            # 显示统计结果
            if stats:
                QMessageBox.information(
                    self,
                    "基础统计结果",
                    "\n".join(stats)
                )
                self.status_bar.showMessage("已完成基础统计分析")
            else:
                self.status_bar.showMessage("没有找到可分析的数值数据")
                 
        except Exception as e:
            self.status_bar.showMessage(f"数据分析失败: {str(e)}")
         
    # except Exception as e:
    #     self.status_bar.showMessage(f"数据分析失败: {str(e)}")
     
    def _show_about(self):
        """显示关于信息"""
        self.status_bar.showMessage("关于功能待实现")
 
 
if __name__ == "__main__":
    """程序入口"""
    app = QApplication(sys.argv)
     
    # 创建主窗口
    window = DataAnalysisPlatform()
    window.show()
     
    # 运行应用
    sys.exit(app.exec())


免费评分

参与人数 6吾爱币 +11 热心值 +5 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ZeLin99 + 1 我很赞同!
ruanxiaoqi + 1 + 1 用心讨论,共获提升!
pyjiujiu + 1 我很赞同!
清淡如风 + 1 + 1 我很赞同!
AlanF1 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
Doublevv 发表于 2025-4-10 10:21
本帖最后由 Doublevv 于 2025-5-12 20:51 编辑

感谢分享源码,已收录到《高质量Python源码资源》专辑
https://www.52pojie.cn/forum.php?mod=collection&action=view&ctid=2848
3#
清淡如风 发表于 2025-4-9 17:07
4#
bi1ovg 发表于 2025-4-9 17:12
5#
ZeLin99 发表于 2025-4-10 09:53
这个脚本特别强大&#128077;
6#
springOfSummer 发表于 2025-4-10 10:18
简洁易用,
7#
space4fly 发表于 2025-4-10 13:49

厉害了,这个脚本够强大!
8#
ziangu 发表于 2025-4-10 14:54
厉害了,感谢大佬分享
9#
coocoocoo3 发表于 2025-4-10 19:25
66666.高人阿。6
10#
马马超超 发表于 2025-4-15 15:05
厉害了,这个脚本够强大
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-5-17 20:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表