当前位置: 首页 > news >正文

基于 PyQt5 实现刀具类型选择界面的设计与交互逻辑

在工业软件或数控系统的人机交互设计中,用户需要从多种刀具中选择合适的加工工具。这类界面通常要求直观、美观且具备良好的反馈机制。本文将详细阐述如何使用 Python 的 PyQt5 库从零构建一个“刀具类型选择”界面,不仅实现视觉上的布局还原,更深入探讨其背后的设计思想、事件处理机制以及可扩展性结构。

我们将逐步构建一个完整的应用程序,该程序不依赖外部图片资源,通过代码生成占位图像来模拟真实刀具图标,并允许用户点击按钮进行选择。整个过程注重代码的独立性与可运行性,每个代码块均可单独保存为 .py 文件并直接执行。


界面结构分析与设计思路

目标界面包含以下几个核心元素:顶部标题、中间的刀具选择区域(3行2列网格布局)、底部操作按钮(关闭和帮助)。从功能角度看,这是一个典型的模态选择对话框,用户在做出选择后应获得明确反馈。
在这里插入图片描述

在 PyQt5 中,我们可以利用 QWidget 作为主窗口容器,使用 QVBoxLayout 控制垂直方向的布局层次,QGridLayout 管理刀具按钮的二维排列。每个刀具按钮由图像和文字标签组成,因此需要嵌套布局结构。为了增强用户体验,我们还加入了悬停效果和点击响应。


第一版:无依赖图像的完整可运行界面

以下代码实现了完整的刀具选择窗口,所有图像均为程序内生成,无需任何外部文件:
在这里插入图片描述

# tool_selector_v1.py
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,QGridLayout, QPushButton, QLabel, QMessageBox
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPainter, QColor, QFontclass ToolSelectionWindow(QWidget):def __init__(self):super().__init__()self.setWindowTitle("选择刀具类型")self.setGeometry(300, 100, 600, 400)self.selected_tool = Nonemain_layout = QVBoxLayout()# 标题title_label = QLabel("选择刀具类型")title_label.setAlignment(Qt.AlignCenter)title_label.setFont(self.create_font(16, bold=True))main_layout.addWidget(title_label)# 网格布局grid_layout = QGridLayout()grid_layout.setSpacing(20)tools = [("铣刀", "#4A90E2"),("钻头 / 阶梯钻", "#50C878"),("成型铣刀", "#D35400"),("旋转锉", "#9B59B6")]for i, (tool_name, color) in enumerate(tools):btn = self.create_tool_button(tool_name, color)row, col = i // 2, i % 2grid_layout.addWidget(btn, row, col)main_layout.addLayout(grid_layout)# 底部按钮bottom_layout = QHBoxLayout()help_btn = QPushButton("?")help_btn.setFixedSize(40, 40)help_btn.setFont(self.create_font(14))help_btn.setStyleSheet("border-radius: 20px; background-color: #f0f0f0;")help_btn.clicked.connect(self.show_help)close_btn = QPushButton("关闭")close_btn.setFixedHeight(40)close_btn.setStyleSheet("padding: 10px;")close_btn.clicked.connect(self.close)bottom_layout.addStretch()bottom_layout.addWidget(help_btn)bottom_layout.addWidget(close_btn)main_layout.addLayout(bottom_layout)self.setLayout(main_layout)def create_font(self, size, bold=False):font = QFont()font.setPointSize(size)font.setBold(bold)return fontdef create_placeholder_image(self, width, height, color, label=""):pixmap = QPixmap(width, height)pixmap.fill(Qt.transparent)painter = QPainter(pixmap)painter.setRenderHint(QPainter.Antialiasing)painter.setBrush(QColor(color))painter.setPen(Qt.NoPen)painter.drawRoundedRect(0, 0, width, height, 10, 10)painter.setPen(Qt.white)painter.setFont(self.create_font(10, bold=True))painter.drawText(pixmap.rect(), Qt.AlignCenter, label)painter.end()return pixmapdef create_tool_button(self, tool_name, color):btn = QPushButton()btn.setFixedSize(200, 120)btn.setStyleSheet("""QPushButton {border: 1px solid #ccc;border-radius: 10px;background-color: white;padding: 5px;}QPushButton:hover {background-color: #f9f9f9;border-color: #aaa;}""")layout = QVBoxLayout()layout.setSpacing(5)img_label = QLabel()pixmap = self.create_placeholder_image(180, 80, color, tool_name.split()[0])img_label.setPixmap(pixmap)img_label.setAlignment(Qt.AlignCenter)layout.addWidget(img_label)text_label = QLabel(tool_name)text_label.setAlignment(Qt.AlignCenter)text_label.setFont(self.create_font(10))layout.addWidget(text_label)btn.setLayout(layout)btn.clicked.connect(lambda: self.on_tool_selected(tool_name))return btndef on_tool_selected(self, tool_name):self.selected_tool = tool_nameQMessageBox.information(self, "已选择", f"你选择了:{tool_name}")def show_help(self):QMessageBox.information(self, "帮助", "请点击任一刀具类型进行选择。\n选择后将进入下一步设置。")if __name__ == "__main__":app = QApplication(sys.argv)window = ToolSelectionWindow()window.show()sys.exit(app.exec_())

此版本展示了如何在没有图像资源的情况下,通过 QPainter 动态绘制带有颜色和文字的占位图。这种方法特别适用于原型开发或资源受限环境。每个按钮的颜色编码有助于用户快速识别不同类别,符合认知心理学中的“色彩语义”原则。


第二版:引入信号机制以实现模块化通信

在大型应用中,UI 组件应当尽可能解耦。上一版本中,选择结果直接通过 QMessageBox 显示,不利于与其他模块集成。我们可以通过自定义信号实现更优雅的通信方式。
在这里插入图片描述

# tool_selector_v2.py
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,QGridLayout, QPushButton, QLabel
)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QPixmap, QPainter, QColor, QFontclass ToolSelectionDialog(QWidget):tool_chosen = pyqtSignal(str)  # 定义信号,携带字符串参数cancelled = pyqtSignal()       # 取消信号def __init__(self):super().__init__()self.setWindowTitle("选择刀具类型")self.setGeometry(300, 100, 600, 400)main_layout = QVBoxLayout()title_label = QLabel("选择刀具类型")title_label.setAlignment(Qt.AlignCenter)title_label.setFont(self.create_font(16, bold=True))main_layout.addWidget(title_label)grid_layout = QGridLayout()grid_layout.setSpacing(20)tools = [("铣刀", "#4A90E2"),("钻头 / 阶梯钻", "#50C878"),("成型铣刀", "#D35400"),("旋转锉", "#9B59B6")]for i, (tool_name, color) in enumerate(tools):btn = self.create_tool_button(tool_name, color)row, col = i // 2, i % 2grid_layout.addWidget(btn, row, col)main_layout.addLayout(grid_layout)bottom_layout = QHBoxLayout()help_btn = QPushButton("?")help_btn.setFixedSize(40, 40)help_btn.setFont(self.create_font(14))help_btn.setStyleSheet("border-radius: 20px; background-color: #f0f0f0;")help_btn.clicked.connect(self.show_help)close_btn = QPushButton("关闭")close_btn.setFixedHeight(40)close_btn.setStyleSheet("padding: 10px;")close_btn.clicked.connect(self.on_cancel)bottom_layout.addStretch()bottom_layout.addWidget(help_btn)bottom_layout.addWidget(close_btn)main_layout.addLayout(bottom_layout)self.setLayout(main_layout)def create_font(self, size, bold=False):font = QFont()font.setPointSize(size)font.setBold(bold)return fontdef create_placeholder_image(self, width, height, color, label=""):pixmap = QPixmap(width, height)pixmap.fill(Qt.transparent)painter = QPainter(pixmap)painter.setRenderHint(QPainter.Antialiasing)painter.setBrush(QColor(color))painter.setPen(Qt.NoPen)painter.drawRoundedRect(0, 0, width, height, 10, 10)painter.setPen(Qt.white)painter.setFont(self.create_font(10, bold=True))painter.drawText(pixmap.rect(), Qt.AlignCenter, label)painter.end()return pixmapdef create_tool_button(self, tool_name, color):btn = QPushButton()btn.setFixedSize(200, 120)btn.setStyleSheet("""QPushButton {border: 1px solid #ccc;border-radius: 10px;background-color: white;padding: 5px;}QPushButton:hover {background-color: #f9f9f9;border-color: #aaa;}""")layout = QVBoxLayout()layout.setSpacing(5)img_label = QLabel()pixmap = self.create_placeholder_image(180, 80, color, tool_name.split()[0])img_label.setPixmap(pixmap)img_label.setAlignment(Qt.AlignCenter)layout.addWidget(img_label)text_label = QLabel(tool_name)text_label.setAlignment(Qt.AlignCenter)text_label.setFont(self.create_font(10))layout.addWidget(text_label)btn.setLayout(layout)btn.clicked.connect(lambda: self.on_tool_selected(tool_name))return btndef on_tool_selected(self, tool_name):self.tool_chosen.emit(tool_name)self.close()def on_cancel(self):self.cancelled.emit()self.close()def show_help(self):from PyQt5.QtWidgets import QMessageBoxQMessageBox.information(self, "帮助", "请选择一种刀具类型进行下一步操作。")if __name__ == "__main__":app = QApplication(sys.argv)dialog = ToolSelectionDialog()def handle_choice(tool):print(f"主程序接收到选择:{tool}")def handle_cancel():print("用户取消了选择")dialog.tool_chosen.connect(handle_choice)dialog.cancelled.connect(handle_cancel)dialog.show()sys.exit(app.exec_())

在此版本中,我们引入了 pyqtSignal 机制,使得 UI 组件可以通知外部模块其状态变化。这种设计遵循了观察者模式(Observer Pattern),是构建可维护 GUI 应用的关键技术之一。当用户选择某个刀具时,tool_chosen 信号被触发,主程序通过连接该信号来执行后续逻辑。


第三版:数学建模辅助刀具选择逻辑

在实际应用中,刀具选择可能并非完全由用户决定,而是基于加工参数自动推荐。我们可以引入简单的数学模型来辅助决策。

假设刀具选择依赖于两个参数:材料硬度 HHH 和加工深度 ddd。定义一个评分函数 SiS_iSi 来评估第 iii 种刀具的适用性:

Si=w1⋅11+e−k(H−H0i)+w2⋅(1−ddmax,i) S_i = w_1 \cdot \frac{1}{1 + e^{-k(H - H_{0i})}} + w_2 \cdot \left(1 - \frac{d}{d_{\text{max},i}}\right) Si=w11+ek(HH0i)1+w2(1dmax,id)

其中:

  • H0iH_{0i}H0i 是刀具 iii 的推荐硬度阈值,
  • dmax,id_{\text{max},i}dmax,i 是最大加工深度,
  • w1,w2w_1, w_2w1,w2 是权重,
  • kkk 控制硬度响应曲线的陡峭程度。

我们可以基于此模型自动高亮推荐刀具:
在这里插入图片描述

# tool_selector_v3.py
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,QGridLayout, QPushButton, QLabel, QInputDialog
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPainter, QColor, QFont
import mathclass SmartToolSelector(QWidget):def __init__(self):super().__init__()self.setWindowTitle("智能刀具选择")self.setGeometry(300, 100, 600, 450)main_layout = QVBoxLayout()title_label = QLabel("智能刀具选择")title_label.setAlignment(Qt.AlignCenter)title_label.setFont(self.create_font(16, bold=True))main_layout.addWidget(title_label)# 参数输入按钮param_btn = QPushButton("设置加工参数")param_btn.clicked.connect(self.set_parameters)main_layout.addWidget(param_btn)self.grid_layout = QGridLayout()self.grid_layout.setSpacing(20)main_layout.addLayout(self.grid_layout)self.tools = [{"name": "铣刀", "color": "#4A90E2", "h0": 300, "dmax": 10},{"name": "钻头 / 阶梯钻", "color": "#50C878", "h0": 400, "dmax": 15},{"name": "成型铣刀", "color": "#D35400", "h0": 350, "dmax": 8},{"name": "旋转锉", "color": "#9B59B6", "h0": 250, "dmax": 5}]self.H = 320  # 默认硬度self.d = 6    # 默认深度self.load_tool_buttons()bottom_layout = QHBoxLayout()close_btn = QPushButton("关闭")close_btn.setFixedHeight(40)close_btn.clicked.connect(self.close)bottom_layout.addStretch()bottom_layout.addWidget(close_btn)main_layout.addLayout(bottom_layout)self.setLayout(main_layout)def create_font(self, size, bold=False):font = QFont()font.setPointSize(size)font.setBold(bold)return fontdef calculate_score(self, tool):H, d = self.H, self.dH0, dmax = tool["h0"], tool["dmax"]w1, w2, k = 0.6, 0.4, 0.02term1 = 1 / (1 + math.exp(-k * (H - H0)))term2 = max(0, 1 - d / dmax) if dmax > 0 else 0return w1 * term1 + w2 * term2def set_parameters(self):H, ok1 = QInputDialog.getInt(self, "材料硬度", "请输入材料硬度 H:", value=self.H, min=100, max=600)d, ok2 = QInputDialog.getDouble(self, "加工深度", "请输入加工深度 d (mm):", value=self.d, min=0.1, max=20, decimals=1)if ok1 and ok2:self.H = Hself.d = dself.update_tool_buttons()def create_placeholder_image(self, width, height, color, label="", is_recommended=False):pixmap = QPixmap(width, height)pixmap.fill(Qt.transparent)painter = QPainter(pixmap)painter.setRenderHint(QPainter.Antialiasing)base_color = QColor(color)if is_recommended:# 推荐项加边框painter.setBrush(Qt.NoBrush)painter.setPen(QColor("gold"))painter.setPen(Qt.PenStyle(4))  # 加粗painter.drawRoundedRect(2, 2, width-4, height-4, 12, 12)painter.setBrush(base_color)painter.setPen(Qt.NoPen)painter.drawRoundedRect(0, 0, width, height, 10, 10)painter.setPen(Qt.white)painter.setFont(self.create_font(10, bold=True))painter.drawText(pixmap.rect(), Qt.AlignCenter, label)painter.end()return pixmapdef load_tool_buttons(self):self.clear_layout(self.grid_layout)for i, tool in enumerate(self.tools):btn = self.create_tool_button(tool)row, col = i // 2, i % 2self.grid_layout.addWidget(btn, row, col)def update_tool_buttons(self):scores = [self.calculate_score(t) for t in self.tools]max_score = max(scores)for i, btn in enumerate(self.findChildren(QPushButton, "")):tool = self.tools[i]score = scores[i]is_recommended = score == max_scorebtn.findChild(QLabel).setPixmap(self.create_placeholder_image(180, 80, tool["color"], tool["name"].split()[0], is_recommended))btn.setToolTip(f"适用评分: {score:.3f}" + (" ✅ 推荐" if is_recommended else ""))def create_tool_button(self, tool):btn = QPushButton()btn.setFixedSize(200, 120)btn.setStyleSheet("""QPushButton {border: 1px solid #ccc;border-radius: 10px;background-color: white;padding: 5px;}QPushButton:hover {background-color: #f9f9f9;border-color: #aaa;}""")layout = QVBoxLayout()layout.setSpacing(5)img_label = QLabel()pixmap = self.create_placeholder_image(180, 80, tool["color"], tool["name"].split()[0])img_label.setPixmap(pixmap)img_label.setAlignment(Qt.AlignCenter)layout.addWidget(img_label)text_label = QLabel(tool["name"])text_label.setAlignment(Qt.AlignCenter)text_label.setFont(self.create_font(10))layout.addWidget(text_label)btn.setLayout(layout)btn.clicked.connect(lambda: self.on_tool_selected(tool["name"]))return btndef on_tool_selected(self, tool_name):from PyQt5.QtWidgets import QMessageBoxQMessageBox.information(self, "选择", f"已选择: {tool_name}")def clear_layout(self, layout):while layout.count():child = layout.takeAt(0)if child.widget():child.widget().deleteLater()if __name__ == "__main__":app = QApplication(sys.argv)window = SmartToolSelector()window.show()sys.exit(app.exec_())

该版本展示了如何将领域知识融入 GUI 设计。通过一个简单的数学模型,系统能够根据输入参数动态推荐最优刀具,并通过视觉提示(金色边框)引导用户决策。这体现了人机协同(Human-AI Collaboration)的设计理念。


总结

本文通过三个递进版本的实现,展示了如何使用 PyQt5 构建一个功能完整、结构清晰且具备智能决策能力的刀具选择界面。从基础布局到信号通信,再到数学建模辅助决策,每一步都体现了现代 GUI 开发的核心原则:解耦、可扩展、用户中心

未来可进一步引入机器学习模型进行更复杂的推荐,或将界面封装为插件供其他系统调用。无论技术如何演进,优秀的界面设计始终服务于“降低认知负荷、提升操作效率”这一根本目标。

http://www.dtcms.com/a/469136.html

相关文章:

  • 常用库函数
  • QUIC协议相比其他传输层协议(TCP,STCP,UDP)的优势
  • 【PC+安卓】塞尔达传说:王国之泪|v1.4.2整合版|官方中文|解压可玩 内附switch模拟器
  • 【自然语言处理】实现跨层跨句的上下文语义理解的解决办法
  • 保利威点播插件功能概览:一体化视频学习与内容管理能力
  • 第六节_PySide6基本窗口控件_单行文本框(QLineEdit)
  • wordpress如何应用sslseo关键字优化软件
  • flutter项目打包macOS桌面程序dmg
  • 【MCAL】AUTOSAR架构下TC3xx芯片I2C模块详解
  • Windows10部署yolov8
  • Git|GitHub SSH 连接配置与验证全流程(通用方法)
  • K230基础-录放音频
  • 炫酷风格的 ECharts + AWS 实时数据 Dashboard
  • wordpress菜单 链接怎样进行站点优化
  • 【H3C NX30Pro】光猫桥接并使用OpenWRT配置NAS端口映射;配置IPv6、IPv4公网直连内网服务器;
  • Parasoft C/C++test如何将静态分析集成到VSCode中
  • 沈阳网站建设公司哪个好网站模板打包
  • 树莓派+ubuntu的蓝牙
  • 【k8s】基础概念+下载安装教程
  • K8S原理刨析
  • 前端学习之样式设计
  • vue3+elementplugs+原生css实现切换主题色
  • Windows用Notepad++编辑Shell脚本:一招解决Linux执行报错问题
  • 自己做网站要不要租服务器软件开发工程师时薪
  • 工业智能科技网站设计做搜狗pc网站软件下载
  • 企业网站制作收费拍卖行 网站建设
  • 网站建设和网站开发的区别域名主机基地
  • 宁波营销型网站建设首选肥东县建设局网站
  • 工商营业执照网上申报关键词优化报价
  • 帮人做网站要怎么赚钱吗网页设计软件培训机构