2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

B型リアルタイムオペレーショングラフ

Last updated at Posted at 2024-02-28

※動作検証としてMPU使用率を表示している様子
123.jpg
※ 動画 WQHD 2560x1440,自作機 MPU i5-7600K 3.80GHz

・心電図に興味を持ち同じ物を作ってみました。
 (職務上、病棟に行くのでたまに見かける)
・左から表示して行き(緑色)、一番右に達するとまた一番左に戻りデータを
 上書きして行く。
・前周のデータは見やすいように薄青に変えて履歴として表示。
・現在の値は右上に数値表示。100を超えると点滅。
・その他アイコン類は飾り。
・更新間隔を1分にすれば5時間記録されます。
・測定器等の出力値を指定するだけでリアルタイム表示が可能。
・JPGファイルは提供していないのでXAMLのjpg部は適当に要修正。
・更新速度、色等の変更は先頭のconst値を変える。

1.心電図等に利用する方法

Ga関数内の a[c++] =(int) (((int)(pc.NextValue()))*1.25); この行を修正して下さい。
・a配列にデータを順次入れて行けばグラフ化されます。
 (各種装置からのソケットデータ、DB-SELECT値を設定する等が想定される)
・左側へのリターンも自動的に行われます。
・扱う範囲は0~200なのでデータ補正またはコードを修正して下さい。

遊びで作ったこんな簡単なコードでも業者に発注、購入すると高価だったりします。

2.参考デモ A型グラフはこちら

A型は左から表示して行き、右端に達すると既存グラフを左スクロールさせて新規データは常に右に追加されて行く物、としています。
B型の方が面倒でしたが個人的にスクロールするA型が好み。

3.WPF (C#)

600ライン超えてくると重くなりますのでCANVAS.Children.Clear()が必要な様です。
初めこれ知らなくて難儀しました。

////////////////////////////////////////////////////////////////
// RealTimeOperation GRAPH TYPEB (WPF+Windows.Shapes NameSpace)
// (c) inf102 S.H 2023-2024
////////////////////////////////////////////////////////////////

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace NDMC_LOAD {

    public partial class MainWindow : Window {
        
        /////////////////////////////////////////////
        static int[] a = new int[1000]; // グラフデータ保存用

        // データ 更新間隔(mmSEC) Ex 500= 0.5Sec , 1200=1.2Sec
        const int INTER = 100;
        
        // 初回表示管理用
        static bool flg=false;

        static bool OVER=false;
        static bool sw=false;      
        
        // グラフX軸
        const int GRA=2;

        // 新規グラフと履歴部の空白幅
        const int SPACE=45;
         
        //////////////////////////////////////////////////////// グラフ部 背景色
        const int BACK_R=60;
        const int BACK_G=70;
        const int BACK_B=100;

        //////////////////////////////////////////////////////// グラフ 線
        // 新規グラフ線 太さ
        const int DATALINE = 1;

        // 新規グラフ線 色
        const int DATALINE_R=0;
        const int DATALINE_G=255;
        const int DATALINE_B=0;

        // 新規グラフ線 透過率
        const int DATALINE_A=254; // 254 == 100%

        // 履歴グラフ線 色
        const int RDATALINE_R=0;
        const int RDATALINE_G=200;
        const int RDATALINE_B=205;
        
        // 履歴グラフ線 太さ
        const int RDATALINE = 1;

        //////////////////////////////////////////////////////// 中央線
        // 中央線太さ
        const int CENTERLINE =2;

        // 中央線色
        const int CENTERLINE_R =254;
        const int CENTERLINE_G =0;
        const int CENTERLINE_B =0;    
        
        // 中央線透過率
        const int CENTERLINE_A=200;
        
        ////////////////////////////////////////////////////////        
      
        public MainWindow() {
            InitializeComponent();
        }
    
         private void Window_Loaded(object sender, RoutedEventArgs e) {

            DATA_CANVAS.Children.Clear();
            BACK_CANVAS.Children.Clear();   

            DATA_CANVAS.Background=new SolidColorBrush(Color.FromArgb(254,BACK_R,BACK_G,BACK_B));
            BACK_CANVAS.Background=new SolidColorBrush(Color.FromArgb(254,147,170,204));

            BACK_CANVAS.Children.Add(CreateText("200", 14d, Brushes.Black, 7d, -5d,   500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            BACK_CANVAS.Children.Add(CreateText("100", 14d, Brushes.Black, 7d, 87d,   500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            BACK_CANVAS.Children.Add(CreateText("0",   14d, Brushes.Black, 13d, 185d, 500.0d, 30.0d, HorizontalAlignment.Left, VerticalAlignment.Center));
            
            // 数値点滅
            Task.Run(() => Proc1());

            // MAIN LOOP
            Ga();          
        }

        private ContentControl CreateText(string text, double fontSize, Brush brush, double x, double y, double widh, double height, HorizontalAlignment hAlign, VerticalAlignment vAlign){
        
            ContentControl content = new ContentControl();
            Canvas.SetLeft(content, x);
            Canvas.SetTop(content, y);
            content.Width = widh;
            content.Height = height;

            TextBlock tb = new TextBlock();
            tb.Text = text;
            tb.FontSize = fontSize;
            tb.Foreground = brush;
            tb.HorizontalAlignment = hAlign;
            tb.VerticalAlignment = vAlign;
            content.Content = tb;

            return content;
        }

        // グラフ描画
        public async void Ga(){
            int vt=SPACE;  // 最左部分は新しい描画が入る為、2回目以降表示させないため
            PerformanceCounter pc = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);

            int c=0;
            while (true){

                // 最左から右方向へ描画
                for (int xc=0;xc<=326;xc++){

                    await Task.Delay(INTER); 
                    a[c++] =(int) (((int)(pc.NextValue()))*1.25);

                    if (c>=327 ) c=0;

                    //  Title = DATA_CANVAS.Children.Count.ToString();

                    // 右側全て描画 初回は非表示(false)
                    if (flg == true){
                        ALL(vt);
                        vt+=2; 
                    }
                    else {
                        DATA_CANVAS.Children.Clear();
                        Line line1 = new Line();
                        line1.Stroke = new SolidColorBrush(Color.FromArgb(CENTERLINE_A,CENTERLINE_R , CENTERLINE_G,CENTERLINE_B));
		                line1.X1 = 0;
		                line1.Y1 = 100;
		                line1.X2 = 652;
		                line1.Y2 = 100;
                        line1.StrokeThickness = CENTERLINE;
                        DATA_CANVAS.Children.Add(line1);
                    }

                    // 新規左側の描画
                    Ga2(xc);
                }
                vt=SPACE; 
                flg=true;
            }
        }
         
        // 先頭からshまで描画
        public void Ga2(int sh){

            int StartLine_X=0;
            int EndLine    =GRA;

            Line line1 = new Line();

            // 先頭からshまで描画
            for (int t=0;t < sh;t++){
                                      
                line1 = new Line();
                line1.SnapsToDevicePixels=true;
		        line1.X1 = StartLine_X;
		        line1.Y1 = 200-a[t];
		        line1.X2 = EndLine;
		        line1.Y2 = 200-a[t+1];

                line1.StrokeThickness = DATALINE; // 太さ
                line1.Stroke = new SolidColorBrush (Color.FromArgb(DATALINE_A,DATALINE_R,DATALINE_G,DATALINE_B));
                DATA_CANVAS.Children.Add(line1);
                
                DATA.Text=a[t].ToString();
                if (a[t] >=100 ) OVER=false; 
                else OVER=true;

                StartLine_X += GRA;
                EndLine     += GRA;
                
             }
        }

        // 履歴右部分表示
        public void ALL(int cx){
                               
            int StartLine_X =0;
            int EndLine     =GRA;
            
            DATA_CANVAS.Children.Clear();
            Line line1 = new Line();
            line1.SnapsToDevicePixels=true;
            line1.Stroke = new SolidColorBrush(Color.FromArgb(CENTERLINE_A,CENTERLINE_R , CENTERLINE_G,CENTERLINE_B));
		    line1.X1 = 0;
		    line1.Y1 = 100;
		    line1.X2 = 652;
		    line1.Y2 = 100;
            line1.StrokeThickness = CENTERLINE;
            DATA_CANVAS.Children.Add(line1);
 
            for (int t=0;t < 9999;t++){
                         
                line1 = new Line();
                line1.SnapsToDevicePixels=true;
                line1.Y1 = 200-a[t+(cx/2)];
		        line1.X1 = StartLine_X+cx-1;     //X1=100 -> t+50
		        line1.X2 = EndLine+cx-1;
		        line1.Y2 = 200-a[t+1+(cx/2)];

                line1.StrokeThickness = RDATALINE; // 太さ
                line1.Stroke = new SolidColorBrush (Color.FromArgb(DATALINE_A,RDATALINE_R,RDATALINE_G,RDATALINE_B));

                DATA_CANVAS.Children.Add(line1);
                
                if (StartLine_X+cx >= 651) break;
                
                StartLine_X += GRA;
                EndLine     += GRA;              
             }
        }

        // 数値点滅 別スレッド
        void  Proc1(){
            while (true) {
                System.Threading.Thread.Sleep (350);
               
                // 100以下
                if(OVER == true) {
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                        DATA.Foreground =new SolidColorBrush(Color.FromArgb(255,0,255,0));
                    }));
                    continue;

                }
                else{
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Foreground =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                    }));
                }

                if (sw == true){
                    sw = !sw;
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,0,0));
                    }));
                }
                else{
                    sw = !sw;
                    this.Dispatcher.Invoke((Action)(() =>{
                        DATA.Background =new SolidColorBrush(Color.FromArgb(255,0,255,0));
                    }));
                }
            }
        }
    }
}

4.WPF (XAML)

<Window x:Class="NDMC_LOAD.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NDMC_LOAD"
        mc:Ignorable="d"
        Title="リアルタイムオペレーション グラフ タイプB" Height="322" Width="860" Loaded="Window_Loaded" ResizeMode="NoResize">

    <Grid Height="319" VerticalAlignment="Top" Margin="0,1,0,0" HorizontalAlignment="Left" Width="860">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="690"/>
            <ColumnDefinition Width="121"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="212"/>
            <RowDefinition Height="55"/>
        </Grid.RowDefinitions>

        <Canvas x:Name="BACK_CANVAS" Grid.Column="0" Margin="1,0,0,0" Grid.Row="1" Grid.RowSpan="2" HorizontalAlignment="Left" Width="861" Grid.ColumnSpan="2" >
            <Rectangle  Panel.ZIndex="0"/>

        </Canvas>
        <Image Canvas.Left="777" Canvas.Top="136" Grid.Column="1" Margin="0,12,-26,23" Source="/DAT2.jpg"  Grid.RowSpan="2" Grid.Row="1" Stretch="None"/>
        <Canvas x:Name="DATA_CANVAS" Width="652" HorizontalAlignment="Left" Canvas.Left="10" Canvas.Top="10" Margin="31,0,0,0" Grid.Row="1" Height="202" VerticalAlignment="Center"  >
            <Rectangle  Panel.ZIndex="11"/>

        </Canvas>
        <Image  Grid.Column="0" Grid.ColumnSpan="2" Source="/TOP.jpg"  Height="24" VerticalAlignment="Center" Margin="1,0,-39,0"/>
        <TextBlock x:Name="DATA" Margin="53,20,-9,136" Grid.Row="1"  Foreground="Black" TextAlignment="Center"  Grid.Column="1" FontSize="43"/>
        <Image Height="42" Grid.Row="2" Grid.Column="0" Canvas.Left="147" Canvas.Top="187" VerticalAlignment="Top" Source="/DOWN.jpg" Margin="5,0,10,0"/>

    </Grid>
</Window>
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?