mirror of
https://github.com/goldenfishs/MRobot.git
synced 2025-06-14 22:16:38 +08:00
Compare commits
3 Commits
c4731883f2
...
79da21bca0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
79da21bca0 | ||
![]() |
b879e0ae94 | ||
![]() |
214ac00e90 |
266
MR_Tool.py
266
MR_Tool.py
@ -18,6 +18,18 @@ import matplotlib
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView # 新增
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtCore import QThread
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
|
||||
from PyQt5.QtWidgets import QFileDialog
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEnginePage
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
|
||||
from PyQt5.QtWidgets import QSplashScreen
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtGui import QPixmap
|
||||
|
||||
|
||||
def resource_path(relative_path):
|
||||
"""兼容PyInstaller打包后资源路径"""
|
||||
@ -1092,7 +1104,7 @@ class SerialAssistant(QWidget):
|
||||
|
||||
def send_data(self):
|
||||
if self.ser and self.ser.is_open:
|
||||
data = self.send_edit.text()
|
||||
data = self.send_edit.toPlainText()
|
||||
try:
|
||||
if self.hex_send_chk.isChecked():
|
||||
# 支持 0x11 0x22 33 44 格式
|
||||
@ -1920,6 +1932,179 @@ class GenerateMRobotCode(QWidget):
|
||||
except Exception as e:
|
||||
self.log(f"生成 init.c 文件时出错: {e}")
|
||||
|
||||
# --------- 功能五:零件库 ---------
|
||||
|
||||
class CustomWebView(QWebEngineView):
|
||||
def __init__(self, parent=None, popup_list=None):
|
||||
super().__init__(parent)
|
||||
self.popup_list = popup_list
|
||||
self._progress_dialog = None
|
||||
self.page().profile().downloadRequested.connect(self.handle_download)
|
||||
self.setStyleSheet("""
|
||||
QWebEngineView {
|
||||
border-radius: 12px;
|
||||
background: #f8fbfd;
|
||||
border: 1px solid #d6eaf8;
|
||||
}
|
||||
""")
|
||||
|
||||
def handle_download(self, download_item):
|
||||
from PyQt5.QtWidgets import QFileDialog, QProgressDialog
|
||||
|
||||
# 防止重复弹窗
|
||||
if hasattr(download_item, "_handled") and download_item._handled:
|
||||
return
|
||||
download_item._handled = True
|
||||
|
||||
suggested = download_item.suggestedFileName()
|
||||
path, _ = QFileDialog.getSaveFileName(self, "保存文件", suggested)
|
||||
if not path:
|
||||
download_item.cancel()
|
||||
return
|
||||
|
||||
download_item.setPath(path)
|
||||
download_item.accept()
|
||||
|
||||
# 创建进度对话框
|
||||
self._progress_dialog = QProgressDialog(f"正在下载: {suggested}", "取消", 0, 100, self)
|
||||
self._progress_dialog.setWindowTitle("下载进度")
|
||||
self._progress_dialog.setWindowModality(Qt.WindowModal)
|
||||
self._progress_dialog.setMinimumDuration(0)
|
||||
self._progress_dialog.setValue(0)
|
||||
self._progress_dialog.canceled.connect(download_item.cancel)
|
||||
self._progress_dialog.show()
|
||||
|
||||
def on_progress(received, total):
|
||||
if total > 0:
|
||||
percent = int(received * 100 / total)
|
||||
self._progress_dialog.setValue(percent)
|
||||
else:
|
||||
self._progress_dialog.setValue(0)
|
||||
|
||||
download_item.downloadProgress.connect(on_progress)
|
||||
|
||||
def on_finished():
|
||||
self._progress_dialog.setValue(100)
|
||||
self._progress_dialog.close()
|
||||
if self.parent() and isinstance(self.parent(), CustomWebView):
|
||||
self.parent().close()
|
||||
elif self.popup_list and self in self.popup_list:
|
||||
self.close()
|
||||
self.popup_list.remove(self)
|
||||
|
||||
download_item.finished.connect(on_finished)
|
||||
|
||||
def createWindow(self, _type):
|
||||
popup = CustomWebView(popup_list=self.popup_list)
|
||||
popup.setAttribute(Qt.WA_DeleteOnClose)
|
||||
popup.setWindowTitle("下载")
|
||||
popup.resize(900, 600)
|
||||
popup.show()
|
||||
if self.popup_list is not None:
|
||||
self.popup_list.append(popup)
|
||||
return popup
|
||||
|
||||
class MachineryLibrary(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.popup_windows = []
|
||||
self.setFont(QFont("微软雅黑", 15))
|
||||
self.setStyleSheet("""
|
||||
QWidget {
|
||||
background: #f8fbfd;
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
""")
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(18)
|
||||
main_layout.setContentsMargins(32, 32, 32, 32)
|
||||
|
||||
# 标题区
|
||||
title = QLabel("MRobot 零件库")
|
||||
title.setFont(QFont("微软雅黑", 22, QFont.Bold))
|
||||
title.setAlignment(Qt.AlignCenter)
|
||||
title.setStyleSheet("color: #2980b9; letter-spacing: 2px; margin-bottom: 2px;")
|
||||
main_layout.addWidget(title)
|
||||
|
||||
desc = QLabel("零件库账号:Engineer(无密码)")
|
||||
desc.setFont(QFont("微软雅黑", 13))
|
||||
desc.setAlignment(Qt.AlignCenter)
|
||||
desc.setStyleSheet("color: #34495e; margin-bottom: 8px;")
|
||||
main_layout.addWidget(desc)
|
||||
|
||||
# 加载提示
|
||||
self.loading_label = QLabel("正在加载零件库网页,请稍候...")
|
||||
self.loading_label.setAlignment(Qt.AlignCenter)
|
||||
self.loading_label.setFont(QFont("微软雅黑", 14))
|
||||
self.loading_label.setStyleSheet("color: #888; margin-bottom: 8px;")
|
||||
main_layout.addWidget(self.loading_label)
|
||||
|
||||
# 网页视图
|
||||
self.webview = CustomWebView(parent=self, popup_list=self.popup_windows)
|
||||
self.webview.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||
self.webview.setMinimumHeight(480)
|
||||
self.webview.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
self.webview.loadFinished.connect(self.on_webview_loaded)
|
||||
main_layout.addWidget(self.webview, stretch=10)
|
||||
|
||||
# 刷新按钮
|
||||
btn_row = QHBoxLayout()
|
||||
btn_row.addStretch(1)
|
||||
self.refresh_btn = QPushButton("刷新零件库")
|
||||
self.refresh_btn.setFont(QFont("微软雅黑", 13, QFont.Bold))
|
||||
self.refresh_btn.setFixedWidth(140)
|
||||
self.refresh_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
|
||||
stop:0 #eaf6fb, stop:1 #d6eaf8);
|
||||
color: #2980b9;
|
||||
border-radius: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding: 8px 0;
|
||||
border: 1.5px solid #d6eaf8;
|
||||
}
|
||||
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;
|
||||
}
|
||||
""")
|
||||
self.refresh_btn.clicked.connect(self.reload_webview)
|
||||
btn_row.addWidget(self.refresh_btn)
|
||||
btn_row.addStretch(1)
|
||||
main_layout.addLayout(btn_row)
|
||||
|
||||
# 自动加载网页
|
||||
QTimer.singleShot(200, lambda: self.webview.setUrl(QUrl("http://alist.qutrobot.top")))
|
||||
self.webview.show()
|
||||
|
||||
# 定时刷新(可选,防止页面假死)
|
||||
self.refresh_timer = QTimer(self)
|
||||
self.refresh_timer.setInterval(100)
|
||||
self.refresh_timer.timeout.connect(self.webview.update)
|
||||
self.refresh_timer.start()
|
||||
|
||||
def reload_webview(self):
|
||||
self.loading_label.show()
|
||||
self.webview.setUrl(QUrl("http://alist.qutrobot.top"))
|
||||
|
||||
def on_webview_loaded(self):
|
||||
self.loading_label.hide()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.refresh_timer.stop()
|
||||
super().closeEvent(event)
|
||||
# --------- 主工具箱UI ---------
|
||||
class ToolboxUI(QWidget):
|
||||
def __init__(self):
|
||||
@ -1977,7 +2162,7 @@ class ToolboxUI(QWidget):
|
||||
left_layout.addWidget(logo_label)
|
||||
|
||||
# 按钮区
|
||||
self.button_names = ["主页", "曲线拟合", "Mini串口助手(BUG)", "MR架构配置(开发中)","软件指南"]
|
||||
self.button_names = ["主页", "曲线拟合", "Mini串口助手", "MR架构配置", "零件库", "软件指南"]
|
||||
self.buttons = []
|
||||
for idx, name in enumerate(self.button_names):
|
||||
btn = QPushButton(name)
|
||||
@ -2050,7 +2235,8 @@ class ToolboxUI(QWidget):
|
||||
1: PolyFitApp(), # 多项式拟合
|
||||
2: SerialAssistant(), # 串口助手
|
||||
3: GenerateMRobotCode(), # MRobot架构生成
|
||||
4: DownloadPage(), # 下载页面
|
||||
4: MachineryLibrary(), # 零件库
|
||||
5: DownloadPage(), # 下载页面
|
||||
}
|
||||
for i in range(len(self.button_names)):
|
||||
self.stack.addWidget(self.page_widgets[i])
|
||||
@ -2077,7 +2263,77 @@ class ToolboxUI(QWidget):
|
||||
self.output_box.append(f"已切换到功能:{self.button_names[idx]}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
from PyQt5.QtWidgets import QSplashScreen, QGraphicsDropShadowEffect
|
||||
from PyQt5.QtCore import Qt, QTimer, QRect
|
||||
from PyQt5.QtGui import QPixmap, QPainter, QColor, QFont, QLinearGradient, QBrush
|
||||
|
||||
class CustomSplash(QSplashScreen):
|
||||
def __init__(self, pixmap):
|
||||
super().__init__(QPixmap(640, 400))
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
self.logo = pixmap.scaled(360, 240, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
self.title = "MRobot 工具箱"
|
||||
self.subtitle = "欢迎使用 MRobot,正在启动中..."
|
||||
self.title_color = QColor("#2471a3")
|
||||
self.subtitle_color = QColor("#2980b9")
|
||||
self.bg_gradient = QLinearGradient(0, 0, 0, 400)
|
||||
self.bg_gradient.setColorAt(0, QColor("#f8fbfd"))
|
||||
self.bg_gradient.setColorAt(1, QColor("#eaf6fb"))
|
||||
self.border_color = QColor("#2980b9")
|
||||
self.setFixedSize(640, 400)
|
||||
# 阴影
|
||||
effect = QGraphicsDropShadowEffect(self)
|
||||
effect.setBlurRadius(36)
|
||||
effect.setOffset(0, 10)
|
||||
effect.setColor(QColor(80, 120, 180, 80))
|
||||
self.setGraphicsEffect(effect)
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
# 渐变背景
|
||||
painter.setBrush(QBrush(self.bg_gradient))
|
||||
painter.setPen(Qt.NoPen)
|
||||
painter.drawRoundedRect(0, 0, self.width(), self.height(), 44, 44)
|
||||
# 边框
|
||||
pen = painter.pen()
|
||||
pen.setColor(self.border_color)
|
||||
pen.setWidth(3)
|
||||
painter.setPen(pen)
|
||||
painter.drawRoundedRect(2, 2, self.width()-4, self.height()-4, 44, 44)
|
||||
# LOGO
|
||||
logo_x = (self.width() - self.logo.width()) // 2
|
||||
logo_y = 80
|
||||
painter.drawPixmap(logo_x, logo_y, self.logo)
|
||||
# 主标题
|
||||
# painter.setFont(QFont("微软雅黑", 24, QFont.Bold))
|
||||
# painter.setPen(self.title_color)
|
||||
# painter.drawText(QRect(0, 200, self.width(), 48), Qt.AlignCenter, self.title)
|
||||
# 副标题
|
||||
painter.setFont(QFont("微软雅黑", 12))
|
||||
painter.setPen(self.subtitle_color)
|
||||
painter.drawText(QRect(0, 250, self.width(), 36), Qt.AlignCenter, self.subtitle)
|
||||
# 版权
|
||||
painter.setFont(QFont("微软雅黑", 10))
|
||||
painter.setPen(QColor("#b2bec3"))
|
||||
painter.drawText(QRect(0, 360, self.width(), 30), Qt.AlignCenter, "© 2025 MRobot. All rights reserved.")
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
win = ToolboxUI()
|
||||
win.show()
|
||||
|
||||
# 立即显示Splash
|
||||
logo_pix = QPixmap(resource_path("mr_tool_img/MRobot.png"))
|
||||
splash = CustomSplash(logo_pix)
|
||||
splash.show()
|
||||
app.processEvents() # 强制立即刷新Splash
|
||||
|
||||
# 异步加载主窗口
|
||||
def load_main():
|
||||
win = ToolboxUI()
|
||||
splash.finish(win)
|
||||
win.show()
|
||||
|
||||
QTimer.singleShot(100, load_main)
|
||||
|
||||
sys.exit(app.exec_())
|
1
MRobot_repo
Submodule
1
MRobot_repo
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c4731883f241d4748d45ed168520a345a042326e
|
@ -88,4 +88,6 @@
|
||||
|
||||
```bash
|
||||
pyinstaller --onefile --windowed
|
||||
pyinstaller MR_Toolbox.py --onefile --noconsole --icon=img\M.ico --add-data "mr_tool_img\MRobot.png;mr_tool_img"
|
||||
pyinstaller MR_Toolbox.py --onefile --noconsole --icon=img\M.ico --add-data "mr_tool_img\MRobot.png;mr_tool_img"
|
||||
|
||||
pyinstaller MR_Tool.py --onefile --noconsole --icon=img\M.ico --add-data "mr_tool_img\MRobot.png;mr_tool_img" --add-data "src;src" --add-data "User;User"
|
131
src/freertos.c
Normal file
131
src/freertos.c
Normal file
@ -0,0 +1,131 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : freertos.c
|
||||
* Description : Code for freertos applications
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "main.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "task/user_task.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Variables */
|
||||
osThreadId_t initTaskHandle; // 定义 Task_Init 的任务句柄
|
||||
/* USER CODE END Variables */
|
||||
/* Definitions for defaultTask */
|
||||
osThreadId_t defaultTaskHandle;
|
||||
const osThreadAttr_t defaultTask_attributes = {
|
||||
.name = "defaultTask",
|
||||
.stack_size = 128 * 4,
|
||||
.priority = (osPriority_t) osPriorityNormal,
|
||||
};
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN FunctionPrototypes */
|
||||
|
||||
/* USER CODE END FunctionPrototypes */
|
||||
|
||||
void StartDefaultTask(void *argument);
|
||||
|
||||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||||
|
||||
/**
|
||||
* @brief FreeRTOS initialization
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void MX_FREERTOS_Init(void) {
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* USER CODE BEGIN RTOS_MUTEX */
|
||||
/* add mutexes, ... */
|
||||
/* USER CODE END RTOS_MUTEX */
|
||||
|
||||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||||
/* add semaphores, ... */
|
||||
/* USER CODE END RTOS_SEMAPHORES */
|
||||
|
||||
/* USER CODE BEGIN RTOS_TIMERS */
|
||||
/* start timers, add new ones, ... */
|
||||
/* USER CODE END RTOS_TIMERS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_QUEUES */
|
||||
/* add queues, ... */
|
||||
/* USER CODE END RTOS_QUEUES */
|
||||
|
||||
/* Create the thread(s) */
|
||||
/* creation of defaultTask */
|
||||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_THREADS */
|
||||
initTaskHandle = osThreadNew(Task_Init, NULL, &attr_init); // 创建初始化任务
|
||||
/* add threads, ... */
|
||||
/* USER CODE END RTOS_THREADS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_EVENTS */
|
||||
/* add events, ... */
|
||||
/* USER CODE END RTOS_EVENTS */
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||||
/**
|
||||
* @brief Function implementing the defaultTask thread.
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_StartDefaultTask */
|
||||
void StartDefaultTask(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN StartDefaultTask */
|
||||
/* Infinite loop */
|
||||
// for(;;)
|
||||
// {
|
||||
// osDelay(1);
|
||||
// }
|
||||
osThreadTerminate(osThreadGetId()); // 结束自身
|
||||
/* USER CODE END StartDefaultTask */
|
||||
}
|
||||
|
||||
/* Private application code --------------------------------------------------*/
|
||||
/* USER CODE BEGIN Application */
|
||||
|
||||
/* USER CODE END Application */
|
||||
|
Loading…
Reference in New Issue
Block a user