本篇博客主要對 HslControls 中的曲線控件作一個詳細的教程說明,你們能夠根據下面的教程開發出高質量的曲線控件html
先從nuget下載到組件,而後就可使用組件裏的各類組件信息了。git
在Visual Studio 中的NuGet管理器中能夠下載安裝,也能夠直接在NuGet控制檯輸入下面的指令安裝:github
Install-Package HslControls
NuGet安裝教程 http://www.cnblogs.com/dathlin/p/7705014.html數據庫
demo項目的源代碼,https://github.com/dathlin/HslControlsDemodom
有一個demo程序能夠下載,地址爲 demo.zipspa
所支持的控件信息以下:設計
曲線控件先上圖,看看3d
正式開始文章以前,咱們先來看看這個曲線控件到底爲了解決什麼樣子的問題的,在工業的場景中,咱們會採集一些設備的工藝參數信息,好比鍋爐和模具溫度,鍋爐壓力,倉庫溼度,等等狀況的信息,咱們會在數據庫創建一張數據表,可能2秒鐘存儲一條數據,可能5秒鐘存儲一條數據等等,甚至可能30秒,如今咱們有數據了,須要將數據進行顯示出來,使用本控件便可以快速的開發可交互式的曲線顯示。orm
以下就是一個數據庫的示例htm
固然實際中你能夠根據本身的狀況來,不過這都無所謂,應該本控件是須要傳入處理過的數據的,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 );
固然,你不喜歡暗色主題的話,經過調整全部的顏色配置,來達到亮色的主題的話,以下的配置只是一個示例
配色的結果以下:
好了,更詳細的就參考demo項目的源代碼,https://github.com/dathlin/HslControlsDemo