用户交互体验优化:缩放、拖拽、日志、错误提示
功能做完了,但好不好用是另一回事。
滚轮缩放、鼠标拖拽、操作日志、状态提示——这些小细节决定软件的专业度。
一、鼠标滚轮缩放
1.1 缩放实现
python
def wheelEvent(self, event): """处理鼠标滚轮事件实现缩放""" if self.original_pixmap is None: return delta = event.angleDelta().y() # 每次滚轮调整10% if delta > 0: self.scale_factor = min(self.scale_factor * 1.1, 5.0) # 最大5倍 else: self.scale_factor = max(self.scale_factor / 1.1, 0.1) # 最小0.1倍 self.update_display() self.parent_window.update_status_bar(f"缩放: {int(self.scale_factor * 100)}%")1.2 缩放参数
| 参数 | 值 | 说明 |
|---|---|---|
| 缩放步长 | 10% | 每次滚动调整10% |
| 最大缩放 | 5.0 | 最多放大5倍 |
| 最小缩放 | 0.1 | 最多缩小到10% |
1.3 平滑缩放
python
def update_display(self): if self.original_pixmap is None: super().setPixmap(QPixmap()) return scaled_pixmap = self.original_pixmap.scaled( self.original_pixmap.size() * self.scale_factor, Qt.AspectRatioMode.KeepAspectRatio, # 保持宽高比 Qt.TransformationMode.SmoothTransformation # 平滑插值,不锯齿 ) super().setPixmap(scaled_pixmap)
二、图像拖拽平移
2.1 拖拽状态
python
class ImageDisplay(QLabel): def __init__(self, parent=None): super().__init__(parent) self.dragging = False self.drag_start = QPoint(0, 0) self.offset = QPoint(0, 0)
2.2 事件处理
python
def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.dragging = True self.drag_start = event.pos() def mouseMoveEvent(self, event): if self.dragging and self.original_pixmap is not None: delta = event.pos() - self.drag_start self.offset = QPoint(delta.x(), delta.y()) self.drag_start = event.pos() def mouseReleaseEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.dragging = False if self.parent_window is not None: self.parent_window.handle_left_click(event)
三、操作日志记录
3.1 日志添加
python
def add_log(self, message): """添加操作日志""" timestamp = get_timestamp().split(" ")[1] # 只取时分秒 self.log_text.append(f"[{timestamp}] {message}") # 自动滚动到底部 self.log_text.verticalScrollBar().setValue( self.log_text.verticalScrollBar().maximum() )3.2 日志显示效果
text
[10:30:45] 已加载图像: droplet.jpg [10:30:52] 进入校准模式,请在标尺上点击两个点 [10:30:55] 已选择校准点 1/2 [10:30:58] 已选择校准点 2/2 [10:31:02] 校准成功!1像素 = 0.086127 mm [10:31:15] 进入区域选择模式,左键点击选择两个对角点 [10:31:18] 已选择区域点 1/2: (100, 100) [10:31:20] 已选择区域点 2/2: (300, 300) [10:31:21] 区域选择完成,自动进行液滴检测... [10:31:22] 液滴检测成功
3.3 日志组件
python
log_group = QWidget() log_layout = QVBoxLayout(log_group) log_label = QLabel("<b>操作日志</b>") log_layout.addWidget(log_label) self.log_text = QTextEdit() self.log_text.setReadOnly(True) self.log_text.setStyleSheet("background-color: #f8f9fa; font-size: 11px;") log_layout.addWidget(self.log_text)四、错误处理与提示
4.1 消息对话框封装
python
def show_message(parent, title, message, icon=QMessageBox.Icon.Information): msg = QMessageBox(parent) msg.setIcon(icon) msg.setWindowTitle(title) msg.setText(message) msg.exec() def show_error(parent, message): show_message(parent, "错误", message, QMessageBox.Icon.Critical) def show_info(parent, message): show_message(parent, "信息", message, QMessageBox.Icon.Information)
4.2 常见错误拦截
python
def open_image(self): file_path, _ = QFileDialog.getOpenFileName( self, "选择图像文件", "", "图像文件 (*.jpg *.jpeg *.png *.bmp)" ) if file_path: success, msg = self.image_processor.load_image(file_path) if success: # 成功处理... else: show_error(self, msg) # 加载失败弹窗
4.3 操作前置检查
python
def start_calibration(self): if self.image_processor.get_original_image() is None: show_error(self, "请先加载图像") return # 继续校准...
五、状态栏实时信息
5.1 初始化
python
def create_status_bar(self): self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) self.status_bar.showMessage("就绪 - 请导入图像")5.2 更新方法
python
def update_status_bar(self, message): self.status_bar.showMessage(message)
5.3 状态示例
| 操作 | 状态消息 |
|---|---|
| 程序启动 | 就绪 - 请导入图像 |
| 加载图像 | 图像加载成功: droplet.jpg |
| 校准模式 | 校准模式: 请在标尺上点击两个点 |
| 区域选择 | 区域选择模式: 左键选择两个对角点 |
| 手动圈选 | 手动圈选模式: 左键添加点,右键闭合 |
| 检测成功 | 液滴检测成功 |
| 缩放 | 缩放: 150% |
六、视觉反馈
6.1 状态颜色区分
python
def update_info_panel(self): if self.calibrator.is_calibrated(): self.calibration_status.setStyleSheet("color: #28a745;") # 绿色 else: self.calibration_status.setStyleSheet("color: #dc3545;") # 红色6.2 重要数值高亮
python
self.real_area_display = QLabel("实际面积: 0.0000 mm²") self.real_area_display.setStyleSheet( "font-size: 14px; font-weight: bold; color: #007bff;" )6.3 组件背景统一
python
# 图像显示区深色背景 self.setStyleSheet("background-color: #2a2a2a;") # 日志和提示浅灰背景 self.log_text.setStyleSheet("background-color: #f8f9fa;") tips_text.setStyleSheet("background-color: #f8f9fa;")七、右键菜单支持
7.1 右键事件传递
python
def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: # 左键处理... elif event.button() == Qt.MouseButton.RightButton: if self.parent_window is not None: self.parent_window.handle_right_click(event)
7.2 手动圈选闭合
python
def handle_right_click(self, event): if self.image_processor.is_manual_drawing(): success, msg = self.image_processor.close_manual_contour() if success: self.display_image() self.calculate_and_display_area() self.add_log(msg) self.status_bar.showMessage(msg) else: show_error(self, msg)
八、键盘快捷键
8.1 注册快捷键
python
def create_menubar(self): file_menu = QMenu("文件", self) self.action_open = QAction("导入图像", self) self.action_open.setShortcut("Ctrl+O") # 快捷键 self.action_open.triggered.connect(self.open_image) file_menu.addAction(self.action_open) # ...8.2 建议的快捷键清单
| 功能 | 快捷键 | 说明 |
|---|---|---|
| 导入图像 | Ctrl+O | 打开图像文件 |
| 保存标注图像 | Ctrl+S | 保存带轮廓的图像 |
| 导出CSV | Ctrl+E | 导出测量数据 |
| 标尺校准 | Ctrl+C | 进入校准模式 |
| 区域选择 | Ctrl+R | 进入区域选择模式 |
| 手动圈选 | Ctrl+M | 进入手动圈选模式 |
| 自动检测 | Ctrl+D | 执行自动检测 |
| 清除轮廓 | Ctrl+X | 清除当前轮廓 |
| 退出 | Ctrl+Q | 退出程序 |
九、踩坑记录
缩放中心:默认缩放是以图像左上角为基准,要改成以鼠标位置为中心需要额外计算
拖拽偏移:拖拽时要考虑当前缩放比例,否则拖拽速度不匹配
日志自动滚动:每次添加日志后必须手动滚动到底部,否则用户看不到最新
错误提示不弹窗:有些错误只用日志记录用户看不到,关键错误必须弹窗
快捷键冲突:避免和系统快捷键或输入框内快捷键冲突
下篇预告
系列文章到此基本结束。后续可能会写软件打包发布(PyInstaller)。
如果对用户体验有更好的建议,评论区聊。
