※動作検証としてMPU使用率を表示している様子
※ 動画 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>