mirror of
				https://github.com/goldenfishs/MRobot.git
				synced 2025-10-30 06:35:43 +08:00 
			
		
		
		
	MR_Tool初有成效
This commit is contained in:
		
							parent
							
								
									2e8c902dd2
								
							
						
					
					
						commit
						511f9f4da8
					
				
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -28,3 +28,7 @@ Examples/ | ||||
| !*.axf | ||||
| !*.bin | ||||
| !*.hex | ||||
| 
 | ||||
| /build | ||||
| /dist | ||||
| *.spec | ||||
							
								
								
									
										897
									
								
								MR_Tool.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										897
									
								
								MR_Tool.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,897 @@ | ||||
| import sys | ||||
| import numpy as np | ||||
| import pandas as pd | ||||
| from PyQt5.QtWidgets import ( | ||||
|     QApplication, QWidget, QLabel, QPushButton, QTextEdit, QVBoxLayout, | ||||
|     QHBoxLayout, QStackedWidget, QSizePolicy, QFrame, QGraphicsDropShadowEffect, | ||||
|     QSpinBox, QTableWidget, QTableWidgetItem, QFileDialog, QComboBox, QMessageBox, QHeaderView | ||||
| ) | ||||
| from PyQt5.QtGui import QPixmap, QFont, QIcon | ||||
| from PyQt5.QtCore import Qt | ||||
| import matplotlib | ||||
| from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas | ||||
| from matplotlib.figure import Figure | ||||
| import os | ||||
| import numpy as np | ||||
| import pandas as pd | ||||
| import requests | ||||
| import webbrowser | ||||
| 
 | ||||
| 
 | ||||
| def resource_path(relative_path): | ||||
|     """兼容PyInstaller打包后资源路径""" | ||||
|     if hasattr(sys, '_MEIPASS'): | ||||
|         return os.path.join(sys._MEIPASS, relative_path) | ||||
|     return os.path.join(os.path.abspath("."), relative_path) | ||||
| 
 | ||||
| # --------- 主页 --------- | ||||
| class HomePage(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         layout = QVBoxLayout(self) | ||||
|         layout.setContentsMargins(60, 60, 60, 60) | ||||
|         layout.setSpacing(32) | ||||
|         self.setStyleSheet(""" | ||||
|             QWidget { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #f8fbfd, stop:1 #eaf6fb); | ||||
|                 border-radius: 18px; | ||||
|             } | ||||
|         """) | ||||
| 
 | ||||
|         # 欢迎标题 | ||||
|         title = QLabel("欢迎来到 MRobot 工具箱!") | ||||
|         title.setFont(QFont("微软雅黑", 26, QFont.Bold)) | ||||
|         title.setAlignment(Qt.AlignCenter) | ||||
|         title.setStyleSheet("color: #2980b9; letter-spacing: 3px;") | ||||
|         layout.addWidget(title) | ||||
|         # 设置高度 | ||||
|         title.setFixedHeight(120) | ||||
| 
 | ||||
|         # 分割线 | ||||
|         line = QFrame() | ||||
|         line.setFrameShape(QFrame.HLine) | ||||
|         line.setFrameShadow(QFrame.Sunken) | ||||
|         line.setStyleSheet("color: #d6eaf8; background: #d6eaf8; min-height: 2px;") | ||||
|         layout.addWidget(line) | ||||
| 
 | ||||
|         # 介绍内容 | ||||
|         desc = QLabel( | ||||
|             "🤖 本工具箱由青岛理工大学(QUT)机器人战队开发,\n" | ||||
|             "涵盖沧溟(Robocon)与MOVE(Robomaster)两支队伍。\n\n" | ||||
|             "集成了常用小工具与助手功能,持续更新中ing!\n" | ||||
|             "👉 可通过左侧选择不同模块,助力更高效的机器人开发,\n" | ||||
|             "节约开发时间,减少繁琐操作。\n\n" | ||||
|             "欢迎反馈建议,共同完善工具箱!" | ||||
|         ) | ||||
|         desc.setFont(QFont("微软雅黑", 16)) | ||||
|         desc.setAlignment(Qt.AlignCenter) | ||||
|         desc.setStyleSheet("color: #34495e;") | ||||
|         desc.setWordWrap(True) | ||||
|         layout.addWidget(desc) | ||||
| 
 | ||||
|         # 作者&版本信息 | ||||
|         info = QLabel( | ||||
|             "<b>作者:</b> QUT RMer & RCer   |   " | ||||
|             "<b>版本:</b> 0.0.2   |   " | ||||
|             "<b>联系方式:</b> QQ群 : 857466609" | ||||
|         ) | ||||
|         info.setFont(QFont("微软雅黑", 14)) | ||||
|         info.setAlignment(Qt.AlignCenter) | ||||
|         info.setStyleSheet("color: #7f8c8d; margin-top: 24px;") | ||||
|         info.setFixedHeight(100)  # 修改为固定高度 | ||||
|         layout.addWidget(info) | ||||
| 
 | ||||
|         # 页脚 | ||||
|         footer = QLabel("© 2025 MRobot. 保留所有权利。") | ||||
|         footer.setFont(QFont("微软雅黑", 12)) | ||||
|         footer.setAlignment(Qt.AlignCenter) | ||||
|         footer.setStyleSheet("color: #b2bec3; margin-top: 18px;") | ||||
|         footer.setFixedHeight(100)  # 修改为固定高度 | ||||
|         layout.addWidget(footer) | ||||
| 
 | ||||
| 
 | ||||
| # --------- 功能一:多项式拟合工具页面 --------- | ||||
| class PolyFitApp(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.setFont(QFont("微软雅黑", 15)) | ||||
|         self.data_x = [] | ||||
|         self.data_y = [] | ||||
|         self.last_coeffs = None | ||||
|         self.last_xmin = None | ||||
|         self.last_xmax = None | ||||
| 
 | ||||
|         # 统一背景和边框 | ||||
|         self.setStyleSheet(""" | ||||
|             QWidget { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                 border-radius: 16px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|         """) | ||||
| 
 | ||||
|         main_layout = QHBoxLayout(self) | ||||
|         main_layout.setContentsMargins(24, 24, 24, 24) | ||||
|         main_layout.setSpacing(24) | ||||
|         left_layout = QVBoxLayout() | ||||
|         left_layout.setSpacing(18) | ||||
|         right_layout = QVBoxLayout() | ||||
|         right_layout.setSpacing(18) | ||||
|         main_layout.addLayout(left_layout, 0) | ||||
|         main_layout.addLayout(right_layout, 1) | ||||
| 
 | ||||
|         # 标题 | ||||
|         title = QLabel("曲线拟合工具") | ||||
|         # title.setFont(QFont("微软雅黑", 2, QFont.Bold)) | ||||
|         # 设置文字大小   | ||||
|         title.setFont(QFont("微软雅黑", 14, QFont.Bold)) | ||||
|         title.setAlignment(Qt.AlignCenter) | ||||
|         title.setStyleSheet("color: #2980b9; letter-spacing: 2px;") | ||||
|         left_layout.addWidget(title) | ||||
| 
 | ||||
|         # 数据表 | ||||
|         self.table = QTableWidget(0, 2) | ||||
|         self.table.setFont(QFont("Consolas", 16)) | ||||
|         self.table.setHorizontalHeaderLabels(["x", "y"]) | ||||
|         self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) | ||||
|         self.table.setSelectionBehavior(QTableWidget.SelectRows) | ||||
|         self.table.setStyleSheet(""" | ||||
|             QTableWidget { | ||||
|                 background: #f8fbfd; | ||||
|                 border-radius: 10px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 font-size: 16px; | ||||
|             } | ||||
|             QHeaderView::section { | ||||
|                 background-color: #eaf6fb; | ||||
|                 color: #2980b9; | ||||
|                 font-size: 16px; | ||||
|                 font-weight: bold; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 height: 36px; | ||||
|             } | ||||
|         """) | ||||
|         self.table.setMinimumHeight(200)  # 设置最小高度 | ||||
|         left_layout.addWidget(self.table, stretch=1)  # 让表格尽量撑大 | ||||
| 
 | ||||
|         # 添加/删除行 | ||||
|         btn_row = QHBoxLayout() | ||||
|         self.add_row_btn = QPushButton("添加数据") | ||||
|         self.add_row_btn.setFont(QFont("微软雅黑", 20, QFont.Bold)) | ||||
|         self.add_row_btn.setMinimumHeight(44) | ||||
|         self.add_row_btn.clicked.connect(self.add_point_row) | ||||
|         self.del_row_btn = QPushButton("删除选中行") | ||||
|         self.del_row_btn.setFont(QFont("微软雅黑", 20, QFont.Bold)) | ||||
|         self.del_row_btn.setMinimumHeight(44) | ||||
|         self.del_row_btn.clicked.connect(self.delete_selected_rows) | ||||
|         for btn in [self.add_row_btn, self.del_row_btn]: | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                     color: #2980b9; | ||||
|                     border-radius: 20px; | ||||
|                     font-size: 20px; | ||||
|                     font-weight: 600; | ||||
|                     padding: 10px 0; | ||||
|                     border: 1px solid #d6eaf8; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                     color: #1a6fae; | ||||
|                     border: 1.5px solid #b5d0ea; | ||||
|                 } | ||||
|                 QPushButton:pressed { | ||||
|                     background: #e3f0fa; | ||||
|                     color: #2471a3; | ||||
|                     border: 1.5px solid #a4cbe3; | ||||
|                 } | ||||
|             """) | ||||
|         btn_row.addWidget(self.add_row_btn) | ||||
|         btn_row.addWidget(self.del_row_btn) | ||||
|         left_layout.addLayout(btn_row) | ||||
| 
 | ||||
|         # 导入/导出 | ||||
|         file_btn_row = QHBoxLayout() | ||||
|         self.import_btn = QPushButton("导入Excel文件") | ||||
|         self.import_btn.setFont(QFont("微软雅黑", 18, QFont.Bold)) | ||||
|         self.import_btn.setMinimumHeight(44) | ||||
|         self.import_btn.clicked.connect(self.load_excel) | ||||
|         self.export_btn = QPushButton("导出Excel文件") | ||||
|         self.export_btn.setFont(QFont("微软雅黑", 18, QFont.Bold)) | ||||
|         self.export_btn.setMinimumHeight(44) | ||||
|         self.export_btn.clicked.connect(self.export_excel_and_plot) | ||||
|         for btn in [self.import_btn, self.export_btn]: | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                     color: #2980b9; | ||||
|                     border-radius: 20px; | ||||
|                     font-size: 20px; | ||||
|                     font-weight: 600; | ||||
|                     padding: 10px 0; | ||||
|                     border: 1px solid #d6eaf8; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                     color: #1a6fae; | ||||
|                     border: 1.5px solid #b5d0ea; | ||||
|                 } | ||||
|                 QPushButton:pressed { | ||||
|                     background: #e3f0fa; | ||||
|                     color: #2471a3; | ||||
|                     border: 1.5px solid #a4cbe3; | ||||
|                 } | ||||
|             """) | ||||
|         file_btn_row.addWidget(self.import_btn) | ||||
|         file_btn_row.addWidget(self.export_btn) | ||||
|         left_layout.addLayout(file_btn_row) | ||||
| 
 | ||||
|         # 阶数选择 | ||||
|         param_layout = QHBoxLayout() | ||||
|         label_order = QLabel("多项式阶数:") | ||||
|         # 文字居中 | ||||
|         label_order.setAlignment(Qt.AlignCenter) | ||||
|         # 文字加粗 | ||||
|         label_order.setStyleSheet("color: #2980b9;") | ||||
|         param_layout.addWidget(label_order) | ||||
|         self.order_spin = QSpinBox() | ||||
|         self.order_spin.setFont(QFont("微软雅黑", 18)) | ||||
|         self.order_spin.setRange(1, 10) | ||||
|         self.order_spin.setValue(2) | ||||
|         self.order_spin.setStyleSheet(""" | ||||
|             QSpinBox { | ||||
|                 background: #f8fbfd; | ||||
|                 border-radius: 10px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 font-size: 18px; | ||||
|                 padding: 4px 12px; | ||||
|             } | ||||
|         """) | ||||
|         param_layout.addWidget(self.order_spin) | ||||
|         left_layout.addLayout(param_layout) | ||||
| 
 | ||||
|         # 拟合按钮 | ||||
|         self.fit_btn = QPushButton("拟合并显示") | ||||
|         self.fit_btn.setFont(QFont("微软雅黑", 20, QFont.Bold)) | ||||
|         self.fit_btn.setMinimumHeight(48) | ||||
|         self.fit_btn.clicked.connect(self.fit_and_plot) | ||||
|         self.fit_btn.setStyleSheet(""" | ||||
|             QPushButton { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                 color: #2980b9; | ||||
|                 border-radius: 20px; | ||||
|                 font-size: 22px; | ||||
|                 font-weight: 600; | ||||
|                 padding: 12px 0; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|             QPushButton:hover { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                 color: #1a6fae; | ||||
|                 border: 1.5px solid #b5d0ea; | ||||
|             } | ||||
|             QPushButton:pressed { | ||||
|                 background: #e3f0fa; | ||||
|                 color: #2471a3; | ||||
|                 border: 1.5px solid #a4cbe3; | ||||
|             } | ||||
|         """) | ||||
|         left_layout.addWidget(self.fit_btn) | ||||
|         # 输出区 | ||||
|         self.output = QTextEdit() | ||||
|         self.output.setReadOnly(False) | ||||
|         self.output.setFont(QFont("Consolas", 16)) | ||||
|         self.output.setMaximumHeight(160) | ||||
|         self.output.setStyleSheet(""" | ||||
|             QTextEdit { | ||||
|                 background: #f4f6f7; | ||||
|                 border-radius: 8px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 font-size: 16px; | ||||
|                 color: #2c3e50; | ||||
|                 padding: 10px; | ||||
|             } | ||||
|         """) | ||||
|         # self.table.setFixedHeight(400)  # 设置表格高度为260像素 | ||||
|         left_layout.addWidget(self.output) | ||||
|         # 代码生成 | ||||
|         code_layout = QHBoxLayout() | ||||
|         label_code = QLabel("输出代码格式:") | ||||
|         # label_code.setFont(QFont("微软雅黑", 18, QFont.Bold)) | ||||
|         label_code.setStyleSheet("color: #2980b9;") | ||||
|         code_layout.addWidget(label_code) | ||||
|         self.code_type = QComboBox() | ||||
|         self.code_type.setFont(QFont("微软雅黑", 18)) | ||||
|         self.code_type.addItems(["C", "C++", "Python"]) | ||||
|         self.code_type.setStyleSheet(""" | ||||
|             QComboBox { | ||||
|                 background: #f8fbfd; | ||||
|                 border-radius: 10px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 font-size: 18px; | ||||
|                 padding: 4px 12px; | ||||
|             } | ||||
|         """) | ||||
|         code_layout.addWidget(self.code_type) | ||||
|         self.gen_code_btn = QPushButton("生成代码") | ||||
|         self.gen_code_btn.setFont(QFont("微软雅黑", 18, QFont.Bold)) | ||||
|         self.gen_code_btn.setMinimumHeight(44) | ||||
|         self.gen_code_btn.clicked.connect(self.generate_code) | ||||
|         self.gen_code_btn.setStyleSheet(""" | ||||
|             QPushButton { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                 color: #2980b9; | ||||
|                 border-radius: 20px; | ||||
|                 font-size: 20px; | ||||
|                 font-weight: 600; | ||||
|                 padding: 10px 0; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|             QPushButton:hover { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                 color: #1a6fae; | ||||
|                 border: 1.5px solid #b5d0ea; | ||||
|             } | ||||
|             QPushButton:pressed { | ||||
|                 background: #e3f0fa; | ||||
|                 color: #2471a3; | ||||
|                 border: 1.5px solid #a4cbe3; | ||||
|             } | ||||
|         """) | ||||
|         code_layout.addWidget(self.gen_code_btn) | ||||
|         left_layout.addLayout(code_layout) | ||||
| 
 | ||||
| 
 | ||||
|         # 曲线区加圆角和阴影 | ||||
|         curve_frame = QFrame() | ||||
|         curve_frame.setStyleSheet(""" | ||||
|             QFrame { | ||||
|                 background: #fff; | ||||
|                 border-radius: 16px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|         """) | ||||
|         curve_shadow = QGraphicsDropShadowEffect(self) | ||||
|         curve_shadow.setBlurRadius(24) | ||||
|         curve_shadow.setOffset(0, 4) | ||||
|         curve_shadow.setColor(Qt.gray) | ||||
|         curve_frame.setGraphicsEffect(curve_shadow) | ||||
|         curve_layout = QVBoxLayout(curve_frame) | ||||
|         curve_layout.setContentsMargins(10, 10, 10, 10) | ||||
|         self.figure = Figure(figsize=(6, 5)) | ||||
|         self.canvas = FigureCanvas(self.figure) | ||||
|         curve_layout.addWidget(self.canvas) | ||||
|         right_layout.addWidget(curve_frame) | ||||
| 
 | ||||
|         # 默认显示空坐标系 | ||||
|         self.figure.clear() | ||||
|         ax = self.figure.add_subplot(111) | ||||
|         # ax.set_title("拟合结果", fontsize=22, fontweight='bold') | ||||
|         ax.set_xlabel("x", fontsize=18) | ||||
|         ax.set_ylabel("y", fontsize=18) | ||||
|         ax.tick_params(labelsize=15) | ||||
|         # ax.set_title("拟合结果", fontsize=22, fontweight='bold')  # 中文标题 | ||||
|         self.canvas.draw() | ||||
|          | ||||
|     def add_point_row(self, x_val="", y_val=""): | ||||
|         row = self.table.rowCount() | ||||
|         self.table.insertRow(row) | ||||
|         self.table.setItem(row, 0, QTableWidgetItem(str(x_val))) | ||||
|         self.table.setItem(row, 1, QTableWidgetItem(str(y_val))) | ||||
| 
 | ||||
|     def delete_selected_rows(self): | ||||
|         selected = self.table.selectionModel().selectedRows() | ||||
|         for idx in sorted(selected, reverse=True): | ||||
|             self.table.removeRow(idx.row()) | ||||
| 
 | ||||
|     def load_excel(self): | ||||
|         file, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls)") | ||||
|         if file: | ||||
|             try: | ||||
|                 data = pd.read_excel(file, usecols=[0, 1]) | ||||
|                 new_x = data.iloc[:, 0].values.tolist() | ||||
|                 new_y = data.iloc[:, 1].values.tolist() | ||||
|                 for x, y in zip(new_x, new_y): | ||||
|                     self.add_point_row(x, y) | ||||
|                 QMessageBox.information(self, "成功", "数据导入成功!") | ||||
|             except Exception as e: | ||||
|                 QMessageBox.critical(self, "错误", f"读取Excel失败: {e}") | ||||
| 
 | ||||
|     def export_excel_and_plot(self): | ||||
|         file, _ = QFileDialog.getSaveFileName(self, "导出Excel文件", "", "Excel Files (*.xlsx *.xls)") | ||||
|         if file: | ||||
|             x_list, y_list = [], [] | ||||
|             for row in range(self.table.rowCount()): | ||||
|                 try: | ||||
|                     x = float(self.table.item(row, 0).text()) | ||||
|                     y = float(self.table.item(row, 1).text()) | ||||
|                     x_list.append(x) | ||||
|                     y_list.append(y) | ||||
|                 except Exception: | ||||
|                     continue | ||||
|             if not x_list or not y_list: | ||||
|                 QMessageBox.warning(self, "导出失败", "没有可导出的数据!") | ||||
|                 return | ||||
|             df = pd.DataFrame({'x': x_list, 'y': y_list}) | ||||
|             try: | ||||
|                 df.to_excel(file, index=False) | ||||
|                 png_file = file | ||||
|                 if png_file.lower().endswith('.xlsx') or png_file.lower().endswith('.xls'): | ||||
|                     png_file = png_file.rsplit('.', 1)[0] + '.png' | ||||
|                 else: | ||||
|                     png_file = png_file + '.png' | ||||
|                 self.figure.savefig(png_file, dpi=150, bbox_inches='tight') | ||||
|                 QMessageBox.information(self, "导出成功", f"数据已成功导出到Excel文件!\n图像已导出为:{png_file}") | ||||
|             except Exception as e: | ||||
|                 QMessageBox.critical(self, "导出错误", f"导出Excel或图像失败: {e}") | ||||
| 
 | ||||
|     def get_manual_points(self): | ||||
|         x_list, y_list = [], [] | ||||
|         for row in range(self.table.rowCount()): | ||||
|             try: | ||||
|                 x = float(self.table.item(row, 0).text()) | ||||
|                 y = float(self.table.item(row, 1).text()) | ||||
|                 x_list.append(x) | ||||
|                 y_list.append(y) | ||||
|             except Exception: | ||||
|                 continue | ||||
|         return x_list, y_list | ||||
| 
 | ||||
|     def fit_and_plot(self): | ||||
|         self.data_x, self.data_y = self.get_manual_points() | ||||
|         try: | ||||
|             order = int(self.order_spin.value()) | ||||
|         except ValueError: | ||||
|             QMessageBox.warning(self, "输入错误", "阶数必须为整数!") | ||||
|             return | ||||
|         n_points = len(self.data_x) | ||||
|         if n_points < order + 1: | ||||
|             QMessageBox.warning(self, "数据不足", "数据点数量不足以拟合该阶多项式!") | ||||
|             return | ||||
|         x = np.array(self.data_x, dtype=np.float64) | ||||
|         y = np.array(self.data_y, dtype=np.float64) | ||||
|         x_min, x_max = x.min(), x.max() | ||||
|         if x_max - x_min == 0: | ||||
|             QMessageBox.warning(self, "数据错误", "所有x值都相同,无法拟合!") | ||||
|             return | ||||
|         try: | ||||
|             coeffs = np.polyfit(x, y, order) | ||||
|         except Exception as e: | ||||
|             QMessageBox.critical(self, "拟合错误", f"多项式拟合失败:{e}") | ||||
|             return | ||||
|         poly = np.poly1d(coeffs) | ||||
|         expr = "y = " + " + ".join([f"{c:.6g}*x^{order-i}" for i, c in enumerate(coeffs)]) | ||||
|         self.output.setPlainText(f"{expr}\n") | ||||
|         self.figure.clear() | ||||
|         ax = self.figure.add_subplot(111) | ||||
|         # ax.set_title("拟合结果", fontsize=22, fontweight='bold') | ||||
|         ax.set_xlabel("x", fontsize=18) | ||||
|         ax.set_ylabel("y", fontsize=18) | ||||
|         ax.scatter(x, y, color='red', label='Data') | ||||
|         x_fit = np.linspace(x_min, x_max, 200) | ||||
|         y_fit = poly(x_fit) | ||||
|         ax.plot(x_fit, y_fit, label='Fit Curve') | ||||
|         ax.legend() | ||||
|         self.canvas.draw() | ||||
|         self.last_coeffs = coeffs | ||||
|         self.last_xmin = x_min | ||||
|         self.last_xmax = x_max | ||||
| 
 | ||||
|     def generate_code(self): | ||||
|         if self.last_coeffs is None: | ||||
|             QMessageBox.warning(self, "未拟合", "请先拟合数据!") | ||||
|             return | ||||
|         coeffs = self.last_coeffs | ||||
|         code_type = self.code_type.currentText() | ||||
|         if code_type == "C": | ||||
|             code = self.create_c_function(coeffs) | ||||
|         elif code_type == "C++": | ||||
|             code = self.create_cpp_function(coeffs) | ||||
|         else: | ||||
|             code = self.create_py_function(coeffs) | ||||
|         self.output.setPlainText(code) | ||||
| 
 | ||||
|     def create_c_function(self, coeffs): | ||||
|         lines = ["#include <math.h>", "double polynomial(double x) {", "    return "] | ||||
|         n = len(coeffs) | ||||
|         terms = [] | ||||
|         for i, c in enumerate(coeffs): | ||||
|             exp = n - i - 1 | ||||
|             if exp == 0: | ||||
|                 terms.append(f"{c:.8g}") | ||||
|             elif exp == 1: | ||||
|                 terms.append(f"{c:.8g}*x") | ||||
|             else: | ||||
|                 terms.append(f"{c:.8g}*pow(x,{exp})") | ||||
|         lines[-1] += " + ".join(terms) + ";" | ||||
|         lines.append("}") | ||||
|         return "\n".join(lines) | ||||
| 
 | ||||
|     def create_cpp_function(self, coeffs): | ||||
|         lines = ["#include <cmath>", "double polynomial(double x) {", "    return "] | ||||
|         n = len(coeffs) | ||||
|         terms = [] | ||||
|         for i, c in enumerate(coeffs): | ||||
|             exp = n - i - 1 | ||||
|             if exp == 0: | ||||
|                 terms.append(f"{c:.8g}") | ||||
|             elif exp == 1: | ||||
|                 terms.append(f"{c:.8g}*x") | ||||
|             else: | ||||
|                 terms.append(f"{c:.8g}*pow(x,{exp})") | ||||
|         lines[-1] += " + ".join(terms) + ";" | ||||
|         lines.append("}") | ||||
|         return "\n".join(lines) | ||||
| 
 | ||||
|     def create_py_function(self, coeffs): | ||||
|         n = len(coeffs) | ||||
|         lines = ["def polynomial(x):", "    return "] | ||||
|         terms = [] | ||||
|         for i, c in enumerate(coeffs): | ||||
|             exp = n - i - 1 | ||||
|             if exp == 0: | ||||
|                 terms.append(f"{c:.8g}") | ||||
|             elif exp == 1: | ||||
|                 terms.append(f"{c:.8g}*x") | ||||
|             else: | ||||
|                 terms.append(f"{c:.8g}*x**{exp}") | ||||
|         lines[-1] += " + ".join(terms) | ||||
|         return "\n".join(lines) | ||||
| 
 | ||||
| # --------- 功能二:下载 --------- | ||||
| class DownloadPage(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.setFont(QFont("微软雅黑", 15)) | ||||
|         self.setStyleSheet(""" | ||||
|             QWidget { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                 border-radius: 18px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|         """) | ||||
|         main_layout = QVBoxLayout(self) | ||||
|         main_layout.setContentsMargins(60, 60, 60, 60) | ||||
|         main_layout.setSpacing(32) | ||||
| 
 | ||||
|         # 标题 | ||||
|         title = QLabel("常用工具下载") | ||||
|         title.setFont(QFont("微软雅黑", 26, QFont.Bold)) | ||||
|         title.setAlignment(Qt.AlignCenter) | ||||
|         title.setStyleSheet("color: #2980b9; letter-spacing: 3px; margin-bottom: 10px;") | ||||
|         main_layout.addWidget(title) | ||||
| 
 | ||||
|         # 分割线 | ||||
|         line = QFrame() | ||||
|         line.setFrameShape(QFrame.HLine) | ||||
|         line.setFrameShadow(QFrame.Sunken) | ||||
|         line.setStyleSheet("color: #d6eaf8; background: #d6eaf8; min-height: 2px;") | ||||
|         main_layout.addWidget(line) | ||||
| 
 | ||||
|         # # 说明 | ||||
|         # desc = QLabel("点击下方按钮可直接跳转到常用工具或开发软件的官方下载页面:") | ||||
|         # desc.setFont(QFont("微软雅黑", 17)) | ||||
|         # desc.setAlignment(Qt.AlignCenter) | ||||
|         # desc.setStyleSheet("color: #34495e; margin-bottom: 18px;") | ||||
|         # main_layout.addWidget(desc) | ||||
| 
 | ||||
|         # 两大类布局 | ||||
|         from PyQt5.QtWidgets import QGridLayout, QGroupBox | ||||
| 
 | ||||
|         # 小工具类 | ||||
|         tools_tools = [ | ||||
|             ("Geek Uninstaller", "https://geekuninstaller.com/download", "🧹"), | ||||
|             ("Neat Download Manager", "https://www.neatdownloadmanager.com/index.php/en/", "⬇️"), | ||||
|             ("Everything", "https://www.voidtools.com/zh-cn/downloads/", "🔍"), | ||||
|             ("Bandizip", "https://www.bandisoft.com/bandizip/", "🗜️"), | ||||
|             ("PotPlayer", "https://potplayer.daum.net/", "🎬"), | ||||
|             ("Typora", "https://typora.io/", "📝"), | ||||
|             ("Git", "https://git-scm.com/download/win", "🟥"), | ||||
|             ("Python", "https://www.python.org/downloads/", "🐍"), | ||||
|         ] | ||||
|         tools_group = QGroupBox("常用小工具") | ||||
|         tools_group.setFont(QFont("微软雅黑", 14, QFont.Bold)) | ||||
|         tools_group.setStyleSheet(""" | ||||
|             QGroupBox { | ||||
|                 border: 2px solid #b5d0ea; | ||||
|                 border-radius: 12px; | ||||
|                 margin-top: 16px; | ||||
|                 background: #f8fbfd; | ||||
|                 color: #2471a3; | ||||
|                 padding: 10px 0 0 0; | ||||
|             } | ||||
|             QGroupBox:title { | ||||
|                 subcontrol-origin: margin; | ||||
|                 left: 18px; | ||||
|                 top: -10px; | ||||
|                 background: transparent; | ||||
|                 padding: 0 8px; | ||||
|             } | ||||
|         """) | ||||
|         tools_layout = QGridLayout() | ||||
|         tools_layout.setSpacing(18) | ||||
|         tools_layout.setContentsMargins(24, 24, 24, 24) | ||||
|         for idx, (name, url, icon) in enumerate(tools_tools): | ||||
|             btn = QPushButton(f"{icon}  {name}") | ||||
|             btn.setFont(QFont("微软雅黑", 16, QFont.Bold)) | ||||
|             btn.setMinimumHeight(60) | ||||
|             btn.setCursor(Qt.PointingHandCursor) | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                     color: #2471a3; | ||||
|                     border-radius: 14px; | ||||
|                     font-size: 16px; | ||||
|                     font-weight: 600; | ||||
|                     padding: 8px 0; | ||||
|                     border: 1.5px solid #d6eaf8; | ||||
|                     letter-spacing: 1px; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                     color: #1a6fae; | ||||
|                     border: 2px solid #b5d0ea; | ||||
|                 } | ||||
|                 QPushButton:pressed { | ||||
|                     background: #e3f0fa; | ||||
|                     color: #2471a3; | ||||
|                     border: 2px solid #a4cbe3; | ||||
|                 } | ||||
|             """) | ||||
|             btn.clicked.connect(lambda checked, link=url: webbrowser.open(link)) | ||||
|             row, col = divmod(idx, 4) | ||||
|             tools_layout.addWidget(btn, row, col) | ||||
|         tools_group.setLayout(tools_layout) | ||||
|         main_layout.addWidget(tools_group) | ||||
| 
 | ||||
|         # 开发/设计软件类 | ||||
|         dev_tools = [ | ||||
|             ("STM32CubeMX", "https://www.st.com/zh/development-tools/stm32cubemx.html", "🟦"), | ||||
|             ("Keil MDK", "https://www.keil.com/download/product/", "🟩"), | ||||
|             ("Visual Studio Code", "https://code.visualstudio.com/", "🟦"), | ||||
|             ("CLion", "https://www.jetbrains.com/clion/download/", "🟧"), | ||||
|             ("MATLAB", "https://www.mathworks.com/downloads/", "🟨"), | ||||
|             ("SolidWorks", "https://www.solidworks.com/sw/support/downloads.htm", "🟫"), | ||||
|             ("Altium Designer", "https://www.altium.com/zh/altium-designer/downloads", "🟪"), | ||||
|             ("原神", "https://download-porter.hoyoverse.com/download-porter/2025/03/27/GenshinImpact_install_202503072011.exe?trace_key=GenshinImpact_install_ua_679d0b4e9b10", "🟫"), | ||||
|         ] | ||||
|         dev_group = QGroupBox("开发/设计软件") | ||||
|         dev_group.setFont(QFont("微软雅黑", 14, QFont.Bold)) | ||||
|         dev_group.setStyleSheet(""" | ||||
|             QGroupBox { | ||||
|                 border: 2px solid #b5d0ea; | ||||
|                 border-radius: 12px; | ||||
|                 margin-top: 16px; | ||||
|                 background: #f8fbfd; | ||||
|                 color: #2471a3; | ||||
|                 padding: 10px 0 0 0; | ||||
|             } | ||||
|             QGroupBox:title { | ||||
|                 subcontrol-origin: margin; | ||||
|                 left: 18px; | ||||
|                 top: -10px; | ||||
|                 background: transparent; | ||||
|                 padding: 0 8px; | ||||
|             } | ||||
|         """) | ||||
|         dev_layout = QGridLayout() | ||||
|         dev_layout.setSpacing(18) | ||||
|         dev_layout.setContentsMargins(24, 24, 24, 24) | ||||
|         for idx, (name, url, icon) in enumerate(dev_tools): | ||||
|             btn = QPushButton(f"{icon}  {name}") | ||||
|             btn.setFont(QFont("微软雅黑", 16, QFont.Bold)) | ||||
|             btn.setMinimumHeight(60) | ||||
|             btn.setCursor(Qt.PointingHandCursor) | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                     color: #2471a3; | ||||
|                     border-radius: 14px; | ||||
|                     font-size: 16px; | ||||
|                     font-weight: 600; | ||||
|                     padding: 8px 0; | ||||
|                     border: 1.5px solid #d6eaf8; | ||||
|                     letter-spacing: 1px; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                     color: #1a6fae; | ||||
|                     border: 2px solid #b5d0ea; | ||||
|                 } | ||||
|                 QPushButton:pressed { | ||||
|                     background: #e3f0fa; | ||||
|                     color: #2471a3; | ||||
|                     border: 2px solid #a4cbe3; | ||||
|                 } | ||||
|             """) | ||||
|             btn.clicked.connect(lambda checked, link=url: webbrowser.open(link)) | ||||
|             row, col = divmod(idx, 4) | ||||
|             dev_layout.addWidget(btn, row, col) | ||||
|         dev_group.setLayout(dev_layout) | ||||
|         main_layout.addWidget(dev_group) | ||||
| 
 | ||||
|         main_layout.addStretch(1) | ||||
| 
 | ||||
|         # 页脚 | ||||
|         footer = QLabel("如有问题或建议,欢迎反馈至QQ群:857466609") | ||||
|         footer.setFont(QFont("微软雅黑", 13)) | ||||
|         footer.setAlignment(Qt.AlignCenter) | ||||
|         footer.setStyleSheet("color: #b2bec3; margin-top: 18px;") | ||||
|         main_layout.addWidget(footer) | ||||
| 
 | ||||
| # --------- 功能三:串口助手 --------- | ||||
| # class SerialAssistant(QWidget): | ||||
| 
 | ||||
| # --------- 主工具箱UI --------- | ||||
| class ToolboxUI(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.setWindowTitle("MRobot 工具箱") | ||||
|         self.resize(1920, 1080) | ||||
|         self.setMinimumSize(900, 600) | ||||
|         self.setStyleSheet(""" | ||||
|             QWidget { | ||||
|                 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                     stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                 border-radius: 16px; | ||||
|             } | ||||
|         """) | ||||
|         self.init_ui() | ||||
| 
 | ||||
|     def init_ui(self): | ||||
|         main_layout = QHBoxLayout(self) | ||||
|         main_layout.setContentsMargins(20, 20, 20, 20) | ||||
|         main_layout.setSpacing(20) | ||||
| 
 | ||||
|         # 左侧导航 | ||||
|         left_frame = QFrame() | ||||
|         left_frame.setFrameShape(QFrame.StyledPanel) | ||||
|         left_frame.setStyleSheet(""" | ||||
|             QFrame { | ||||
|                 background: #f8fbfd; | ||||
|                 border-radius: 14px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|         """) | ||||
|         left_shadow = QGraphicsDropShadowEffect(self) | ||||
|         left_shadow.setBlurRadius(16) | ||||
|         left_shadow.setOffset(0, 4) | ||||
|         left_shadow.setColor(Qt.gray) | ||||
|         left_frame.setGraphicsEffect(left_shadow) | ||||
| 
 | ||||
|         left_layout = QVBoxLayout(left_frame) | ||||
|         left_layout.setSpacing(24) | ||||
|         left_layout.setContentsMargins(18, 18, 18, 18) | ||||
|         left_frame.setFixedWidth(260) | ||||
|         main_layout.addWidget(left_frame) | ||||
| 
 | ||||
|         # Logo | ||||
|         logo_label = QLabel() | ||||
|         logo_pixmap = QPixmap(resource_path("mr_tool_img/MRobot.png")) | ||||
|         if not logo_pixmap.isNull(): | ||||
|             logo_label.setPixmap(logo_pixmap.scaled(180, 80, Qt.KeepAspectRatio, Qt.SmoothTransformation)) | ||||
|         else: | ||||
|             logo_label.setText("MRobot") | ||||
|         logo_label.setAlignment(Qt.AlignCenter) | ||||
|         logo_label.setFont(QFont("Arial", 36, QFont.Bold)) | ||||
|         logo_label.setStyleSheet("color: #3498db;") | ||||
|         logo_label.setFixedHeight(120) | ||||
|         left_layout.addWidget(logo_label) | ||||
| 
 | ||||
|         # 按钮区 | ||||
|         self.button_names = ["主页", "曲线拟合", "功能三", "软件指南"] | ||||
|         self.buttons = [] | ||||
|         for idx, name in enumerate(self.button_names): | ||||
|             btn = QPushButton(name) | ||||
|             btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) | ||||
|             btn.setMinimumHeight(48) | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #eaf6fb, stop:1 #d6eaf8); | ||||
|                     color: #2980b9; | ||||
|                     border-radius: 20px; | ||||
|                     font-size: 22px; | ||||
|                     font-weight: 600; | ||||
|                     padding: 14px 0; | ||||
|                     border: 1px solid #d6eaf8; | ||||
|                     letter-spacing: 2px; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, | ||||
|                         stop:0 #f8fffe, stop:1 #cfe7fa); | ||||
|                     color: #1a6fae; | ||||
|                     border: 1.5px solid #b5d0ea; | ||||
|                 } | ||||
|                 QPushButton:pressed { | ||||
|                     background: #e3f0fa; | ||||
|                     color: #2471a3; | ||||
|                     border: 1.5px solid #a4cbe3; | ||||
|                 } | ||||
|             """) | ||||
|             btn.clicked.connect(lambda checked, i=idx: self.switch_function(i)) | ||||
|             self.buttons.append(btn) | ||||
|             left_layout.addWidget(btn) | ||||
| 
 | ||||
|         left_layout.addStretch(1) | ||||
| 
 | ||||
|         # 文本输出框 | ||||
|         self.output_box = QTextEdit() | ||||
|         self.output_box.setReadOnly(True) | ||||
|         self.output_box.setFixedHeight(180) | ||||
|         self.output_box.setStyleSheet(""" | ||||
|             QTextEdit { | ||||
|                 background: #f4f6f7; | ||||
|                 border-radius: 8px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|                 font-size: 16px; | ||||
|                 color: #2c3e50; | ||||
|                 padding: 10px; | ||||
|             } | ||||
|         """) | ||||
|         left_layout.addWidget(self.output_box) | ||||
| 
 | ||||
|         # 右侧功能区 | ||||
|         self.stack = QStackedWidget() | ||||
|         self.stack.setStyleSheet(""" | ||||
|             QStackedWidget { | ||||
|                 background: #fff; | ||||
|                 border-radius: 16px; | ||||
|                 border: 1px solid #d6eaf8; | ||||
|             } | ||||
|         """) | ||||
|         right_shadow = QGraphicsDropShadowEffect(self) | ||||
|         right_shadow.setBlurRadius(24) | ||||
|         right_shadow.setOffset(0, 4) | ||||
|         right_shadow.setColor(Qt.gray) | ||||
|         self.stack.setGraphicsEffect(right_shadow) | ||||
| 
 | ||||
|         # 功能页面注册(后续扩展只需在这里添加页面类即可) | ||||
|         self.page_widgets = { | ||||
|             0: HomePage(),  # 主页 | ||||
|             1: PolyFitApp(),  # 多项式拟合 | ||||
|             2: self.placeholder_page("功能三开发中..."), | ||||
|             3: DownloadPage(),  # 下载页面 | ||||
|         } | ||||
|         for i in range(len(self.button_names)): | ||||
|             self.stack.addWidget(self.page_widgets[i]) | ||||
|         main_layout.addWidget(self.stack) | ||||
| 
 | ||||
|         self.output_box.append("欢迎使用 MRobot 工具箱!请选择左侧功能。") | ||||
| 
 | ||||
|     def placeholder_page(self, text): | ||||
|         page = QWidget() | ||||
|         layout = QVBoxLayout(page) | ||||
|         label = QLabel(text) | ||||
|         label.setAlignment(Qt.AlignCenter) | ||||
|         label.setFont(QFont("微软雅黑", 22, QFont.Bold)) | ||||
|         label.setStyleSheet("color: #2980b9;") | ||||
|         layout.addStretch(1) | ||||
|         layout.addWidget(label) | ||||
|         layout.addStretch(1) | ||||
|         return page | ||||
| 
 | ||||
|     def switch_function(self, idx): | ||||
|         self.stack.setCurrentIndex(idx) | ||||
|         self.output_box.append(f"已切换到功能:{self.button_names[idx]}") | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     app = QApplication(sys.argv) | ||||
|     win = ToolboxUI() | ||||
|     win.show() | ||||
|     sys.exit(app.exec_()) | ||||
| @ -1,92 +0,0 @@ | ||||
| import sys | ||||
| from PyQt5.QtWidgets import ( | ||||
|     QApplication, QWidget, QLabel, QPushButton, QTextEdit, QVBoxLayout, | ||||
|     QHBoxLayout, QStackedWidget, QSizePolicy, QFrame | ||||
| ) | ||||
| from PyQt5.QtGui import QPixmap, QFont | ||||
| from PyQt5.QtCore import Qt | ||||
| 
 | ||||
| class ToolboxUI(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.setWindowTitle("MRobot 工具箱") | ||||
|         self.setMinimumSize(900, 600) | ||||
|         self.init_ui() | ||||
| 
 | ||||
|     def init_ui(self): | ||||
|         # 主布局 | ||||
|         main_layout = QHBoxLayout(self) | ||||
|         main_layout.setContentsMargins(10, 10, 10, 10) | ||||
|         main_layout.setSpacing(10) | ||||
| 
 | ||||
|         # 左半区 | ||||
|         left_frame = QFrame() | ||||
|         left_frame.setFrameShape(QFrame.StyledPanel) | ||||
|         left_layout = QVBoxLayout(left_frame) | ||||
|         left_layout.setSpacing(20) | ||||
| 
 | ||||
|         # Logo | ||||
|         logo_label = QLabel() | ||||
|         logo_pixmap = QPixmap(180, 80) | ||||
|         logo_pixmap.fill(Qt.transparent) | ||||
|         logo_label.setPixmap(logo_pixmap) | ||||
|         logo_label.setText("MRobot") | ||||
|         logo_label.setAlignment(Qt.AlignCenter) | ||||
|         logo_label.setFont(QFont("Arial", 28, QFont.Bold)) | ||||
|         logo_label.setStyleSheet("color: #3498db;") | ||||
|         logo_label.setFixedHeight(100) | ||||
|         left_layout.addWidget(logo_label) | ||||
| 
 | ||||
|         # 按钮区 | ||||
|         self.buttons = [] | ||||
|         button_names = ["功能一", "功能二", "功能三", "功能四"] | ||||
|         for idx, name in enumerate(button_names): | ||||
|             btn = QPushButton(name) | ||||
|             btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) | ||||
|             btn.setMinimumHeight(40) | ||||
|             btn.setStyleSheet(""" | ||||
|                 QPushButton { | ||||
|                     background-color: #2980b9; color: white; | ||||
|                     border-radius: 8px; font-size: 16px; | ||||
|                 } | ||||
|                 QPushButton:hover { | ||||
|                     background-color: #3498db; | ||||
|                 } | ||||
|             """) | ||||
|             btn.clicked.connect(lambda checked, i=idx: self.switch_function(i)) | ||||
|             self.buttons.append(btn) | ||||
|             left_layout.addWidget(btn) | ||||
| 
 | ||||
|         left_layout.addStretch(1) | ||||
| 
 | ||||
|         # 文本输出框 | ||||
|         self.output_box = QTextEdit() | ||||
|         self.output_box.setReadOnly(True) | ||||
|         self.output_box.setFixedHeight(80) | ||||
|         self.output_box.setStyleSheet("background: #f4f6f7; border-radius: 6px;") | ||||
|         left_layout.addWidget(self.output_box) | ||||
| 
 | ||||
|         left_frame.setMaximumWidth(240) | ||||
|         main_layout.addWidget(left_frame) | ||||
| 
 | ||||
|         # 右半区 | ||||
|         self.stack = QStackedWidget() | ||||
|         for i in range(len(button_names)): | ||||
|             page = QLabel(f"这里是 {button_names[i]} 的功能界面") | ||||
|             page.setAlignment(Qt.AlignCenter) | ||||
|             page.setFont(QFont("微软雅黑", 20)) | ||||
|             self.stack.addWidget(page) | ||||
|         main_layout.addWidget(self.stack) | ||||
| 
 | ||||
|         # 默认输出 | ||||
|         self.output_box.append("欢迎使用 MRobot 工具箱!请选择左侧功能。") | ||||
| 
 | ||||
|     def switch_function(self, idx): | ||||
|         self.stack.setCurrentIndex(idx) | ||||
|         self.output_box.append(f"已切换到功能:{self.buttons[idx].text()}") | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     app = QApplication(sys.argv) | ||||
|     win = ToolboxUI() | ||||
|     win.show() | ||||
|     sys.exit(app.exec_()) | ||||
| @ -87,4 +87,5 @@ | ||||
| 使用以下命令构建可执行文件: | ||||
| 
 | ||||
| ```bash | ||||
| pyinstaller --onefile --windowed  | ||||
| pyinstaller --onefile --windowed  | ||||
| pyinstaller MR_Toolbox.py --onefile --noconsole --icon=img\M.ico --add-data "mr_tool_img\MRobot.png;mr_tool_img" | ||||
							
								
								
									
										
											BIN
										
									
								
								mr_tool_img/MRobot.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mr_tool_img/MRobot.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 96 KiB | 
							
								
								
									
										304
									
								
								polynomial.py
									
									
									
									
									
								
							
							
						
						
									
										304
									
								
								polynomial.py
									
									
									
									
									
								
							| @ -1,205 +1,216 @@ | ||||
| import tkinter as tk | ||||
| from tkinter import filedialog, messagebox, ttk | ||||
| import sys | ||||
| import numpy as np | ||||
| import pandas as pd | ||||
| from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg | ||||
| from PyQt5.QtWidgets import ( | ||||
|     QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QSpinBox, | ||||
|     QLabel, QTableWidget, QTableWidgetItem, QFileDialog, QTextEdit, | ||||
|     QComboBox, QMessageBox, QHeaderView | ||||
| ) | ||||
| from PyQt5.QtGui import QFont | ||||
| from PyQt5.QtCore import Qt | ||||
| import matplotlib | ||||
| from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas | ||||
| from matplotlib.figure import Figure | ||||
| 
 | ||||
| class PolyFitApp: | ||||
|     def __init__(self, root): | ||||
|         self.root = root | ||||
|         self.root.title("多项式拟合工具") | ||||
| class PolyFitApp(QWidget): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.setWindowTitle("MRobot 多项式拟合工具") | ||||
|         self.resize(1440, 1280) | ||||
|         self.setFont(QFont("微软雅黑", 11)) | ||||
|         self.center() | ||||
| 
 | ||||
|         self.data_x = [] | ||||
|         self.data_y = [] | ||||
|         self.last_coeffs = None | ||||
|         self.last_xmin = None | ||||
|         self.last_xmax = None | ||||
| 
 | ||||
|         # ===== 主布局 ===== | ||||
|         main_frame = ttk.Frame(root, padding=8) | ||||
|         main_frame.pack(fill="both", expand=True) | ||||
|         main_frame.columnconfigure(0, weight=0) | ||||
|         main_frame.columnconfigure(1, weight=1) | ||||
|         main_frame.rowconfigure(0, weight=1) | ||||
|         # 主布局 | ||||
|         main_layout = QHBoxLayout(self) | ||||
|         main_layout.setContentsMargins(20, 20, 20, 20) | ||||
|         main_layout.setSpacing(20) | ||||
|         left_layout = QVBoxLayout() | ||||
|         left_layout.setSpacing(12) | ||||
|         right_layout = QVBoxLayout() | ||||
|         right_layout.setSpacing(12) | ||||
|         main_layout.addLayout(left_layout, 0) | ||||
|         main_layout.addLayout(right_layout, 1) | ||||
| 
 | ||||
|         # ===== 左侧区 ===== | ||||
|         left_frame = ttk.Frame(main_frame, width=320, height=580)  # 设置固定宽度 | ||||
|         left_frame.grid(row=0, column=0, sticky="nsw")  # 只贴左侧 | ||||
|         left_frame.columnconfigure(0, weight=1) | ||||
|         left_frame.grid_propagate(False)  # 防止自动缩放 | ||||
|         # 数据输入区 | ||||
|         self.table = QTableWidget(0, 2) | ||||
|         self.table.setFont(QFont("Consolas", 11)) | ||||
|         self.table.setHorizontalHeaderLabels(["x", "y"]) | ||||
|         self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) | ||||
|         self.table.setSelectionBehavior(QTableWidget.SelectRows) | ||||
|         left_layout.addWidget(self.table) | ||||
| 
 | ||||
|         # --- 数据输入区 --- | ||||
|         input_frame = ttk.LabelFrame(left_frame, text="数据输入", padding=6) | ||||
|         input_frame.grid(row=0, column=0, sticky="ew", pady=(0, 8)) | ||||
|         input_frame.columnconfigure(0, weight=1) | ||||
|         btn_row = QHBoxLayout() | ||||
|         self.add_row_btn = QPushButton("添加数据") | ||||
|         self.add_row_btn.setStyleSheet("color: #333;") | ||||
|         self.add_row_btn.clicked.connect(self.add_point_row) | ||||
|         btn_row.addWidget(self.add_row_btn) | ||||
| 
 | ||||
|         self.excel_btn = ttk.Button(input_frame, text="导入excel文件", command=self.load_excel) | ||||
|         self.excel_btn.grid(row=0, column=0, sticky="ew", padx=2, pady=2) | ||||
|         self.del_row_btn = QPushButton("删除选中行") | ||||
|         self.del_row_btn.setStyleSheet("color: #333;") | ||||
|         self.del_row_btn.clicked.connect(self.delete_selected_rows) | ||||
|         btn_row.addWidget(self.del_row_btn) | ||||
|         left_layout.addLayout(btn_row) | ||||
| 
 | ||||
|         # 滚动区域 | ||||
|         self.scroll_canvas = tk.Canvas(input_frame, height=200) | ||||
|         self.scroll_canvas.grid(row=1, column=0, sticky="ew", pady=4) | ||||
|         self.scrollbar = ttk.Scrollbar(input_frame, orient="vertical", command=self.scroll_canvas.yview) | ||||
|         self.scrollbar.grid(row=1, column=1, sticky="ns") | ||||
|         self.scroll_canvas.configure(yscrollcommand=self.scrollbar.set) | ||||
|         # 导入导出按钮区 | ||||
|         file_btn_row = QHBoxLayout() | ||||
|         self.import_btn = QPushButton("导入Excel文件") | ||||
|         self.import_btn.setStyleSheet("font-weight: bold; color: #333;") | ||||
|         self.import_btn.clicked.connect(self.load_excel) | ||||
|         file_btn_row.addWidget(self.import_btn) | ||||
| 
 | ||||
|         self.manual_frame = ttk.Frame(self.scroll_canvas) | ||||
|         self.manual_frame.bind("<Configure>", lambda e: self.scroll_canvas.configure(scrollregion=self.scroll_canvas.bbox("all"))) | ||||
|         self.scroll_canvas.create_window((0, 0), window=self.manual_frame, anchor="nw") | ||||
|         self.export_btn = QPushButton("导出Excel文件") | ||||
|         self.export_btn.setStyleSheet("font-weight: bold; color: #333;") | ||||
|         self.export_btn.clicked.connect(self.export_excel_and_plot) | ||||
|         file_btn_row.addWidget(self.export_btn) | ||||
|         left_layout.addLayout(file_btn_row) | ||||
| 
 | ||||
|         self.point_rows = [] | ||||
|         self.add_row_btn = ttk.Button(input_frame, text="添加数据", command=self.add_point_row) | ||||
|         self.add_row_btn.grid(row=2, column=0, sticky="ew", padx=2, pady=2) | ||||
|         # 拟合参数区 | ||||
|         param_layout = QHBoxLayout() | ||||
|         param_layout.addWidget(QLabel("多项式阶数:")) | ||||
|         self.order_spin = QSpinBox() | ||||
|         self.order_spin.setRange(1, 10) | ||||
|         self.order_spin.setValue(2) | ||||
|         param_layout.addWidget(self.order_spin) | ||||
|         left_layout.addLayout(param_layout) | ||||
| 
 | ||||
|         # --- 参数区 --- | ||||
|         param_frame = ttk.LabelFrame(left_frame, text="拟合参数", padding=6) | ||||
|         param_frame.grid(row=1, column=0, sticky="ew", pady=(0, 8)) | ||||
|         ttk.Label(param_frame, text="选择多项式阶数:").grid(row=0, column=0, padx=2, pady=2, sticky="e") | ||||
|         self.order_spin = ttk.Spinbox(param_frame, from_=1, to=10, width=5) | ||||
|         self.order_spin.set(2) | ||||
|         self.order_spin.grid(row=0, column=1, padx=2, pady=2, sticky="w") | ||||
|         # 优化复选框和拟合按钮同一行 | ||||
|         self.fit_btn = ttk.Button(param_frame, text="拟合并显示", command=self.fit_and_plot) | ||||
|         self.fit_btn.grid(row=1, column=0, padx=2, pady=4, sticky="ew") | ||||
|         self.optimize_var = tk.BooleanVar(value=True) | ||||
|         self.optimize_check = ttk.Checkbutton(param_frame, text="优化曲线(防止突起)", variable=self.optimize_var) | ||||
|         self.optimize_check.grid(row=1, column=1, padx=2, pady=4, sticky="w") | ||||
|         self.fit_btn = QPushButton("拟合并显示") | ||||
|         self.fit_btn.setStyleSheet("font-weight: bold; color: #333;") | ||||
|         self.fit_btn.clicked.connect(self.fit_and_plot) | ||||
|         left_layout.addWidget(self.fit_btn) | ||||
| 
 | ||||
|         # --- 输出区 --- | ||||
|         output_frame = ttk.LabelFrame(left_frame, text="表达式与代码", padding=6) | ||||
|         output_frame.grid(row=2, column=0, sticky="ew") | ||||
|         self.output = tk.Text(output_frame, height=6, width=40, font=("Consolas", 10)) | ||||
|         self.output.grid(row=0, column=0, columnspan=3, padx=2, pady=2) | ||||
|         ttk.Label(output_frame, text="输出代码格式:").grid(row=1, column=0, padx=2, pady=2, sticky="e") | ||||
|         self.code_type = ttk.Combobox(output_frame, values=["C", "C++", "Python"], width=8) | ||||
|         self.code_type.set("C") | ||||
|         self.code_type.grid(row=1, column=1, padx=2, pady=2, sticky="w") | ||||
|         self.gen_code_btn = ttk.Button(output_frame, text="生成函数代码", command=self.generate_code) | ||||
|         self.gen_code_btn.grid(row=1, column=2, padx=2, pady=2, sticky="ew") | ||||
|         # 输出区 | ||||
|         self.output = QTextEdit() | ||||
|         self.output.setReadOnly(False) | ||||
|         self.output.setFont(QFont("Consolas", 10)) | ||||
|         self.output.setMaximumHeight(150) | ||||
|         left_layout.addWidget(self.output) | ||||
| 
 | ||||
|         # ===== 右侧区 ===== | ||||
|         right_frame = ttk.Frame(main_frame) | ||||
|         # right_frame.grid(row=0, column=1, sticky="nsew")  # 填满剩余空间 | ||||
|         right_frame.grid(row=0, column=1, sticky="nsew", padx=(8, 0)) | ||||
|         right_frame.rowconfigure(0, weight=1) | ||||
|         right_frame.columnconfigure(0, weight=1) | ||||
|         code_layout = QHBoxLayout() | ||||
|         code_layout.addWidget(QLabel("输出代码格式:")) | ||||
|         self.code_type = QComboBox() | ||||
|         self.code_type.addItems(["C", "C++", "Python"]) | ||||
|         code_layout.addWidget(self.code_type) | ||||
|         self.gen_code_btn = QPushButton("生成函数代码") | ||||
|         self.gen_code_btn.setStyleSheet("color: #333;") | ||||
|         self.gen_code_btn.clicked.connect(self.generate_code) | ||||
|         code_layout.addWidget(self.gen_code_btn) | ||||
|         left_layout.addLayout(code_layout) | ||||
| 
 | ||||
|         plot_frame = ttk.LabelFrame(right_frame, text="拟合曲线", padding=6) | ||||
|         plot_frame.grid(row=0, column=0, sticky="nsew") | ||||
|         plot_frame.rowconfigure(0, weight=1) | ||||
|         plot_frame.columnconfigure(0, weight=1) | ||||
|         # 拟合曲线区 | ||||
|         self.figure = Figure(figsize=(5, 4)) | ||||
|         self.canvas = FigureCanvasTkAgg(self.figure, master=plot_frame) | ||||
|         self.canvas.get_tk_widget().pack(fill="both", expand=True) | ||||
|         self.scroll_canvas.bind_all("<MouseWheel>", self._on_mousewheel) | ||||
|         self.canvas = FigureCanvas(self.figure) | ||||
|         right_layout.addWidget(self.canvas) | ||||
| 
 | ||||
| 
 | ||||
|     def _on_mousewheel(self, event): | ||||
|         # Windows下event.delta为120的倍数,负值向下 | ||||
|         self.scroll_canvas.yview_scroll(int(-1*(event.delta/120)), "units") | ||||
|     def center(self): | ||||
|         qr = self.frameGeometry() | ||||
|         cp = QApplication.desktop().availableGeometry().center() | ||||
|         qr.moveCenter(cp) | ||||
|         self.move(qr.topLeft()) | ||||
| 
 | ||||
|     def add_point_row(self, x_val="", y_val=""): | ||||
|         row = {} | ||||
|         idx = len(self.point_rows) | ||||
|         row['x'] = ttk.Entry(self.manual_frame, width=10) | ||||
|         row['x'].insert(0, str(x_val)) | ||||
|         row['y'] = ttk.Entry(self.manual_frame, width=10) | ||||
|         row['y'].insert(0, str(y_val)) | ||||
|         row['del'] = ttk.Button(self.manual_frame, text="删除", width=5, command=lambda r=idx: self.delete_point_row(r)) | ||||
|         row['x'].grid(row=idx, column=0, padx=1, pady=1) | ||||
|         row['y'].grid(row=idx, column=1, padx=1, pady=1) | ||||
|         row['del'].grid(row=idx, column=2, padx=1, pady=1) | ||||
|         self.point_rows.append(row) | ||||
|         self.refresh_point_rows() | ||||
|         row = self.table.rowCount() | ||||
|         self.table.insertRow(row) | ||||
|         self.table.setItem(row, 0, QTableWidgetItem(str(x_val))) | ||||
|         self.table.setItem(row, 1, QTableWidgetItem(str(y_val))) | ||||
| 
 | ||||
|     def delete_point_row(self, idx): | ||||
|         for widget in self.point_rows[idx].values(): | ||||
|             widget.grid_forget() | ||||
|             widget.destroy() | ||||
|         self.point_rows.pop(idx) | ||||
|         self.refresh_point_rows() | ||||
| 
 | ||||
|     def refresh_point_rows(self): | ||||
|         for i, row in enumerate(self.point_rows): | ||||
|             row['x'].grid(row=i, column=0, padx=1, pady=1) | ||||
|             row['y'].grid(row=i, column=1, padx=1, pady=1) | ||||
|             row['del'].config(command=lambda r=i: self.delete_point_row(r)) | ||||
|             row['del'].grid(row=i, column=2, padx=1, pady=1) | ||||
|     def delete_selected_rows(self): | ||||
|         selected = self.table.selectionModel().selectedRows() | ||||
|         for idx in sorted(selected, reverse=True): | ||||
|             self.table.removeRow(idx.row()) | ||||
| 
 | ||||
|     def load_excel(self): | ||||
|         file = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx *.xls")]) | ||||
|         file, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls)") | ||||
|         if file: | ||||
|             try: | ||||
|                 data = pd.read_excel(file, usecols=[0, 1]) | ||||
|                 new_x = data.iloc[:, 0].values.tolist() | ||||
|                 new_y = data.iloc[:, 1].values.tolist() | ||||
|                 messagebox.showinfo("成功", "数据导入成功!") | ||||
|                 for x, y in zip(new_x, new_y): | ||||
|                     self.add_point_row(x, y) | ||||
|                 QMessageBox.information(self, "成功", "数据导入成功!") | ||||
|             except Exception as e: | ||||
|                 messagebox.showerror("错误", f"读取Excel失败: {e}") | ||||
|                 QMessageBox.critical(self, "错误", f"读取Excel失败: {e}") | ||||
| 
 | ||||
|     def export_excel_and_plot(self): | ||||
|         file, _ = QFileDialog.getSaveFileName(self, "导出Excel文件", "", "Excel Files (*.xlsx *.xls)") | ||||
|         if file: | ||||
|             x_list, y_list = [], [] | ||||
|             for row in range(self.table.rowCount()): | ||||
|                 try: | ||||
|                     x = float(self.table.item(row, 0).text()) | ||||
|                     y = float(self.table.item(row, 1).text()) | ||||
|                     x_list.append(x) | ||||
|                     y_list.append(y) | ||||
|                 except Exception: | ||||
|                     continue | ||||
|             if not x_list or not y_list: | ||||
|                 QMessageBox.warning(self, "导出失败", "没有可导出的数据!") | ||||
|                 return | ||||
|             df = pd.DataFrame({'x': x_list, 'y': y_list}) | ||||
|             try: | ||||
|                 df.to_excel(file, index=False) | ||||
|                 # 导出同名png图像 | ||||
|                 png_file = file | ||||
|                 if png_file.lower().endswith('.xlsx') or png_file.lower().endswith('.xls'): | ||||
|                     png_file = png_file.rsplit('.', 1)[0] + '.png' | ||||
|                 else: | ||||
|                     png_file = png_file + '.png' | ||||
|                 self.figure.savefig(png_file, dpi=150, bbox_inches='tight') | ||||
|                 QMessageBox.information(self, "导出成功", f"数据已成功导出到Excel文件!\n图像已导出为:{png_file}") | ||||
|             except Exception as e: | ||||
|                 QMessageBox.critical(self, "导出错误", f"导出Excel或图像失败: {e}") | ||||
| 
 | ||||
|     def get_manual_points(self): | ||||
|         x_list, y_list = [], [] | ||||
|         for row in self.point_rows: | ||||
|         for row in range(self.table.rowCount()): | ||||
|             try: | ||||
|                 x = float(row['x'].get()) | ||||
|                 y = float(row['y'].get()) | ||||
|                 x = float(self.table.item(row, 0).text()) | ||||
|                 y = float(self.table.item(row, 1).text()) | ||||
|                 x_list.append(x) | ||||
|                 y_list.append(y) | ||||
|             except ValueError: | ||||
|             except Exception: | ||||
|                 continue | ||||
|         return x_list, y_list | ||||
| 
 | ||||
| 
 | ||||
|     def fit_and_plot(self): | ||||
|         # 始终以手动输入区为准 | ||||
|         matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] | ||||
|         matplotlib.rcParams['axes.unicode_minus'] = False | ||||
|         matplotlib.rcParams['font.size'] = 14 | ||||
|         self.data_x, self.data_y = self.get_manual_points() | ||||
|         try: | ||||
|             order = int(self.order_spin.get()) | ||||
|             order = int(self.order_spin.value()) | ||||
|         except ValueError: | ||||
|             messagebox.showwarning("输入错误", "阶数必须为整数!") | ||||
|             QMessageBox.warning(self, "输入错误", "阶数必须为整数!") | ||||
|             return | ||||
|         n_points = len(self.data_x) | ||||
|         if n_points < order + 1: | ||||
|             messagebox.showwarning("数据不足", "数据点数量不足以拟合该阶多项式!") | ||||
|             QMessageBox.warning(self, "数据不足", "数据点数量不足以拟合该阶多项式!") | ||||
|             return | ||||
| 
 | ||||
|         # 阶数过高判断,只提示不强制修改 | ||||
|         max_order = max(2, min(6, n_points // 3)) | ||||
|         if order > max_order: | ||||
|             messagebox.showwarning("阶数过高", f"当前数据点数为{n_points},建议阶数不超过{max_order},否则容易出现异常突起!") | ||||
| 
 | ||||
|         x = np.array(self.data_x, dtype=np.float64) | ||||
|         y = np.array(self.data_y, dtype=np.float64) | ||||
| 
 | ||||
|         # ----------- 新增归一化 ----------- | ||||
|         x_min, x_max = x.min(), x.max() | ||||
|         if x_max - x_min == 0: | ||||
|             messagebox.showwarning("数据错误", "所有x值都相同,无法拟合!") | ||||
|             QMessageBox.warning(self, "数据错误", "所有x值都相同,无法拟合!") | ||||
|             return | ||||
|         x_norm = (x - x_min) / (x_max - x_min) | ||||
|         # --------------------------------- | ||||
| 
 | ||||
|         try: | ||||
|             if self.optimize_var.get(): | ||||
|                 # 优化:加大rcond,减少高阶影响 | ||||
|                 coeffs = np.polyfit(x_norm, y, order, rcond=1e-3) | ||||
|             else: | ||||
|                 coeffs = np.polyfit(x_norm, y, order) | ||||
|             coeffs = np.polyfit(x, y, order) | ||||
|         except Exception as e: | ||||
|             messagebox.showerror("拟合错误", f"多项式拟合失败:{e}") | ||||
|             QMessageBox.critical(self, "拟合错误", f"多项式拟合失败:{e}") | ||||
|             return | ||||
|         poly = np.poly1d(coeffs) | ||||
|         expr = "y = " + " + ".join([f"{c:.6g}*x_norm^{order-i}" for i, c in enumerate(coeffs)]) | ||||
|         self.output.delete(1.0, tk.END) | ||||
|         self.output.insert(tk.END, f"归一化x: x_norm=(x-{x_min:.6g})/({x_max:.6g}-{x_min:.6g})\n") | ||||
|         self.output.insert(tk.END, expr + "\n") | ||||
|         # 绘图 | ||||
|         expr = "y = " + " + ".join([f"{c:.6g}*x^{order-i}" for i, c in enumerate(coeffs)]) | ||||
|         self.output.setPlainText(f"{expr}\n") | ||||
|         self.figure.clear() | ||||
|         ax = self.figure.add_subplot(111) | ||||
|         ax.scatter(x, y, color='red', label='数据点') | ||||
|         x_fit = np.linspace(x_min, x_max, 200) | ||||
|         x_fit_norm = (x_fit - x_min) / (x_max - x_min) | ||||
|         y_fit = poly(x_fit_norm) | ||||
|         y_fit = poly(x_fit) | ||||
|         ax.plot(x_fit, y_fit, label='拟合曲线') | ||||
|         ax.legend() | ||||
|         self.canvas.draw() | ||||
| @ -209,19 +220,17 @@ class PolyFitApp: | ||||
| 
 | ||||
|     def generate_code(self): | ||||
|         if self.last_coeffs is None: | ||||
|             messagebox.showwarning("未拟合", "请先拟合数据!") | ||||
|             QMessageBox.warning(self, "未拟合", "请先拟合数据!") | ||||
|             return | ||||
|         coeffs = self.last_coeffs | ||||
|         order = len(coeffs) - 1 | ||||
|         code_type = self.code_type.get() | ||||
|         code_type = self.code_type.currentText() | ||||
|         if code_type == "C": | ||||
|             code = self.create_c_function(coeffs) | ||||
|         elif code_type == "C++": | ||||
|             code = self.create_cpp_function(coeffs) | ||||
|         else: | ||||
|             code = self.create_py_function(coeffs) | ||||
|         self.output.delete(1.0, tk.END) | ||||
|         self.output.insert(tk.END, code) | ||||
|         self.output.setPlainText(code) | ||||
| 
 | ||||
|     def create_c_function(self, coeffs): | ||||
|         lines = ["#include <math.h>", "double polynomial(double x) {", "    return "] | ||||
| @ -271,6 +280,7 @@ class PolyFitApp: | ||||
|         return "\n".join(lines) | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     root = tk.Tk() | ||||
|     app = PolyFitApp(root) | ||||
|     root.mainloop() | ||||
|     app = QApplication(sys.argv) | ||||
|     win = PolyFitApp() | ||||
|     win.show() | ||||
|     sys.exit(app.exec_()) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 RB
						RB