WPF调用Python心率监测脚本解决方案

一、项目背景

你有一个Python脚本PolarHR.py,使用bleak库异步扫描并连接蓝牙心率设备,后台线程持续获取心率数据,并每2秒打印最新心率。

你希望在WPF程序中启动该Python脚本,实时获取心率数据并显示。


二、Python脚本(PolarHR.py

请确保Python脚本内容如下,重点是:

  • 使用print(..., flush=True)确保输出不被缓冲,WPF能及时读取。
  • 每2秒打印格式为当前心率: 数字的字符串,方便WPF解析。
python 复制代码
import asyncio
import threading
from bleak import BleakScanner, BleakClient
import time

HR_UUID = "00002a37-0000-1000-8000-00805f9b34fb"
_latest_heart_rate = None
_lock = threading.Lock()

async def _heart_rate_worker():
    global _latest_heart_rate
    print("开始扫描设备...", flush=True)
    devices = await BleakScanner.discover(timeout=5)
    print(f"扫描到设备数量: {len(devices)}", flush=True)
    polar_devices = [d for d in devices if d.name and "Polar" in d.name]
    print(f"找到 Polar 设备数量: {len(polar_devices)}", flush=True)
    if not polar_devices:
        print("未找到 Polar 设备", flush=True)
        return
    device = polar_devices[0]

    async with BleakClient(device.address) as client:
        queue = asyncio.Queue()

        def callback(sender, data):
            flags = data[0]
            hr_format = flags & 0x01
            if hr_format:
                hr = int.from_bytes(data[1:3], byteorder='little')
            else:
                hr = data[1]
            queue.put_nowait(hr)

        await client.start_notify(HR_UUID, callback)
        print(f"已连接设备 {device.name},开始接收心率数据...", flush=True)

        while True:
            hr = await queue.get()
            with _lock:
                _latest_heart_rate = hr

def _start_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_until_complete(_heart_rate_worker())

def start_heart_rate_monitor():
    loop = asyncio.new_event_loop()
    t = threading.Thread(target=_start_loop, args=(loop,), daemon=True)
    t.start()

def get_latest_heart_rate():
    with _lock:
        return _latest_heart_rate

if __name__ == "__main__":
    start_heart_rate_monitor()
    while True:
        hr = get_latest_heart_rate()
        if hr is not None:
            print(f"当前心率: {hr}", flush=True)
        else:
            print("当前心率: None", flush=True)
        time.sleep(2)

三、WPF项目代码示例

1. MainWindow.xaml

xml 复制代码
<Window x:Class="HeartRateWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        Title="心率监测" Height="200" Width="300">
    <Grid>
        <TextBlock x:Name="HeartRateTextBlock" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

2. MainWindow.xaml.cs

csharp 复制代码
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Threading;

namespace HeartRateWpfApp
{
    public partial class MainWindow : Window
    {
        private Process _pythonProcess;
        private string _latestHeartRate = null;
        private DispatcherTimer _timer;

        public MainWindow()
        {
            InitializeComponent();
            StartPythonProcess();
            StartTimer();
        }

        private void StartPythonProcess()
        {
            var psi = new ProcessStartInfo
            {
                FileName = @"C:\Path\To\Your\Python\python.exe",  // 替换为你的python.exe完整路径
                Arguments = "-u PolarHR.py",  // -u 禁用缓冲,PolarHR.py是脚本名
                WorkingDirectory = @"C:\Users\86730\Desktop\步态资料\步态资料", // 脚本所在目录
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true
            };

            _pythonProcess = new Process();
            _pythonProcess.StartInfo = psi;
            _pythonProcess.OutputDataReceived += PythonOutputDataReceived;
            _pythonProcess.ErrorDataReceived += PythonErrorDataReceived;
            _pythonProcess.Start();
            _pythonProcess.BeginOutputReadLine();
            _pythonProcess.BeginErrorReadLine();
        }

        private void PythonOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data)) return;

            // 调试输出,方便查看Python打印内容
            Console.WriteLine("Python STDOUT: " + e.Data);

            // 匹配格式:当前心率: 数字
            var match = Regex.Match(e.Data, @"当前心率:\s*(\d+)");
            if (match.Success)
            {
                _latestHeartRate = match.Groups[1].Value;
            }
        }

        private void PythonErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                Console.WriteLine("Python STDERR: " + e.Data);
            }
        }

        private void StartTimer()
        {
            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromSeconds(2);
            _timer.Tick += Timer_Tick;
            _timer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(_latestHeartRate))
            {
                HeartRateTextBlock.Text = "等待心率数据...";
            }
            else
            {
                HeartRateTextBlock.Text = $"当前心率: {_latestHeartRate}";
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            if (_pythonProcess != null && !_pythonProcess.HasExited)
            {
                _pythonProcess.Kill();
                _pythonProcess.Dispose();
            }
        }
    }
}

四、注意事项

  1. 替换Python路径

    FileName中的路径替换为你本机Python解释器的完整路径,例如:

    复制代码
    C:\Users\86730\AppData\Local\Programs\Python\Python310\python.exe
  2. 确保Python环境安装依赖

    确保bleak库已安装:

    复制代码
    C:\Path\To\Your\Python\python.exe -m pip install bleak
  3. 确保Python脚本路径正确
    WorkingDirectory设置为Python脚本所在目录,Arguments只写脚本名。

  4. 调试输出

    运行WPF程序时,查看输出窗口(Console)是否有Python的标准输出和错误输出,确认Python脚本是否正常启动。

  5. 蓝牙权限

    确保WPF程序有权限访问蓝牙设备,必要时以管理员身份运行。


五、总结

  • Python脚本后台线程持续采集心率数据,主线程每2秒打印格式为当前心率: 数字的字符串。
  • WPF启动Python进程,异步读取标准输出,使用正则表达式匹配并提取数字心率。
  • WPF用DispatcherTimer每2秒刷新UI显示最新心率。
相关推荐
B站_计算机毕业设计之家9 分钟前
豆瓣电影数据采集分析推荐系统 | Python Vue Flask框架 LSTM Echarts多技术融合开发 毕业设计源码 计算机
vue.js·python·机器学习·flask·echarts·lstm·推荐算法
渣渣苏17 分钟前
Langchain实战快速入门
人工智能·python·langchain
3GPP仿真实验室18 分钟前
【Matlab源码】6G候选波形:OFDM-IM 增强仿真平台 DM、CI
开发语言·matlab·ci/cd
devmoon22 分钟前
在 Polkadot 上部署独立区块链Paseo 测试网实战部署指南
开发语言·安全·区块链·polkadot·erc-20·测试网·独立链
lili-felicity22 分钟前
CANN流水线并行推理与资源调度优化
开发语言·人工智能
沐知全栈开发23 分钟前
CSS3 边框:全面解析与实战技巧
开发语言
lili-felicity26 分钟前
CANN模型量化详解:从FP32到INT8的精度与性能平衡
人工智能·python
数据知道28 分钟前
PostgreSQL实战:详解如何用Python优雅地从PG中存取处理JSON
python·postgresql·json
island131433 分钟前
CANN GE(图引擎)深度解析:计算图优化管线、内存静态规划与异构 Stream 调度机制
c语言·开发语言·神经网络
曹牧37 分钟前
Spring Boot:如何在Java Controller中处理POST请求?
java·开发语言