C# 曲線控件 曲線繪制 實時曲線 多曲線控件 開發


Prepare


 本文將使用一個NuGet公開的組件來實現曲線的顯示,包含了多種顯示的模式和配置來滿足各種不同的應用場景,方便大家進行快速的開發系統。

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

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

Install-Package HslCommunication

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

 

 

更強大的歷史曲線控件參考:https://www.cnblogs.com/dathlin/p/10291327.html

 

Summary


曲線控件屬於組件里諸多控件中的一種,為什么單獨拿出來寫一篇博客呢,就是因為曲線控件相對於其他控件都要復雜很多,並不是幾個屬性那么簡單,下面列舉了本曲線控件的特性:

  • 提供便捷的API調用即可顯示曲線信息內容,不需要復雜的配置
  • 曲線界面的一些信息可以自由定制,比如坐標軸的顏色,是否顯示虛線等等
  • 高度的大小自適應,無論你怎么調整控件的大小,始終都能友好顯示
  • 支持數據拉伸填充和像素點填充兩種模式,具體區別參照下面的代碼
  • 多曲線支持,支持同時顯示多個曲線信息,每個曲線可獨立的指定顏色,線寬等等。
  • 支持左右兩個參考系,就是說一個控件中允許顯示2種數據跨度不一致的曲線,每種曲線可以顯示多條不同的曲線

 其他控件的說明地址:http://www.cnblogs.com/dathlin/p/8150516.html

 組件的完整API說明:http://www.cnblogs.com/dathlin/p/7703805.html

 

要想使用組件的控件,除了使用NuGet來安裝組件外,還需要將組件的dll文件(在你的項目的packages里面可以找到,如果你本來就是引用本地的,就直接拖拽本地的即可)拖拽到工具欄:

拖拽完成后效果如下:

 

 

先定義一個方法,獲取指定范圍的,指定個數的隨機數數組,供下方的代碼調用

        private float[] GetRandomValueByCount( int count, float min, float max )
        {
            float[] data = new float[count];
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = (float)random.NextDouble( ) * (max - min) + min;
            }
            return data;
        }

 

 

 

1.單曲線使用


把控件拖拽到窗口界面上去后,現在界面如下,你可以隨意的拉伸大小,調整到一個虛線看着比較清晰的時刻停止:

我們看到左右縱軸的數據跨度都是0-100,現在我們有個需求,手里有300個0-200的數據需要顯示,那么就要先設置左右縱軸的數據跨度

接下來就可以編寫顯示的代碼了,一下數據隨機:

        private void userButton1_Click( object sender, EventArgs e )
        {
            userCurve1.SetLeftCurve( "A", GetRandomValueByCount( 300, 0, 200 ), Color.DodgerBlue );
        }

 

顯示結果如下:

看吧,相當簡單方便,如果你覺得目前的數據太密了,想要寬松一點,希望數據拉伸滿整個X軸,沒問題,因為目前默認的模式是像素點模式,所以切換為拉伸模式即可。

然后在運行看看效果:

 

接下來我們要對曲線“A”進行數據更新,我們假設你的data數組的數據已經更新了,有可能只更新了一個數據,有可能全部更新了,在數據更新的時候就不需要在指定顏色了,因為指定了顏色也沒有用了。

        private void userButton3_Click( object sender, EventArgs e )
        {
            // 假設你的data數組已經更新了

            // 之前已經給A指定過顏色了,以后后續的數據更新不需要重新指定,指定了也無效
            // 如果需要重新設置顏色,或是線寬,需要先RemoveCurve,然后重新創建曲線信息
            userCurve1.SetLeftCurve( "A", GetRandomValueByCount( 300, 100, 200 ) );
        }

 

 

 

從上面的數據更新我們發現,只要更新了數據,就不停的調用數據顯示,那么我們就可以顯示實時數據了,而唯一的麻煩之處在於我們需要維護自己的data數組。所以當前的這種方式只適合靜態數據顯示

 

2.舉個經典的例子


當我們需要顯示一些統計數據的時候,比如說我要顯示十二個月的銷售金額,那么我們應該怎么寫

我們先選擇拉伸模式,然后設置拉伸模式下最大的數據量為12;

        private void userButton9_Click( object sender, EventArgs e )
        {
            // 模擬的數據
            string[] text = new string[]
            {
                "一月",
                "二月",
                "三月",
                "四月",
                "五月",
                "六月",
                "七月",
                "八月",
                "九月",
                "十月",
                "十一月",
                "十二月"
            };
            userCurve1.SetCurveText( text );
            userCurve1.SetLeftCurve( "A", GetRandomValueByCount( 12, 0, 200 ), Color.Tomato );            // 每個月用戶1的銷售金額
        }

 效果圖如下:

 

 如果我有兩條曲線需要顯示,以方便對比的話:

        private void userButton9_Click( object sender, EventArgs e )
        {
            // 模擬的數據
            string[] text = new string[]
            {
                "一月",
                "二月",
                "三月",
                "四月",
                "五月",
                "六月",
                "七月",
                "八月",
                "九月",
                "十月",
                "十一月",
                "十二月"
            };
            userCurve1.SetCurveText( text );
            userCurve1.SetLeftCurve( "A", GetRandomValueByCount( 12, 0, 200 ), Color.Tomato );            // 每個月用戶1的銷售金額
            userCurve1.SetLeftCurve( "B", GetRandomValueByCount( 12, 0, 200 ), Color.DodgerBlue );            // 每個月用戶2的銷售金額
        }

 

 圖形效果如下:

即時3條曲線或者是更多的曲線,以此類推。重復設定數據即可,只是每條曲線的關鍵字需要區分開來。

 

控件支持移除曲線,主要包含了下面的兩個方法,移除單個的曲線,或者是移除所有的曲線。

 

            userCurve1.RemoveCurve( "A" );  // 移除指定的曲線
            userCurve1.RemoveAllCurve( );   // 移除所有的曲線

 

 

 

在上面設置曲線數據的時候發現,是通過調用 SetLeftCurve 方法來設置曲線信息的,這個方法有個left單詞,很明顯是設置左曲線的,控件里還有設置右曲線的,SetLeftCurve 方法就是設置右曲線,那么這里的左右曲線都是指什么呢?

我們在上面的曲線控件上看到,縱軸的刻度線分左右兩邊,那么設置左曲線就是以左邊的刻度線為標准繪制的曲線,而設置右曲線則以右刻度線為標准,在上圖中,左右刻度的信息是一致的,所以無所謂左曲線還是右曲線,但是如果我們設置不一致后,那么我們就可以實現顯示2種不同范圍的數據信息,例如我們右曲線設置為0-10,再隨便顯示2條曲線

        private void userButton9_Click( object sender, EventArgs e )
        {
            // 模擬的數據
            string[] text = new string[]
            {
                "一月",
                "二月",
                "三月",
                "四月",
                "五月",
                "六月",
                "七月",
                "八月",
                "九月",
                "十月",
                "十一月",
                "十二月"
            };
            userCurve1.SetCurveText( text );
            userCurve1.SetLeftCurve( "A", GetRandomValueByCount( 12, 0, 200 ), Color.Tomato );            // 每個月用戶1的銷售金額
            userCurve1.SetLeftCurve( "B", GetRandomValueByCount( 12, 0, 200 ), Color.DodgerBlue );            // 每個月用戶2的銷售金額

            userCurve1.SetRightCurve( "C", GetRandomValueByCount( 12, 3, 6 ), Color.LimeGreen );
            userCurve1.SetRightCurve( "D", GetRandomValueByCount( 12, 3, 6 ), Color.Orchid );
        }

 效果圖如下:

 

高級使用舉例,動態坐標軸

根據上面的情況,我們看到如果我們獲取到的一組數據,范圍不確定的,需要來動態調整的,比如我們有一個12個數據的float數組,我們設置左坐標軸為數據的上下限

        private void userButton10_Click( object sender, EventArgs e )
        {
            // 模擬的數據
            string[] text = new string[]
            {
                "一月",
                "二月",
                "三月",
                "四月",
                "五月",
                "六月",
                "七月",
                "八月",
                "九月",
                "十月",
                "十一月",
                "十二月"
            };

            float[] data = GetRandomValueByCount( 12, 40, 150 );
            userCurve1.ValueMaxLeft = (float)Math.Ceiling( data.Max( ) );// 向上取整
            userCurve1.ValueMinLeft = (float)Math.Floor( data.Min( ) );// 向下取整

            userCurve1.SetCurveText( text );
            userCurve1.SetLeftCurve( "A", data, Color.Tomato );            // 每個月用戶1的銷售金額
        }

 效果圖如下:

可以看到,不停的刷新數據后,左坐標軸的數據一直在更新中。

 

 

 總結下:如果每次都是強行更新所有的數據,也能達到實時刷新的效果,但是如果是一個數據一個數據的采集顯示,將按照下面的實時數據模式使用更加合理

 

3.實時數據顯示使用


當我們需要顯示一些實時數據時,也就是說,每隔1秒(隨便舉個栗子)就有新的數據采集上來,然后追加到曲線中去,曲線進行挪動,通常就是這種情況。

3.1 像素點模式(請確認 IsAbscissaStrech 為False):

我們先講解默認的模式,所謂像素點模式是指在橫軸上,一個像素點顯示一個數據,如果你的橫軸像素長度為1000,那么你就可以顯示1000個數據了,當然在實時顯示的情況下,不需要你管那么多,你只需要負責定期往里面塞數據即可。

第一步先進行初始化:先增加指定名字的曲線信息,曲線顏色,曲線寬度等等

        private void userButton4_Click( object sender, EventArgs e )
        {
            // 這里傳入了數組長度為空的數據,不能傳NULL
            userCurve1.SetLeftCurve( "B", new float[] { }, Color.Tomato );
        }

我們再寫一個按鈕,啟動定時器,去新增數據,來模擬我們從其他設備讀取到的數據信息:

        private void userButton5_Click( object sender, EventArgs e )
        {
            Timer timer = new Timer( );
            timer.Interval = 100;
            timer.Tick += ( sender1, e1 ) =>
            {
                userCurve1.AddCurveData( "B", random.Next( 50, 201 ) );
            };
            timer.Start( );
        }

如上面的兩個按鈕信息,必須先點擊按鈕4進行曲線初始化,按鈕5的點擊才有效果。最終你會看到曲線每隔100ms刷新一次,不停的有新的數據遞增。

當曲線數量超過當前可顯示的點數時,曲線會自動的往左挪動,即時你拉伸的整個控件,它依然可以正常的工作,可顯示的數據點數會自動更新,內存中會緩存2048個數據點來支持拉伸的效果轉換。

 

當然,它也支持一次更新多個數據,雖然這種情況很少,只是需要注意的是,一次更新的數據必須少於2048。

userCurve1.AddCurveData( "B", new float[] { random.Next( 50, 201 ), random.Next( 50, 201 ), random.Next( 50, 201 ) } );

 

 

 

2.2 拉伸模式(請確認 IsAbscissaStrech 為True):

拉伸模式的意思是無論你的data數組有多少個點,都強行按照最大數據點拉伸完整個橫軸界面

先設置 StrechDataCountMax 屬性為 300 ,意思是強行顯示300個點,最大300個點,僅僅在拉伸模式下有效果

        private void userButton4_Click( object sender, EventArgs e )
        {
            // 這里傳入了數組長度為空的數據,不能傳NULL
            userCurve1.SetLeftCurve( "B", new float[] { }, Color.Tomato); // 指定上限500個數據,該上限只對拉伸模式有效
        }

        private void userButton5_Click( object sender, EventArgs e )
        {
            Timer timer = new Timer( );
            timer.Interval = 100;
            timer.Tick += ( sender1, e1 ) =>
            {
                userCurve1.AddCurveData( "B", random.Next( 50, 201 ) );
            };
            timer.Start( );
        }

我們再看拉伸模式的曲線:

你再拉伸控件試試看?拉伸模式的意思是無論你的控件多少大小,你規定了300個點,它就是300個點,即使你的控件拉伸了,它還是300個點,只是沒有那么密罷了

至於一次增加多個數據是和上面的像素點模式是一致的。

 

2.3 模式區別及選擇

像素點模式下,隨便看着數據比較密,但是好處在於分辨率高的顯示器,可以顯示的數據更多。

拉伸模式雖然在控件拉伸的情況下顯示的數據量不會增長,但是可以控制疏密程度。

各有優劣,建議先使用像素點模式,看看效果怎么樣,一般數據變化都是慢慢來的,所以曲線不會像測試數據那樣亂串。如果數據亂串比較厲害,再使用拉伸模式。

 

 

3.多曲線,雙坐標使用


多曲線和單曲線模式很相似,無非是多幾條曲線而已,每條曲線的操作,新增數據都是一模一樣的,只是多曲線的模式都是統一的,要么全部是像素點模式,要么全部是拉伸模式,所有的特性和上兩節是相似的。

為了說明使用,舉個例子,你有多個設備(2個及以上),每個設備都有一個溫度信息,現在要進行實時數據的直接對比,當然最好將三條曲線放到一起顯示。

我們命名三個曲線為“A”,“B”,“C” 然后假設所有的數據都是100-200之間,數據A是160-180隨機,數據B是150-170隨機,數據C是155-165隨機

此處測試方便,使用了 像素點模式。在 拉伸模式 下代碼也是一致的              

 

我們接下來看一種相當復雜的使用場景,假設我們有一台設備,需要監控4條曲線,2條溫度,2條壓力,溫度的范圍是0-200,壓力的范圍為0-5 mpa,那么想要在一個控件里顯示,也是可以實現的。先調整左右的坐標范圍。

 

此處仍然使用像素點模式,我們接下來寫初始化代碼和新增數據的代碼:

        private void userButton4_Click( object sender, EventArgs e )
        {
            userCurve1.SetLeftCurve( "A", new float[] { }, Color.Tomato );            // 溫度1
            userCurve1.SetLeftCurve( "B", new float[] { }, Color.DodgerBlue );        // 溫度2
            userCurve1.SetRightCurve( "C", new float[] { }, Color.LimeGreen );         // 壓力1
            userCurve1.SetRightCurve( "D", new float[] { }, Color.Purple );            // 壓力2
        }

        private void userButton5_Click( object sender, EventArgs e )
        {
            Timer timer = new Timer( );
            timer.Interval = 100;
            timer.Tick += ( sender1, e1 ) =>
            {
                userCurve1.AddCurveData(
                    new string[] { "A", "B", "C", "D" },
                    new float[] { random.Next( 160, 181 ), random.Next( 150, 171 ), (float)random.NextDouble( ) * 2.5f + 1, (float)random.NextDouble( ) * 1f } );
            };
            timer.Start( );
        }

 

 

效果如下圖:

 

 

4.橫坐標文本格式調整


上述的實時曲線在顯示的時候,我們看到橫坐標的文本是小時加分鍾的模式,如果我們改成只顯示分鍾和秒鍾怎么辦

這個屬性就是DateTime的格式化字符串,理論上你可以獲取到任務時間相關的文本信息,按照當前的需求,調整成 mm:ss 即可

 

5.輔助線添加


我想在實時數據顯示中設置一條曲線數據的報警上限的輔助線,用來提醒以及更加至關的查看信息,是否異常,可以調用控件的方法來完成

新增的輔助線是左右兩個參考坐標系區分出來了,比如我新增左輔助線,192的一條線,顏色為紅色

userCurve1.AddLeftAuxiliary( 192, Color.Red);

 移除的代碼為

userCurve1.RemoveAuxiliary( 192 );

 輔助線效果如下:

如果你新增的輔助線和原有的虛線重疊時,原有的虛線會自動屏蔽掉。

 

6.背景顏色調整


我修改下背景為暗黑色,瞬間就有黑科技的效果了。當然,線條的顏色可以調整的更加好一點

 

 

 

4.結束語


感謝閱讀。

 


免責聲明!

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



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