WPF开发随笔收录-WriteableBitmap绘制高性能曲线图

打印 上一主题 下一主题

主题 884|帖子 884|积分 2652

一、前言

之前分享过一期关于DrawingVisual来绘制高性能曲线的博客,今天再分享一篇通过另一种方式来绘制高性能曲线的方法,也就是通过WriteableBitmap的方式;具体的一些细节这里就不啰嗦了,同样是局部绘制的思想,滚动条拖动到哪里,就只绘制那一部分的曲线,直接贴代码;(该程序在英特尔11代CPU的电脑可能会遇到拖动滚动条曲线图卡住不动的情况,这个是显卡驱动的问题,官方已经修复了,遇到这问题的记得更新一下驱动)
二、正文

1、新建一个类,继承FrameworkElement,然后在里面实现一下绘图的逻辑;
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Drawing.Drawing2D;
  5. using System.Drawing.Text;
  6. using System.IO;
  7. using System.Windows;
  8. using System.Windows.Media;
  9. using System.Windows.Media.Imaging;
  10. using System.Windows.Resources;
  11. using _Font = System.Drawing.Font;
  12. using GDI = System.Drawing;
  13. namespace WriteableBitmapDemo.Controls
  14. {
  15.     public class CruveWriteableBitmap : FrameworkElement
  16.     {
  17.         private static PrivateFontCollection pfc = new PrivateFontCollection();
  18.         private WriteableBitmap bitmap;
  19.         private int bitmap_width = 0;
  20.         private int bitmap_height = 0;
  21.         private static _Font font = null;
  22.         private static _Font time_font = null;
  23.         private PointF[][] horizontals = null;
  24.         private PointF[][] horizontals_thin = null;
  25.         private PointF[][] verticals = null;
  26.         private PointF[][] verticals_thin = null;
  27.         private List<PointF> top_points1;
  28.         private List<PointF> top_points2;
  29.         private List<PointF> top_points3;
  30.         private List<PointF> bottom_points;
  31.         private List<PointF> labelPosition_up;
  32.         private List<string> labelText_up;
  33.         private List<PointF> labelPosition_down;
  34.         private List<string> labelText_down;
  35.         private List<PointF> timePosition;
  36.         private List<string> timeText;
  37.         private GDI.Pen blackPen = new GDI.Pen(GDI.Color.Black, 1.5f);
  38.         private GDI.Pen grayPen = new GDI.Pen(GDI.Color.Gray, 1f);
  39.         private GDI.Pen top_pen1 = new GDI.Pen(GDI.Color.Black, 2);
  40.         private GDI.Pen top_pen2 = new GDI.Pen(GDI.Color.Orange, 2);
  41.         private GDI.Pen top_pen3 = new GDI.Pen(GDI.Color.Purple, 2);public float scaleX { get; set; } = 1f;
  42.         private float _ScaleY { get; set; } = 1f;
  43.         public float ScaleY
  44.         {
  45.             get { return _ScaleY; }
  46.             set
  47.             {
  48.                 _ScaleY = value;
  49.             }
  50.         }
  51.         static CruveWriteableBitmap()
  52.         {
  53.             var appRootDataDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "msyh.ttf");
  54.             if (!File.Exists(appRootDataDir))
  55.             {
  56.                 var key = $"/CurveChartDemo;component/Fonts/msyh.ttf";
  57.                 StreamResourceInfo info = Application.GetResourceStream(new Uri(key, UriKind.Relative));
  58.                 using (var stream = info.Stream)
  59.                 {
  60.                     byte[] bytes = new byte[stream.Length];
  61.                     int len = stream.Read(bytes, 0, bytes.Length);
  62.                     File.WriteAllBytes(appRootDataDir, bytes);
  63.                 }
  64.             }
  65.             pfc.AddFontFile(appRootDataDir);
  66.         }
  67.         public CruveWriteableBitmap()
  68.         {
  69.             time_font = new _Font(pfc.Families[0], 10);
  70.             font = new _Font(pfc.Families[0], 8);
  71.         }
  72.         public void DrawPoints()
  73.         {
  74.             //InitBitmap();
  75.             if (this.bitmap == null)
  76.             {
  77.                 return;
  78.             }
  79.             this.bitmap.Lock();
  80.             using (Bitmap backBufferBitmap = new Bitmap(this.bitmap_width, this.bitmap_height,
  81.                 this.bitmap.BackBufferStride, GDI.Imaging.PixelFormat.Format24bppRgb,
  82.                 this.bitmap.BackBuffer))
  83.             {
  84.                 using (Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap))
  85.                 {
  86.                     backBufferGraphics.SmoothingMode = SmoothingMode.AntiAlias;
  87.                     backBufferGraphics.CompositingQuality = CompositingQuality.HighSpeed;
  88.                     backBufferGraphics.Clear(GDI.Color.White);
  89.                     //粗横线
  90.                     if (this.horizontals != null)
  91.                     {
  92.                         foreach (var horizontal in this.horizontals)
  93.                         {
  94.                             backBufferGraphics.DrawLine(blackPen, horizontal[0], horizontal[1]);
  95.                         }
  96.                     }
  97.                     //细横线
  98.                     if (this.horizontals_thin != null)
  99.                     {
  100.                         foreach (var horizontal in this.horizontals_thin)
  101.                         {
  102.                             backBufferGraphics.DrawLine(grayPen, horizontal[0], horizontal[1]);
  103.                         }
  104.                     }
  105.                     //粗竖线
  106.                     if (this.verticals != null)
  107.                     {
  108.                         foreach (var vertical in this.verticals)
  109.                         {
  110.                             backBufferGraphics.DrawLine(blackPen, vertical[0], vertical[1]);
  111.                         }
  112.                     }
  113.                     //细竖线
  114.                     if (this.verticals_thin != null)
  115.                     {
  116.                         foreach (var vertical in this.verticals_thin)
  117.                         {
  118.                             backBufferGraphics.DrawLine(grayPen, vertical[0], vertical[1]);
  119.                         }
  120.                     }
  121.                     //上图曲线1
  122.                     if (this.top_points1 != null && this.top_points1.Count > 0)
  123.                     {
  124.                         backBufferGraphics.DrawLines(top_pen1, top_points1.ToArray());
  125.                     }
  126.                     //上图曲线2
  127.                     if (this.top_points2 != null && this.top_points2.Count > 0)
  128.                     {
  129.                         backBufferGraphics.DrawLines(top_pen2, this.top_points2.ToArray());
  130.                     }
  131.                     //上图曲线3
  132.                     if (this.top_points3 != null && this.top_points3.Count > 0)
  133.                     {
  134.                         backBufferGraphics.DrawLines(top_pen3, this.top_points3.ToArray());
  135.                     }
  136.                     //下图曲线
  137.                     if (this.bottom_points != null && this.bottom_points.Count > 0)
  138.                     {
  139.                         backBufferGraphics.DrawLines(top_pen1, this.bottom_points.ToArray());
  140.                     }
  141.                     //文本
  142.                     if (labelPosition_up != null && labelPosition_up.Count > 0)
  143.                     {
  144.                         SizeF fontSize = backBufferGraphics.MeasureString(labelText_up[0], font);
  145.                         for (int i = 0; i < labelPosition_up.Count; ++i)
  146.                         {
  147.                             backBufferGraphics.DrawString(labelText_up[i], font, GDI.Brushes.Black, labelPosition_up[i].X, labelPosition_up[i].Y - fontSize.Height);
  148.                         }
  149.                     }
  150.                     if (labelPosition_down != null && labelPosition_down.Count > 0)
  151.                     {
  152.                         for (int i = 0; i < labelPosition_down.Count; ++i)
  153.                         {
  154.                             backBufferGraphics.DrawString(labelText_down[i], font, GDI.Brushes.Black, labelPosition_down[i].X, labelPosition_down[i].Y);
  155.                         }
  156.                     }
  157.                     if (timePosition != null && timePosition.Count > 0)
  158.                     {
  159.                         for (int i = 0; i < timePosition.Count; ++i)
  160.                         {
  161.                             if (i == 0)
  162.                                 backBufferGraphics.DrawString(timeText[i], time_font, GDI.Brushes.Black, timePosition[i].X, timePosition[i].Y);
  163.                             else
  164.                             {
  165.                                 SizeF fontSize = backBufferGraphics.MeasureString(timeText[i], time_font);
  166.                                 backBufferGraphics.DrawString(timeText[i], time_font, GDI.Brushes.Black, timePosition[i].X - fontSize.Width / 2, timePosition[i].Y);
  167.                             }
  168.                         }
  169.                     }
  170.                     backBufferGraphics.Flush();
  171.                 }
  172.             }
  173.             this.bitmap.AddDirtyRect(new Int32Rect(0, 0, this.bitmap_width, this.bitmap_height));
  174.             this.bitmap.Unlock();
  175.         }public void UpdateTimeLabel(List<PointF> timePosition, List<string> timeText)
  176.         {
  177.             this.timePosition = timePosition;
  178.             this.timeText = timeText;
  179.         }
  180.         public void UpdatePosition(List<PointF> fhr1_points, List<PointF> fhr2_points, List<PointF> fhr3_points, List<PointF> toco_points)
  181.         {
  182.             this.top_points1 = fhr1_points;
  183.             this.top_points2 = fhr2_points;
  184.             this.top_points3 = fhr3_points;
  185.             this.bottom_points = toco_points;
  186.         }
  187.         public void UpdateLabelPosition(List<PointF> labelPosition_up, List<string> labelText_up, List<PointF> labelPosition_down, List<string> labelText_down)
  188.         {
  189.             this.labelPosition_up = labelPosition_up;
  190.             this.labelText_up = labelText_up;
  191.             this.labelPosition_down = labelPosition_down;
  192.             this.labelText_down = labelText_down;
  193.         }
  194.         public void UpdateHorizontalLine(PointF[][] horizontals, PointF[][] horizontals_thin)
  195.         {
  196.             this.horizontals = horizontals;
  197.             this.horizontals_thin = horizontals_thin;
  198.         }
  199.         public void UpdateVerticalLine(PointF[][] verticals, PointF[][] verticals_thin)
  200.         {
  201.             this.verticals = verticals;
  202.             this.verticals_thin = verticals_thin;
  203.         }
  204.         protected override void OnRender(DrawingContext dc)
  205.         {
  206.             InitBitmap();
  207.             if (this.bitmap != null)
  208.             {
  209.                 dc.DrawImage(bitmap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
  210.             }
  211.             base.OnRender(dc);
  212.         }
  213.         private void InitBitmap()
  214.         {
  215.             if (bitmap == null || this.bitmap.Width != (int)this.ActualWidth || this.bitmap.Height != (int)this.ActualHeight)
  216.             {
  217.                 if ((int)this.ActualWidth > 0 && (int)this.ActualHeight > 0)
  218.                 {
  219.                     this.bitmap_width = (int)this.ActualWidth;
  220.                     this.bitmap_height = (int)this.ActualHeight;
  221.                     this.bitmap = new WriteableBitmap(bitmap_width, bitmap_height, 96, 96, PixelFormats.Bgr24, null);
  222.                     this.bitmap.Lock();
  223.                     using (Bitmap backBufferBitmap = new Bitmap(bitmap_width, bitmap_height,
  224.                         this.bitmap.BackBufferStride, GDI.Imaging.PixelFormat.Format24bppRgb,
  225.                         this.bitmap.BackBuffer))
  226.                     {
  227.                         using (Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap))
  228.                         {
  229.                             backBufferGraphics.SmoothingMode = SmoothingMode.HighSpeed;
  230.                             backBufferGraphics.CompositingQuality = CompositingQuality.HighSpeed;
  231.                             backBufferGraphics.Clear(GDI.Color.White);
  232.                             backBufferGraphics.Flush();
  233.                         }
  234.                     }
  235.                     this.bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap_width, bitmap_height));
  236.                     this.bitmap.Unlock();
  237.                 }
  238.             }
  239.         }
  240.     }
  241. }
复制代码
2、主窗口添加该控件,并添加滚动条那些
  1. <Window
  2.     x:Class="WriteableBitmapDemo.MainWindow"
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5.     xmlns:ct="clr-namespace:WriteableBitmapDemo.Controls"
  6.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7.     xmlns:local="clr-namespace:WriteableBitmapDemo"
  8.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  9.     Title="MainWindow"
  10.     Width="1500"
  11.     Height="450"
  12.     Loaded="Window_Loaded"
  13.     mc:Ignorable="d">
  14.     <Grid>
  15.         <ct:CruveWriteableBitmap x:Name="curve" Margin="0,0,0,20" />
  16.         <ScrollViewer
  17.             Name="scroll"
  18.             HorizontalScrollBarVisibility="Auto"
  19.             ScrollChanged="ScrollViewer_ScrollChanged"
  20.             VerticalScrollBarVisibility="Disabled">
  21.             <Canvas x:Name="canvas" Height="1" />
  22.         </ScrollViewer>
  23.         <Canvas
  24.             x:Name="CanvasPanel"
  25.             Margin="0,0,0,20"
  26.             Background="Transparent" />
  27.     </Grid>
  28. </Window>
复制代码
3、主窗口后台添加曲线数值生成方法和更新视图数据方法
[code]using System.Collections.Generic;using System.Drawing;using System.Windows;using System.Windows.Controls;using System.Windows.Input;namespace WriteableBitmapDemo{    ///     /// MainWindow.xaml 的交互逻辑    ///     public partial class MainWindow : Window    {        private bool isAdd = true;        private Dictionary dicTopPoints = new Dictionary();        private Dictionary dicBottomPoints = new Dictionary();        private float y_scale;        private static int Top_Val_Max = 240;        private static int Top_Val_Min = 30;        private static int Top_X_Sex = 20;        private static int Bottom = 100;        private static int Center = 25;        private static int BottomOffset = 0;        private double offset = -1;        public MainWindow()        {            InitializeComponent();            CanvasPanel.MouseMove += delegate (object sender, MouseEventArgs e)            {                if (e.LeftButton == MouseButtonState.Pressed)                {                    if (Mouse.Captured == null) Mouse.Capture(CanvasPanel);                    if (offset >= 0 && offset
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

水军大提督

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表