WPF開發隨筆收錄-心電圖曲線繪製

来源:https://www.cnblogs.com/cong2312/archive/2022/06/25/16411637.html
-Advertisement-
Play Games

一、前言 項目中之前涉及到胎兒心率圖曲線的繪製,最近項目中還需要添加心電曲線和血樣曲線的繪製功能。今天就來分享一下心電曲線的繪製方式; 二、正文 1、胎兒心率曲線的繪製是通過DrawingVisual來實現的,這裡的心電曲線我也是採用差不多相同的方式來實現的,只是兩者曲線的數據有所區別。心電圖的數據 ...


一、前言

項目中之前涉及到胎兒心率圖曲線的繪製,最近項目中還需要添加心電曲線和血樣曲線的繪製功能。今天就來分享一下心電曲線的繪製方式;

二、正文

1、胎兒心率曲線的繪製是通過DrawingVisual來實現的,這裡的心電曲線我也是採用差不多相同的方式來實現的,只是兩者曲線的數據有所區別。心電圖的數據伺服器端每秒發送至客戶端一個數據包,一個數據包鐘心電的數據大概一百個左右,看過心電圖的應該知道,心電圖的效果是勻速繪製出來的,而不是一次性將一百個點繪製出來;項目中是通過將數據存到數據緩衝區,然後通過線程定時推送數據到繪圖端,線程里會根據緩衝區現有數據量來動態控制數據的快慢;這裡的例子我就直接通過定時推數據來直接演示如何實現;

2、新建個項目,添加一個類繼承FrameworkElement,然後加上對應的數據接收和繪製功能,這裡直接貼出所有代碼,具體細節之前寫繪製高性能曲線時寫過了,不清楚的可以參考之前的;(實際上繪圖部分用Canvas實現也可以,用DrawingVisual其實每次推送了一個數據,整個視圖都重新繪製了,我之所以用這個是因為我要支持自動縮放功能)

public class EcgDrawingVisual : FrameworkElement
{
    private readonly List<Visual> visuals = new List<Visual>();
    private DrawingVisual Layer;

    private Pen ecg_pen = new Pen(Brushes.Orange, 1.5);

    private int?[] ecg_points = new int?[2000];

    private int currentStart = 0;

    private double y_offset = 0;

    private int ecg_max = 60;
    private int ecg_min = -25;

    public EcgDrawingVisual()
    {
        ecg_pen.Freeze();

        Layer = new DrawingVisual();
        visuals.Add(Layer);
    }

    public void SetupData(int ecg)
    {
        ecg_points[currentStart] = ecg;
        for (int i = 1; i <= 20; i++)
        {
            ecg_points[currentStart + i] = null;
        }

        currentStart++;
        if (currentStart >= RenderSize.Width / 2)
        {
            currentStart = 0;
        }

        DrawEcgLine();
        InvalidateVisual();
    }

    private void DrawEcgLine()
    {
        var scale = RenderSize.Height / (ecg_max - ecg_min);
        y_offset = ecg_min * -scale;

        DrawingContext dc = Layer.RenderOpen();
        Matrix mat = new Matrix();
        mat.ScaleAt(1, -1, 0, RenderSize.Height / 2);
        dc.PushTransform(new MatrixTransform(mat));

        for (int i = 0, left = 0; left < RenderSize.Width; i++, left += 2)
        {
            if (ecg_points[i] == null || ecg_points[i + 1] == null) continue;
            dc.DrawLine(ecg_pen, new Point(left, ecg_points[i].Value * scale + y_offset), new Point(left + 2, ecg_points[i + 1].Value * scale + y_offset));
        }

        dc.Pop();
        dc.Close();
    }

    protected override int VisualChildrenCount => visuals.Count;
    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        base.OnRenderSizeChanged(sizeInfo);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawRectangle(Brushes.White, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
        base.OnRender(drawingContext);
    }
}

3、主界面添加這個控制項,然後後臺添加對應的推送數據的線程,這裡我是定時每隔十毫秒推送一個數據給到繪圖端。

public partial class MainWindow : Window
{
    private List<int> points = new List<int>() { 4, 4, 3, -1, -2, -2, -2, -2, -2, -2, -2, -2, -4, -3, 25, 37, 8, -7, -5, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, 3, 5, 8, 9, 9, 10, 9, 7, 5, 1, -1, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, 1, 3 };
    private bool flag = true;
    private int currentIndex = 0;

    public MainWindow()
    {
        InitializeComponent();

        new Thread(() =>
        {
            while (flag)
            {
                Thread.Sleep(10);
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (currentIndex == points.Count) currentIndex = 0;
                    ecgDrawingVisual.SetupData(points[currentIndex]);
                    currentIndex++;
                }));
            }
        }).Start();
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        flag = false;
    }
}

4、最終實現效果

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我們在做採集數據的時候,過快或者訪問頻繁,或者一訪問就給彈出驗證碼,然後就蚌珠了~ 今天就給大家來一個簡單處理驗證碼的方法 環境模塊 本文使用的是 Python和pycharm 這裡需要用到一個 ddddocr 模塊 ,這是別人開源寫好的一個東西,簡單又好用,但是精確度差一點點,但是還是非常好用的。 ...
  • mysql服務端整體架構 主要分為兩部分,server層和存儲引擎 server層包括連接器、查詢緩存、分析器、優化器、執行器等,涵蓋mysql的大多數核心服務過功能,以及所有的內置函數,所有跨存儲引擎的功能都在這一層實現,比如存儲過程,觸發器,視圖等 存儲引擎層負責數據等存儲和讀取,其架構模式是插 ...
  • tunm二進位協議在python上的實現 tunm是一種對標JSON的二進位協議, 支持JSON的所有類型的動態組合 支持的數據類型 基本支持的類型 "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "varint", "float", "s ...
  • 迎面走來了你的面試官,身穿格子衫,挺著啤酒肚,髮際線嚴重後移的中年男子。 手拿泡著枸杞的保溫杯,胳膊夾著MacBook,MacBook上還貼著公司標語:“加班使我快樂”。 面試官: 看你簡歷上用過MySQL,問你幾個簡單的問題吧。什麼是聚簇索引和非聚簇索引? 這個問題難不住我啊。來之前我看一下一燈M ...
  • Python中的字典 Python中的字典是另一種可變容器模型,且可存儲任意類型對象。鍵值使用冒號分割,你可以看成是一串json。 常用方法 獲取字典中的值 dict[key] 如果key不存在會報錯,建議使用dict.get(key),不存在返回None 修改和新建字典值 dict[key]=va ...
  • 事情的起因是收到了一位網友的請求,他的java課設需要設計實現迷宮相關的程式——如標題概括。 我這邊不方便透露相關信息,就只把任務要求寫出來。 演示視頻指路👉: 基於JavaFX圖形界面的迷宮程式演示_嗶哩嗶哩_bilibili 完整代碼鏈接🔎: 網盤:https://pan.baidu.com ...
  • Redis 的定義? 百度百科: Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。 中文官網: Redis是一個開源(BSD許可),記憶體存 ...
  • 安裝 Redis # 首先安裝依賴gcc, 後面需要使用make編譯redis yum install gcc -y # 進入 /usr/local/src 目錄, 把源碼下載到這裡 cd /usr/local/src # 下載 redis 7.0.2 的源碼,github被牆,可以使用國內的地址 ...
一周排行
    -Advertisement-
    Play Games
  • 使用原因: 在我們服務端調用第三方介面時,如:支付寶,微信支付,我們服務端需要模擬http請求並加上一些自己的邏輯響應給前端最終達到我們想要的效果 1.使用WebClient 引用命名空間 using System.Net; using System.Collections.Specialized; ...
  • WPF 實現帶蒙版的 MessageBox 消息提示框 WPF 實現帶蒙版的 MessageBox 消息提示框 作者:WPFDevelopersOrg 原文鏈接: https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal 框架使用大於等於.N ...
  • 一、JSON(JavaScript Object Notation)的簡介: ① JSON和XML類似,主要用於存儲和傳輸文本信息,但是和XML相比,JSON更小、更快、更易解析、更易編寫與閱讀。 ② C、Python、C++、Java、PHP、Go等編程語言都支持JSON。 二、JSON語法規則: ...
  • 1.避免Scoped模式註冊的服務變成Singleton模式 當提供一個生命周期模式為Singleton的服務實例時,如果發現該服務中還依賴生命周期模式為Scoped的服務實例(Scoped服務實例將被一個Singleton服務實例所引用),那麼這個被依賴的Scoped服務實例最終會成為一個Sing ...
  • 索引時資料庫提高數據查詢處理性能的一個非常關鍵的技術,索引的使用可以對性能產生上百倍甚至上千倍的影響。接下來,會介紹索引的基本原理、概念,並深入學習資料庫中所使用的索引結構和存儲方式,以及如何管理、維護索引等。 1.索引的基本概念 索引時用來快速查詢表記錄的一種存儲結構,一般使用索引有一下兩個方面: ...
  • django2 路由控制器 Route路由,是一種映射關係。路由是把客戶端請求的url路徑和用戶請求的應用程式,這裡意指django裡面的視圖進行綁定映射的一種關係。 請求路徑和視圖函數不是一一對應的關係 在django中所有的路由最終都被保存到一個叫urlpatterns的文件里,並且該文件必須在 ...
  • 1、我們的目標是獲取微博某博主的全部圖片、視頻 2、拿到網址後 我們先觀察 打開F12 隨著下滑我們發現載入出來了一個叫mymblog的東西,展開響應發現需要的東西就在裡面 3、重點來了!!! 通過觀察發現第二頁比第一頁多了參數since_id 而第二頁的since_id參數剛好在上一頁中能獲取到, ...
  • 一、實現原理 在Servlet3協議規範中,包含在JAR文件/META-INFO/resources/路徑下的資源可以直接訪問。 二、舉例說明 如下圖所示,是我新建的一個Spring Boot Starter項目:zimug-minitor-threadpool,用於實現可配置、可觀測的線程池。其中 ...
  • 精華筆記: static final常量:應用率高 必須聲明同時初始化 由類名打點來訪問,不能被改變 建議:常量所有字母都大寫,多個單詞用_分隔 編譯器在編譯時會將常量直接替換為具體的數,效率高 何時用:數據永遠不變,並且經常使用 抽象方法: 由abstract修飾 只有方法的定義,沒有具體的實現( ...
  • Python有一個for...else語法,它的寫法如下 for i in range(0,100): if i == 3: break else: print("Not found") 該語句表示:若for迴圈遍歷完畢,則執行else部分的語句。也就是說上述代碼不會有任何輸出,而下述代碼會輸出“N ...