C# 歷史曲線控件 基於時間的曲線控件 可交互的高級曲線控件 HslControls曲線控件使用教程


本篇博客主要對 HslControls 中的曲線控件做一個詳細的教程說明,大家可以根據下面的教程開發出高質量的曲線控件

 
聯系作者及加群方式(激活碼在群里發放):http://www.hslcommunication.cn/Cooperation 

Prepare


先從nuget下載到組件,然后就可以使用組件里的各種組件信息了。

 

在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制台輸入下面的指令安裝:

Install-Package HslControls

  

NuGet安裝教程  http://www.cnblogs.com/dathlin/p/7705014.html

 

Demo


 

demo項目的源代碼,https://github.com/dathlin/HslControlsDemo

有一個demo程序可以下載,地址為 demo.zip

所支持的控件信息如下:

pic1

曲線控件先上圖,看看

pic2

 

 

適用場景


 

正式開始文章之前,我們先來看看這個曲線控件到底為了解決什么樣子的問題的,在工業的場景中,我們會采集一些設備的工藝參數信息,比如鍋爐和模具溫度,鍋爐壓力,倉庫濕度,等等情況的信息,我們會在數據庫建立一張數據表,可能2秒鍾存儲一條數據,可能5秒鍾存儲一條數據等等,甚至可能30秒,現在我們有數據了,需要將數據進行顯示出來,使用本控件即可以快速的開發可交互式的曲線顯示。

如下就是一個數據庫的示例

 

曲線顯示


 當然實際中你可以根據自己的情況來,不過這都無所謂,應該本控件是需要傳入處理過的數據的,ok,我們現在界面上拖一個控件

 

先調整兩側坐標軸的,比如溫度的范圍是0-250,壓力的范圍是0-5,我們就調整這個控件的屬性來實現功能

還可以調整分割線的情況,我們調整成如下的數據

然后顯示如下:

 

 我們再調整下文字,設置為空,在新增一個按鈕,點擊的時候就要去數據庫查詢數據了,由於查詢的時間不定,需要花費一些時間,我們還需要進行友好的提示信息,比如正在查詢數據...

 

然后我們完善代碼

        private void button1_Click( object sender, EventArgs e )
        {
            hslCurveHistory1.Text = "正在加載數據...";
            hslCurveHistory1.RemoveAllCurve( );
            new Thread( new ThreadStart( ThreadReadExample1 ) ) { IsBackground = true }.Start( );
        }

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

        private Random random = new Random( );

此處只有一條曲線,橫軸還沒設置,這已經是最簡單的曲線顯示了,而且支持按鈕多次重復點擊,不會發生數據疊加。效果如下:

 

當光標移動的時候,還會提示當前的光標所在位置的數據信息,目前所具備的功能還是比較簡單的,我們從數據庫獲取到數據,通常還包含了時間軸,此處就要傳入同等數量長度的時間軸信息

注意,時間軸是隨着時間逐漸增加的信息,確保是單向增加的。

所以我們的代碼改成如下:

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.RenderCurveUI( );// 所有的曲線設置好后,調用這個方法統一顯示曲線信息,這樣的設計可以有效的避免閃爍的問題
            } ) );
        }

  

這時候的效果已經改變了。最下面已經多了一個時間的信息顯示。

這時候我們在圖形的任意區域點擊鼠標左鍵,然后移動鼠標,然后再松開鼠標左鍵就會發生填充輔助曲線信息

 

這時候可以多次的重復操作,可以標記多個圖形信息。

如果想要清除上面的所有的數據信息,怎么辦?右鍵點擊下圖形的任意界面,所有的輔助曲線就不存在了。

 

 

接下來我們再增加一條曲線,壓力相關的,再看看效果。

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            float[] press = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "壓力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

效果如下:

 

假設我還有個步序的信息,只想在曲線里提示出來,但是不想顯示步序曲線,應該怎么操作呢

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "壓力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不顯示曲線信息
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

  

這樣之后我們就可以顯示步序的提示信息,但是不顯示步序的曲線。

這里有個小問題,如果我希望步序顯示順序在最上面怎么辦?或者是這里的提示信息是根據什么順序來排序的?

答案是曲線的添加順序,我們只需要調整曲線添加的順序即可。如下:

                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "壓力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不顯示曲線信息
                hslCurveHistory1.RenderCurveUI( );

  

 

 

到這里為止,曲線控件的簡單應用已經差不多了,已經實現了一般的情況的應用了。接下來就是比較高級的操作了。

 

高級操作


 

 

 在高級的操作之前,需要先普及個概念,貫穿於這個曲線控件的所有的部分。這個概念就是數據點位的信息,比如我們有2000個數據,那么數據點位就是0-1999,在圖形上顯示不一定是0-1999的位置,存在一個縮放的等級,默認縮放等級是1,也就是說0-1999就是0-1999,如果我們的縮放等級調整為2,那么就是放大,0-1999對應 0-3998,如果縮放等級為0.5,那么就是縮小一倍,0-1999對應0-999

 

單位顯示


 

顯示單位的信息

這樣就可以在圖形里顯示

 

 

隱藏右坐標


 

如果我們想要隱藏右坐標軸信息,可以設置下面的屬性

 

將這個值設置為 False 后,就不顯示右坐標了,如下:

 

 

 

輔助線功能

如果我們需要標記一段特殊的虛線,可以是報警的分界線,也可以是重點的線。操作如下:在窗體的載入中添加如下的代碼即可

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f );
        }

  

效果如下:

 

當然我們也可以指定顏色

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
        }

  

 

 當然也可以添加右曲線信息

 

縮放功能


 

如果你覺得目前的數據點位太多了,曲線太長了,可以進行縮小,那么可以設置縮放等級,在窗口載入的時候設置一次即可。

 

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
            hslCurveHistory1.SetScaleByXAxis( 0.5f );
        }

  

 

 

 接下來我們看看縮放等級設置為4的效果

 

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
            hslCurveHistory1.SetScaleByXAxis( 4f );
        }

  

 

 

 

 

數據點標注操作


 

 我們現在有個需求,我們有了曲線以后,可能對其中的某個或是多個特殊的點進行文本標注,本控件支持這樣的操作,以及標注不同的顏色的信息

hslCurveHistory1.AddMarkText( new HslControls.HslMarkText( )
                {
                    Index = 200,
                    CurveKey = "溫度",
                    MarkText = "標注信息",
                    CircleBrush = Brushes.DodgerBlue,
                    TextBrush = Brushes.Blue
                } );
                hslCurveHistory1.RenderCurveUI( );

當然也可以指定文本的方向,如果想要清除,那么調用

            hslCurveHistory1.RemoveAllMarkText( );
            hslCurveHistory1.RenderCurveUI( );

  

 

 

 

數據線標注操作


 我們現在又有個需求,需要對曲線里的一個區域畫線標注出來。並且可以再標注點信息

                 // 增加一個三角形的線段標記示例 Points的每個點的X是數據索引,Y是數據值(需要選對參考坐標軸,默認為左坐標軸)
                 hslCurveHistory1.AddMarkLine( new HslControls.HslMarkLine( )
                 {
                     CircleBrush = Brushes.DodgerBlue,
                     IsLeftFrame = true,
                     IsLineClosed = true,
                     LinePen = Pens.DodgerBlue,
                     TextBrush = Brushes.DodgerBlue,
                     Points = new PointF[]
                     {
                         new PointF(200, 180f), new PointF(260, 20f), new PointF(550, 150f),
                     },
                     Marks = new string[] { "AA", "BB", "CC" },
                 } );

效果如下:

 

 

 

背景標識操作


 

 我們現在有個需求,我們有了步序之后就可以分析出曲線對應的產品信息,比如分析出點位是從1000點開始到1300點結束的,是一個產品,條碼是 K1234567890 ,現在要在曲線里顯示出來。我們來看看如果通過代碼實現

 我們先調整為正常的縮放等級,也就是1f,

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "壓力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不顯示曲線信息


                HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
                {
                    StartIndex = 1000,
                    EndIndex = 1300,
                    MarkText = "K1234567890",
                };
                hslCurveHistory1.AddMarkBackSection( backSection );


                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

        private Random random = new Random( );

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
        }

  

代碼上來說,就是新增一個 backSection 對象,至於1000和1300怎么分析出來的,就是要自己寫代碼實現了,簡單的說,通過遍歷數據,前后對比可以實現。運行效果如下:

 

可以清楚的看到有一個顏色稍微淡一點點的標記層,如果你的縮放等級是0.5,那么這個陰影的寬度會減少一半,這都是自動適應的。

當然你也可以添加多個背景的標記,如果想要清除標記,只能調用清除所有曲線的方法,

如下是縮放等級為0.5的情況

 

 

區間標識操作


 我們現在有另外的需求,需要標記某些特殊的區間,比如某個區間發生了報警,例如區間 600-700發生了報警,內容為“溫度超標了”;應該怎么操作

        private void ThreadReadExample1( )
        {
            // 模擬下查詢時間
            Thread.Sleep( 2000 );
           
            // 這里數據數據,實際應該是你的真實的數據
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 顯示出數據信息來
            Invoke( new Action( ( ) =>
            {
                // 設置曲線屬性,名稱,數據,顏色,是否平滑,格式化顯示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "溫度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "壓力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不顯示曲線信息


                HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
                {
                    StartIndex = 1000,
                    EndIndex = 1300,
                    MarkText = "K1234567890",
                };
                hslCurveHistory1.AddMarkBackSection( backSection );

                HslControls.HslMarkForeSection foreSection = new HslControls.HslMarkForeSection( )
                {
                    StartIndex = 600,
                    EndIndex = 800,
                    StartHeight = 0.3f,         // 如果值是(0-1)的話,表示的是位置百分比,0.9就是曲線高度為90%,從上往下看的視角,如果填了600,那就是絕對坐標
                    Height = 0.9f,              // 和上面同理
                    LinePen = Pens.Chocolate,   // 指定顏色
                    IsRenderTimeText = false,   // 是否顯示額外的起始時間和結束時間,此處就不要了
                    MarkText = "溫度超標了",
                };
                hslCurveHistory1.AddMarkForeSection( foreSection );

                hslCurveHistory1.RenderCurveUI( );  // 將曲線顯示出來
            } ) );
        }

  

  如上圖,我們完成了標記信息的添加,上述 的幾個屬性,你可以修改試試看,然后運行看看效果。上述的效果如下:

 

當然了,文字的顏色也可以設定的,用於不同功能的區段的提醒,這個區段也是支持自動的縮放的。

 

 

雙擊曲線操作


如果你想捕獲鼠標雙擊曲線的事件,獲取到數據的索引或是實際的時間信息,好進行一些額外的操作,比如打印雙擊時間附近的曲線,生成報告單之類的情況,就顯得很有用了。那么應該怎么做呢?

在這個事件里雙擊生成事件即可。

        private void hslCurveHistory1_onCurveDoubleClick( HslControls.HslCurveHistory hslCurve, int index, DateTime dateTime )
        {
            MessageBox.Show( $"Index: {index} Time:{dateTime.ToString( )}" );
        }

自然會生成上述的代碼,其中index就是數據索引,和圖形的縮放是自動適應的,還有時間信息,也是可以一並獲取到的,可以進行額外的處理。

 

兩個曲線控件同步操作


如果你有個需求。有兩個曲線控件,時間軸是一模一樣的,想要鼠標挪動的時候,讓另一個曲線也跟着動,或是互相一起動,再或是是光標也實現一起運動,這東西解釋起來比較復雜,先上效果圖:

 

首先我先放兩個控件,曲線1和曲線2,如果想讓曲線2跟隨曲線1移動

hslCurveHistory1.Scroll += (sender1 , e1) => hslCurveHistory2.SetScrollPosition( e1 );

如果想要實現互相跟隨

hslCurveHistory1.Scroll += (sender1 , e1) => hslCurveHistory2.SetScrollPosition( e1 );
hslCurveHistory2.Scroll += ( sender1, e1 ) => hslCurveHistory1.SetScrollPosition( e1 );

  

光標移動也是同理,互相移動參考如下:

hslCurveHistory1.onCurveMouseMove += ( curve, x, y ) => hslCurveHistory2.SetCurveMousePosition( x, y );
hslCurveHistory2.onCurveMouseMove += ( curve, x, y ) => hslCurveHistory1.SetCurveMousePosition( x, y );

  

 

 

主題調整操作


 

當然,你不喜歡暗色主題的話,通過調整所有的顏色配置,來達到亮色的主題的話,如下的配置只是一個示例

配色的結果如下:

pic100

 

 

 

好了,更詳細的就參考demo項目的源代碼,https://github.com/dathlin/HslControlsDemo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM