首先的是一个数据采集处理和导出的程序import sys
import time
import random
import pandas as pd
from datetime import datetime
from PyQt5.QtCore import QThread, pyqtSignal, QMutex, QWaitCondition, Qt
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QPushButton, QTableWidget, QTableWidgetItem,
QProgressBar, QLabel, QMessageBox, QTextEdit,
QListWidget, QSplitter, QListWidgetItem, QAbstractItemView)
线程安全的数据存储
class ThreadSafeDataStore:
def init(self):
self.data = []
self.mutex = QMutex()
self.condition = QWaitCondition()
def add_data(self, item): """添加数据(线程安全)""" self.mutex.lock() self.data.append(item) self.mutex.unlock() def get_all_data(self): """获取所有数据(线程安全)""" self.mutex.lock() data_copy = self.data[:] self.mutex.unlock() return data_copy def clear(self): """清空数据(线程安全)""" self.mutex.lock() self.data.clear() self.mutex.unlock()
数据采集线程
class DataCollectorThread(QThread):
data_collected = pyqtSignal(dict)
progress_updated = pyqtSignal(int)
status_changed = pyqtSignal(str)
def __init__(self, data_store): super().__init__() self.data_store = data_store self._is_paused = False self._is_running = False self.pause_condition = QWaitCondition() self.mutex = QMutex() self.sample_count = 0 # 样本计数器 def run(self): """线程主循环""" self._is_running = True self.sample_count = 0 while self._is_running: # 暂停处理 self.mutex.lock() if self._is_paused: self.status_changed.emit("采集已暂停") self.pause_condition.wait(self.mutex) self.mutex.unlock() # 模拟数据采集 self.sample_count += 1 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") value = random.uniform(0, 100) temperature = random.uniform(20, 30) data_point = { "timestamp": timestamp, "sample_id": self.sample_count, "value": value, "temperature": temperature } # 保存数据并发送信号 self.data_store.add_data(data_point) self.data_collected.emit(data_point) self.progress_updated.emit(self.sample_count) self.status_changed.emit(f"采集样本 #{self.sample_count}") # 控制采集速度 time.sleep(0.5) def pause(self): """暂停采集""" self.mutex.lock() self._is_paused = True self.mutex.unlock() def resume(self): """恢复采集""" self.mutex.lock() self._is_paused = False self.pause_condition.wakeAll() self.mutex.unlock() def stop(self): """停止线程""" self._is_running = False self.resume() # 确保线程能退出 self.wait() def reset_counter(self): """重置样本计数器""" self.sample_count = 0
数据处理线程
class DataProcessorThread(QThread):
processed_data = pyqtSignal(dict)
status_changed = pyqtSignal(str)
def __init__(self, data_store): super().__init__() self.data_store = data_store self._is_running = False def run(self): """线程主循环""" self._is_running = True while self._is_running: # 获取所有数据 data = self.data_store.get_all_data() if data: # 模拟数据处理:计算统计指标 values = [d['value'] for d in data] avg_value = sum(values) / len(values) max_value = max(values) min_value = min(values) result = { "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "samples": len(data), "avg_value": avg_value, "max_value": max_value, "min_value": min_value } # 发送处理结果 self.processed_data.emit(result) self.status_changed.emit(f"处理了 {len(data)} 个样本") # 控制处理频率 time.sleep(1) def stop(self): """停止线程""" self._is_running = False self.wait()
主窗口
class MainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(“多线程数据采集与分析系统”)
self.setGeometry(100, 100, 1000, 700)
# 测试计数器 self.test_counter = 1 # 历史测试数据存储 self.history_tests = {} # 创建共享数据存储 self.data_store = ThreadSafeDataStore() # 初始化线程 self.collector_thread = DataCollectorThread(self.data_store) self.processor_thread = DataProcessorThread(self.data_store) # 初始化UI self.init_ui() # 连接信号 self.connect_signals() def init_ui(self): """初始化用户界面""" # 主布局 main_widget = QWidget() main_layout = QVBoxLayout(main_widget) # 使用分割器使界面更灵活 splitter = QSplitter(Qt.Vertical) # 顶部控制面板 top_widget = QWidget() top_layout = QVBoxLayout(top_widget) # 控制面板 - 使用两行布局 control_layout = QVBoxLayout() row1_layout = QHBoxLayout() row2_layout = QHBoxLayout() # 第一行按钮 self.start_btn = QPushButton("开始采集") self.pause_btn = QPushButton("暂停采集") self.stop_btn = QPushButton("停止采集") # 第二行按钮 self.restart_current_btn = QPushButton("重新本次采集") self.restart_btn = QPushButton("重新采集") self.export_btn = QPushButton("导出选中数据") # 初始状态设置 self.pause_btn.setEnabled(False) self.stop_btn.setEnabled(False) self.restart_current_btn.setEnabled(False) self.restart_btn.setEnabled(False) self.export_btn.setEnabled(False) # 添加到布局 row1_layout.addWidget(self.start_btn) row1_layout.addWidget(self.pause_btn) row1_layout.addWidget(self.stop_btn) row2_layout.addWidget(self.restart_current_btn) row2_layout.addWidget(self.restart_btn) row2_layout.addWidget(self.export_btn) control_layout.addLayout(row1_layout) control_layout.addLayout(row2_layout) # 状态显示 status_layout = QHBoxLayout() self.status_label = QLabel("就绪") self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) status_layout.addWidget(self.status_label, 3) status_layout.addWidget(self.progress_bar, 7) top_layout.addLayout(control_layout) top_layout.addLayout(status_layout) # 中部数据显示区域 center_widget = QWidget() center_layout = QHBoxLayout(center_widget) # 左侧:历史测试列表 history_layout = QVBoxLayout() history_layout.addWidget(QLabel("历史测试记录:")) self.test_list = QListWidget() self.test_list.setSelectionMode(QAbstractItemView.ExtendedSelection) # 允许多选 history_layout.addWidget(self.test_list) # 右侧:数据表格 data_layout = QVBoxLayout() # 原始数据表格 self.data_table = QTableWidget() self.data_table.setColumnCount(4) self.data_table.setHorizontalHeaderLabels(["测试时间", "测试次数", "指标1", "指标2"]) self.data_table.setMinimumHeight(200) # 处理结果表格 self.result_table = QTableWidget() self.result_table.setColumnCount(5) self.result_table.setHorizontalHeaderLabels(["处理时间", "样本数", "平均值", "最大值", "最小值"]) self.result_table.setMinimumHeight(150) data_layout.addWidget(QLabel("原始数据:")) data_layout.addWidget(self.data_table) data_layout.addWidget(QLabel("处理结果:")) data_layout.addWidget(self.result_table) center_layout.addLayout(history_layout, 1) center_layout.addLayout(data_layout, 3) # 底部:日志区域 bottom_widget = QWidget() bottom_layout = QVBoxLayout(bottom_widget) bottom_layout.addWidget(QLabel("操作日志:")) self.log_view = QTextEdit() self.log_view.setReadOnly(True) self.log_view.setMinimumHeight(100) bottom_layout.addWidget(self.log_view) # 组装分割器 splitter.addWidget(top_widget) splitter.addWidget(center_widget) splitter.addWidget(bottom_widget) splitter.setSizes([100, 400, 150]) # 设置各部分大小比例 main_layout.addWidget(splitter) self.setCentralWidget(main_widget) # 连接按钮信号 self.start_btn.clicked.connect(self.start_test) self.pause_btn.clicked.connect(self.toggle_pause) self.stop_btn.clicked.connect(self.stop_test) self.export_btn.clicked.connect(self.export_data) self.restart_current_btn.clicked.connect(self.restart_current) self.restart_btn.clicked.connect(self.restart_all) # 连接列表选择信号 self.test_list.itemSelectionChanged.connect(self.show_selected_test) def connect_signals(self): """连接线程信号到槽函数""" self.collector_thread.data_collected.connect(self.add_data_row) self.collector_thread.progress_updated.connect(self.update_progress) self.collector_thread.status_changed.connect(self.update_status) self.processor_thread.processed_data.connect(self.add_result_row) self.processor_thread.status_changed.connect(self.log_message) def start_test(self): """开始采集""" self.log_message("开始数据采集...") # 清空数据 self.data_store.clear() self.data_table.setRowCount(0) self.result_table.setRowCount(0) self.progress_bar.setValue(0) # 重置样本计数器 self.collector_thread.reset_counter() # 启动线程 if not self.collector_thread.isRunning(): self.collector_thread.start() if not self.processor_thread.isRunning(): self.processor_thread.start() # 更新UI状态 self.start_btn.setEnabled(False) self.pause_btn.setEnabled(True) self.stop_btn.setEnabled(True) self.restart_current_btn.setEnabled(True) self.restart_btn.setEnabled(True) self.export_btn.setEnabled(False) self.pause_btn.setText("暂停采集") def restart_current(self): """重新本次采集 - 清空当前数据但保持采集状态""" if not self.collector_thread.isRunning(): self.log_message("警告:采集未运行,无法重新本次采集") return self.log_message("重新本次采集...") # 清空当前数据 self.data_store.clear() self.data_table.setRowCount(0) self.result_table.setRowCount(0) self.progress_bar.setValue(0) # 重置样本计数器 self.collector_thread.reset_counter() self.log_message("已清空当前采集数据,继续采集...") def restart_all(self): """重新采集 - 停止当前采集并重新开始""" self.log_message("重新采集...") # 停止当前采集 if self.collector_thread.isRunning(): self.stop_test() # 开始新的采集 self.start_test() def toggle_pause(self): """切换暂停/继续状态""" if not self.collector_thread.isRunning(): self.log_message("警告:采集未运行,无法暂停") return if self.collector_thread._is_paused: self.collector_thread.resume() self.pause_btn.setText("暂停采集") self.log_message("继续数据采集...") else: self.collector_thread.pause() self.pause_btn.setText("继续采集") self.log_message("数据采集已暂停...") def stop_test(self): """停止采集""" self.log_message("停止数据采集...") # 停止线程 if self.collector_thread.isRunning(): self.collector_thread.stop() if self.processor_thread.isRunning(): self.processor_thread.stop() # 保存本次测试数据 test_name = f"测试{self.test_counter}" test_data = self.data_store.get_all_data() self.history_tests[test_name] = test_data # 添加到历史测试列表 item = QListWidgetItem(test_name) item.setData(Qt.UserRole, test_name) # 存储测试名称 self.test_list.addItem(item) self.log_message(f"已保存本次测试数据: {test_name}") self.test_counter += 1 # 更新UI状态 self.start_btn.setEnabled(True) self.pause_btn.setEnabled(False) self.stop_btn.setEnabled(False) self.restart_current_btn.setEnabled(False) self.restart_btn.setEnabled(True) self.export_btn.setEnabled(True) self.pause_btn.setText("暂停采集") # 重置按钮文本 data_count = len(test_data) self.log_message(f"采集完成,共收集 {data_count} 个样本") def show_selected_test(self): """显示选中的测试数据""" selected_items = self.test_list.selectedItems() if not selected_items: return # 只显示第一个选中的测试 test_name = selected_items[0].data(Qt.UserRole) test_data = self.history_tests.get(test_name, []) # 更新原始数据表格 self.data_table.setRowCount(0) for row, data_point in enumerate(test_data): self.data_table.insertRow(row) self.data_table.setItem(row, 0, QTableWidgetItem(data_point["timestamp"])) self.data_table.setItem(row, 1, QTableWidgetItem(str(data_point["sample_id"]))) self.data_table.setItem(row, 2, QTableWidgetItem(f"{data_point['value']:.2f}")) self.data_table.setItem(row, 3, QTableWidgetItem(f"{data_point['temperature']:.2f}")) # 更新处理结果表格(需要重新计算) if test_data: values = [d['value'] for d in test_data] avg_value = sum(values) / len(values) max_value = max(values) min_value = min(values) self.result_table.setRowCount(0) self.result_table.insertRow(0) self.result_table.setItem(0, 0, QTableWidgetItem(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) self.result_table.setItem(0, 1, QTableWidgetItem(str(len(test_data)))) self.result_table.setItem(0, 2, QTableWidgetItem(f"{avg_value:.2f}")) self.result_table.setItem(0, 3, QTableWidgetItem(f"{max_value:.2f}")) self.result_table.setItem(0, 4, QTableWidgetItem(f"{min_value:.2f}")) def export_data(self): """导出选中的测试数据到Excel文件""" selected_items = self.test_list.selectedItems() if not selected_items: QMessageBox.warning(self, "导出失败", "请选择要导出的测试集") return # 收集所有选中的测试数据 all_data = [] for item in selected_items: test_name = item.data(Qt.UserRole) test_data = self.history_tests.get(test_name, []) # 为每个数据点添加测试名称 for data_point in test_data: data_point_with_test = data_point.copy() data_point_with_test["test_name"] = test_name all_data.append(data_point_with_test) if not all_data: QMessageBox.warning(self, "导出失败", "选中的测试集没有可导出的数据") return try: today = datetime.now() filename = f"data_export_{today.strftime('%Y%m%d_%H%M%S')}.xlsx" # 创建DataFrame并导出 df = pd.DataFrame(all_data) # 重新排序列 column_order = ["test_name", "timestamp", "sample_id", "value", "temperature"] df = df[column_order] df.to_excel(filename, index=False) self.log_message(f"已导出 {len(selected_items)} 个测试集的数据到: {filename}") QMessageBox.information(self, "导出成功", f"已成功导出 {len(selected_items)} 个测试集的数据到:\n{filename}") except Exception as e: self.log_message(f"导出失败: {str(e)}") QMessageBox.critical(self, "导出错误", f"导出数据时发生错误:\n{str(e)}") def add_data_row(self, data): """添加数据到表格""" row = self.data_table.rowCount() self.data_table.insertRow(row) self.data_table.setItem(row, 0, QTableWidgetItem(data["timestamp"])) self.data_table.setItem(row, 1, QTableWidgetItem(str(data["sample_id"]))) self.data_table.setItem(row, 2, QTableWidgetItem(f"{data['value']:.2f}")) self.data_table.setItem(row, 3, QTableWidgetItem(f"{data['temperature']:.2f}")) # 自动滚动到最后一行 self.data_table.scrollToBottom() def add_result_row(self, result): """添加处理结果到表格""" row = self.result_table.rowCount() self.result_table.insertRow(row) self.result_table.setItem(row, 0, QTableWidgetItem(result["timestamp"])) self.result_table.setItem(row, 1, QTableWidgetItem(str(result["samples"]))) self.result_table.setItem(row, 2, QTableWidgetItem(f"{result['avg_value']:.2f}")) self.result_table.setItem(row, 3, QTableWidgetItem(f"{result['max_value']:.2f}")) self.result_table.setItem(row, 4, QTableWidgetItem(f"{result['min_value']:.2f}")) # 自动滚动到最后一行 self.result_table.scrollToBottom() def update_progress(self, count): """更新进度条""" self.progress_bar.setValue(count % 100) def update_status(self, status): """更新状态标签""" self.status_label.setText(status) def log_message(self, message): """添加日志消息""" timestamp = datetime.now().strftime("%H:%M:%S") self.log_view.append(f"[{timestamp}] {message}") def closeEvent(self, event): """窗口关闭时确保线程停止""" if self.collector_thread.isRunning(): self.collector_thread.stop() if self.processor_thread.isRunning(): self.processor_thread.stop() event.accept()
if name == “main”:
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
接下来是需要修改的程序,请根据上面程序的内容,修改下面程序的数据采集后的部分,仿照上面的程序在测试后建立测试集,选中测设集可以导出为excel文件。不要修改原界面布局,界面中间部分的下方空白处放的是采集的数据,右上方的空白处显示数据集,将“导出全部为json”改为“导出为Excel”,点击此按钮即可导出excel文件,其他的部分仍要保持原样
import sys
from PyQt5.QtGui import QPixmap, QPainter
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QDockWidget, QVBoxLayout, QWidget, QLabel,
QPushButton, QTreeWidget, QTreeWidgetItem, QTextEdit, QFileDialog, QMessageBox,
QTextBrowser
)
from PyQt5.QtCore import Qt, QTimer, QUrl, QThread, QDir
from ui.Pages.capturePage.LeftRegion1 import StatusRegion
from ui.Pages.capturePage.RightRegion import videoRegion, videoRegion1
from ui.Pages.capturePage.CenterUpRegion import CentralUpRegion
from ui.Pages.capturePage.CenterDownRegion1 import CentralDownpRegion
class CapturePage(QMainWindow):
def init(self):
super().init()
self.init_ratio()
self.initUI()
self.slot_connect()
def init_ratio(self): """初始化区域比例""" self.horizontal_ratio = [0.2, 0.8] # 左右区域 self.vertical_ratio = [0.5, 0.5] # 中部上下 self.right_ratio = [0.5, 0.5] # 右侧上下 def slot_connect(self): """连接信号槽""" self.status_ui.device_status_changed.connect(self.central_down_widget.get_device_status) self.status_ui.device_stream.connect(self.central_down_widget.handle_data_from_device) def initUI(self): self.takeCentralWidget() self.setDockOptions(self.dockOptions() | QMainWindow.DockOption.AllowTabbedDocks) self.setDockNestingEnabled(True) self.setWindowTitle("数据采集界面") self.setGeometry(100, 100, 1600, 1000) # 初始窗口大小 # 左侧区域 self.status_ui = StatusRegion() self.addDockWidget(Qt.LeftDockWidgetArea, self.status_ui) # 中间区域 self.central_up_widget = CentralUpRegion() # 右侧区域 self.video1_ui = videoRegion() self.central_down_widget = CentralDownpRegion(self.central_up_widget, self.video1_ui) self.video2_ui = videoRegion1() self.addDockWidget(Qt.RightDockWidgetArea, self.video1_ui) self.addDockWidget(Qt.RightDockWidgetArea, self.video2_ui) # 嵌套布局 self.splitDockWidget(self.status_ui, self.central_up_widget, Qt.Horizontal) self.splitDockWidget(self.central_up_widget, self.central_down_widget, Qt.Vertical) self.splitDockWidget(self.video1_ui, self.video2_ui, Qt.Vertical) # 背景图 self.background = QPixmap(r"C:\Users\86153\Downloads\【慧首UI】开发\素材\caiji.jpg") def paintEvent(self, event): painter = QPainter(self) painter.drawPixmap(self.rect(), self.background) def resizeEvent(self, event): """保持窗口缩放时区域比例不变""" super().resizeEvent(event) # 横向分配(左:状态,中:中心区域) total_width = self.width() left_width = int(total_width * self.horizontal_ratio[0]) center_width = int(total_width * self.horizontal_ratio[1]) self.resizeDocks([self.status_ui, self.central_up_widget], [left_width, center_width], Qt.Horizontal) # 中部纵向分配(上、下) center_total_height = self.central_up_widget.height() + self.central_down_widget.height() up_height = int(center_total_height * self.vertical_ratio[0]) down_height = int(center_total_height * self.vertical_ratio[1]) self.resizeDocks([self.central_up_widget, self.central_down_widget], [up_height, down_height], Qt.Vertical) # 右侧纵向分配(video1, video2) right_total_height = self.video1_ui.height() + self.video2_ui.height() video1_height = int(right_total_height * self.right_ratio[0]) video2_height = int(right_total_height * self.right_ratio[1]) self.resizeDocks([self.video1_ui, self.video2_ui], [video1_height, video2_height], Qt.Vertical)
if name == ‘main’:
app = QApplication(sys.argv)
main_window = CapturePage()
main_window.show()
sys.exit(app.exec_())
以下为程序中调用的程序
import sys
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel,
QHBoxLayout, QPushButton, QTextBrowser
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
from CenterUpRegion import CentralUpRegion
from tools.device.myoDevice1 import DataCollectorThread
from VideoPlay1 import VideoPlayerThread
from ui.Pages.capturePage.tools.VideoPlay import VideoPlayerThread
class CentralDownpRegion(QDockWidget):
def init(self, PlayRegion,parent=None):
super().init(‘采集控制区域’)
self.root_path = r’C:\Users\86153\Downloads\【慧首UI】开发\素材’# 视频文件目录
self.video_paths = [‘休息.mp4’,‘握拳.mp4’, ‘抓手机.mp4’, ‘捏杯盖.mp4’, ‘抓水杯.mp4’, ‘二指捏笔.mp4’, ‘伸食指.mp4’,
‘捏钥匙.mp4’]
self.PlayRegion = PlayRegion # 视频播放(对应上边的那个类) self.initUI() self.mode = 0 # 采集模式(0=全部采集,1=单个动作) self.current_action = 0 # 当前动作索引 (0~6) self.current_repeat = 0 # 当前动作的采集次数 (0~5) self.target_action = 0 # 目标动作(单个采集模式下) self.target_repeats = 6 # 目标采集次数(默认6次) self.is_paused = False # 是否暂停 self.is_resting = False # 是否处于休息状态 def initUI(self): # 创建中心区域布局 self.lower_area_widget = QWidget() self.lower_area_layout = QVBoxLayout() self.collect_button_layout = QHBoxLayout() # 选择模式 self.mode_all = QRadioButton("全部采集") self.mode_single = QRadioButton("单个动作采集") self.mode_all.setChecked(True) self.collect_button_layout.addWidget(self.mode_all) self.collect_button_layout.addWidget(self.mode_single) # 选择动作(单个模式) self.action_label = QLabel("选择动作:") self.action_select = QSpinBox() self.action_select.setRange(1, 7) # 1~7 对应索引 0~6 self.collect_button_layout.addWidget(self.action_label) self.collect_button_layout.addWidget(self.action_select) # 选择采集次数(单个模式) self.repeat_label = QLabel("采集次数:") self.repeat_select = QSpinBox() self.repeat_select.setRange(1, 6) # 1~6 次 self.collect_button_layout.addWidget(self.repeat_label) self.collect_button_layout.addWidget(self.repeat_select) self.lower_area_layout.addLayout(self.collect_button_layout) # 采集控制按钮 self.control_button_layout = QHBoxLayout() self.start_button = QPushButton("开始采集") self.pause_button = QPushButton("暂停采集") self.resume_button = QPushButton("继续采集") self.restart_current_button = QPushButton("重新本次采集") self.restart_button = QPushButton("重新采集") self.control_button_layout.addWidget(self.start_button) self.control_button_layout.addWidget(self.pause_button) self.control_button_layout.addWidget(self.resume_button) self.control_button_layout.addWidget(self.restart_current_button) self.control_button_layout.addWidget(self.restart_button) self.lower_area_layout.addLayout(self.control_button_layout) # 采集状态显示 self.collect_status = QTextBrowser() self.lower_area_layout.addWidget(self.collect_status) self.lower_area_widget.setLayout(self.lower_area_layout) self.setWidget(self.lower_area_widget) # 绑定按钮事件 self.start_button.clicked.connect(self.start_collection) self.pause_button.clicked.connect(self.pause_collection) self.resume_button.clicked.connect(self.resume_collection) self.restart_current_button.clicked.connect(self.restart_current_collection) self.restart_button.clicked.connect(self.restart_collection) # 模式切换 self.mode_all.toggled.connect(self.update_mode) self.mode_single.toggled.connect(self.update_mode) # 禁用“继续采集”按钮,只有在暂停后才能点击 self.resume_button.setEnabled(False) def update_mode(self): """ 更新模式选择 """ if self.mode_all.isChecked(): self.mode = 0 self.action_select.setEnabled(False) self.repeat_select.setEnabled(False) else: self.mode = 1 self.action_select.setEnabled(True) self.repeat_select.setEnabled(True) def start_collection(self): self.current_action = self.action_select.value() - 1 self.start_button.setEnabled(False) self.pause_button.setEnabled(True) self.resume_button.setEnabled(False) self.restart_current_button.setEnabled(True) self.restart_button.setEnabled(True) self.thread = VideoPlayerThread(self.root_path,self.video_paths) # 创建线程 self.thread.frame_ready.connect(self.PlayRegion.update_frame) self.thread.start_playback(self.mode,self.current_action,1) def pause_collection(self): self.collect_status.append("采集暂停...") self.start_button.setEnabled(False) self.pause_button.setEnabled(False) self.resume_button.setEnabled(True) self.restart_current_button.setEnabled(True) self.restart_button.setEnabled(True) self.thread.pause() def resume_collection(self): self.collect_status.append(f"恢复采集,继续动作 {self.current_action + 1},第 {self.current_repeat} 次采集...") self.start_button.setEnabled(False) self.pause_button.setEnabled(True) self.resume_button.setEnabled(False) self.restart_current_button.setEnabled(True) self.restart_button.setEnabled(True) self.thread.resume() def restart_current_collection(self): self.collect_status.append(f"重新开始当前动作 {self.current_action + 1}...") self.start_button.setEnabled(True) self.pause_button.setEnabled(False) self.resume_button.setEnabled(False) self.restart_current_button.setEnabled(True) self.restart_button.setEnabled(True) self.thread.stop() def restart_collection(self): self.collect_status.append("重新开始所有采集...") self.start_button.setEnabled(True) self.pause_button.setEnabled(False) self.resume_button.setEnabled(False) self.restart_current_button.setEnabled(True) self.restart_button.setEnabled(True) self.thread.stop()
class MainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(“视频采集系统”)
self.PlayRegion = CentralUpRegion(self) self.collect_control = CentralDownpRegion(self.PlayRegion) self.addDockWidget(Qt.TopDockWidgetArea, self.PlayRegion) self.addDockWidget(Qt.BottomDockWidgetArea, self.collect_control)
if name == ‘main’:
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
以及
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QLabel, QWidget, QVBoxLayout, QDockWidget
class CentralUpRegion(QDockWidget):
def init(self, parent=None):
super().init(‘视频播放区域’, parent)
# self.root_path = ‘D:/Code/UI/【慧首UI】开发/素材’ # 视频文件目录
# self.video_paths = [‘休息.mp4’,‘握拳.mp4’, ‘抓手机.mp4’, ‘捏杯盖.mp4’, ‘抓水杯.mp4’, ‘二指捏笔.mp4’, ‘伸食指.mp4’,
# ‘捏钥匙.mp4’]
self.current_video_index = 0 self.play_count = 0 self.play_limit = None self.mode = 0 self.action_index = None self.cap = None self.video_label = QLabel() self.initUI() # self.videoPlayThread.frame_ready.connect(self.update_frame) def initUI(self): # self.video_label = QLabel() self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setText("等待播放视频...") self.widget = QWidget() self.layout = QVBoxLayout() self.layout.addWidget(self.video_label) self.widget.setLayout(self.layout) self.setWidget(self.widget) def update_frame(self,qimg): # print("接收到视频帧") self.video_label.setPixmap(QPixmap.fromImage(qimg))