關於ZedGraph幾個難點


1.引言

由於工作原因,需要對數據進行圖表展示,.NET默認的控件庫或者DotNetBar的控件庫又不能滿足需求。去網上找到了這個開源的ZedGraph繪制2D圖表的程序集,之所以選擇這個ZedGraph程序集,一來它能夠滿足業務需求,二來它網上相關資料很多,三來它是開源代碼。本篇中主要是給大家介紹幾個我在開發過程中遇到的一些稍微棘手的問題,或者說是在網上資源較少的問題。在面對這些問題時,對於剛剛接觸這個*.dll的我來說還是花了一些時間的,故而總結成篇。

2.相關資料

1.C# WinForm開發系列 - ZedGraph 
2.ZedGraph使用經驗 
3.ZedGraph屬性\方法介紹

相信認真參研上面的幾篇博文,尤其是第一個之后,你對ZedGraph的入門使用會了解許多。如果你想更多的了解ZedGraph,可以Down下源碼,仔細研究。ZedGraph的相對來說還是比較簡單的,雖然說界面不甚美觀,但其功能還算完善,我是做GIS二次開發的,它的幾個基本功能:圖表漫游、放大、縮小、上一視圖等與GIS軟件不謀而合。

3.ZedGraph節點Symbol問題

ZedGraph中有個枚舉列舉了節點的所有常見Symbol(如下),但是有些時候特殊問題特殊處理,我們需要用不同的symbol來表示節點,怎么辦?
public enum SymbolType { Square, Diamond, Triangle, Circle, XCross, Plus, Star, TriangleDown, HDash, VDash, UserDefined,//用戶自定義 Default, None }

參考如下Demo:ZedGraph自定義圖標

4.ZedGraph上下文菜單問題

在開發過程中,如果需要實現圖表的上下文菜單,需要將ZedGraphControl的IsShowContextMenu屬性設置為true才可顯示,當然你也可以實現自己的自定義上下文菜單。這里需要注意的是,有些你下載的dll可能上下菜單是中文,而有些卻是英文並且有可能"缺損"了那么幾項,造成這個問題的主要是由於ZedGraph開源,網友很有可能是改完源碼之后上傳的,這就造成你Down下來的dll不盡相同。現在的問題是:怎么修改ZedGraph的上下文菜單,英文<->中文?隱藏某一選項?代碼如下:
private void zGCDateChart_ContextMenuBuilder(ZedGraphControl sender, ContextMenuStrip menuStrip, Point mousePt, ZedGraphControl.ContextMenuObjectState objState) { try { //每次循環只能遍歷一個鍵 foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "copy") { item.Text = "復制"; item.Visible = true; break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "save_as") { item.Text = "另存圖表"; item.Visible = true; break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "show_val") { item.Text = "顯示XY值"; item.Visible = true; break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "unzoom") { item.Text = "上一視圖"; item.Visible = true; break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "undo_all") { item.Text = "還原縮放/移動"; item.Visible = true; break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "print") { menuStrip.Items.Remove(item); item.Visible = false; //不顯示 break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "page_setup") { menuStrip.Items.Remove(item);//移除菜單項 item.Visible = false; //不顯示 break; } } foreach (ToolStripMenuItem item in menuStrip.Items) { if ((string)item.Tag == "set_default") { menuStrip.Items.Remove(item);//移除菜單項 item.Visible = false; //不顯示 break; } } } catch (System.Exception ex) { MessageBox.Show("初始化右鍵菜單錯誤" + ex.ToString()); } }

上下文菜單中英文對照

這里需要注意幾點:
1.事件為ContextMenuBuilder
2.每次foreach循環只能遍歷一個鍵,因為你改變了枚舉項。

5.添加文本問題

有些時候需要你在圖表是添加一些文本,比如說:

這里寫圖片描述

TextObj text_obs = new TextObj("縮放:鼠標滾輪\n移動:鼠標中鍵\n菜單:鼠標右鍵", 0.899f, 0.001f, CoordType.ChartFraction, AlignH.Center, AlignV.Bottom); text_obs.FontSpec.StringAlignment = StringAlignment.Center; text_obs.FontSpec.Fill = new Fill(Color.LightBlue); text_obs.FontSpec.FontColor = Color.Black; myPane_obs.GraphObjList.Add(text_obs);

這里寫圖片描述

double xVal = Math.Round(list[i].X, 2); double yVal = Math.Round(list[i].Y, 2); string lab = string.Format("高潮位\r\n時間:{0}\r\n潮位:{1}", GetStrTime(xVal), yVal); TextObj text = new TextObj(lab, (float)xVal, (float)yVal * 1.01);//設置一個偏移量 text.FontSpec.StringAlignment = StringAlignment.Near; text.Location.CoordinateFrame = CoordType.AxisXYScale;//很重要,設置參考系,或者說參考坐標 text.FontSpec.Size = 10; text.FontSpec.FontColor = Color.Blue; text.Location.AlignH = AlignH.Center; text.Location.AlignV = AlignV.Bottom; text.FontSpec.Border.IsVisible = false; text.FontSpec.Angle = 0; text.FontSpec.Fill.IsVisible = false; myPane.GraphObjList.Add(text);

6.節點顯示懸停提示和懸停提示閃爍問題

當你需要鼠標懸停在圖表節點上提示節點的位置值,或者其他的一些內容時,你需要首先將ZedGraphControl的IsShowPointValues屬性設置為true,然后關聯事件PointValueEvent。
private string zGCDateChart_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt) { PointPair pt = curve[iPt]; return "時間:" + pt.X.ToString() + " \n潮位:" + pt.Y.ToString(); }
如果這樣就把問題解決了,那固然好,可我在做的過程中發現的一個問題,或者說是不盡如人意的地方:當鼠標懸停在節點上時,內容是顯示出來了,沒有問題,但是懸停提示框就是一直在閃爍,這個問題困擾了我很久,解決方法如下:

找來ZedGraph的源碼,在ZedGraphControl.Event.cs中找到了下面這塊代碼:
private Point HandlePointValues( Point mousePt ) { int iPt; GraphPane pane; object nearestObj; using ( Graphics g = this.CreateGraphics() ) { if ( _masterPane.FindNearestPaneObject( mousePt,g, out pane, out nearestObj, out iPt ) ) { if ( nearestObj is CurveItem && iPt >= 0 ) { //................ //code to show the tooltip } else this.pointToolTip.Active = false; } else this.pointToolTip.Active = false; } return mousePt; }
分析后發現,原來這段代碼不論鼠標移動的范圍大小,甚至乎不論鼠標是否移動,都要刷新一次Tooltip,所以才會導致CPU爆滿。

解決方案並不復雜,包括三個步驟:
1、創建私有變量lastObj用以保存上次為之顯示Tooltip的對象;
2、顯示Tooltip前判斷對象是否就是lastObj;
3、將新獲得的對象保存到lastObj中。
修改后的代碼結構如下:
private object lastObj; private Point HandlePointValues( Point mousePt ) { int iPt; GraphPane pane; object nearestObj; using ( Graphics g = this.CreateGraphics() ) { if ( _masterPane.FindNearestPaneObject( mousePtg, out pane, out nearestObj, out iPt ) ) { if (nearestObj is CurveItem && iPt >= 0 && !object.Equals(nearestObj, lastObj)) { //................ //code to show the tooltip } //else // this.pointToolTip.Active = false; } else this.pointToolTip.Active = false; } lastObj = nearestObj; return mousePt; }

7.X軸刻度重寫(X軸刻度循環問題)

簡單的X、Y軸刻度刻度形式可以通過設置以下屬性來實現:
myPane_obs.XAxis.Scale.Format = ""; myPane_obs.YAxis.Scale.Format = "";

本次開發中碰到的是關於X軸循環問題,X軸是一根絕對的數軸,但是現實的數值代表時間,並且時間從0—23時不斷重復循環,也就是說不會出現負數和大於23的整數,具體解決方案如下:

myPane_obs.XAxis.Scale.Min = 0; myPane_obs.XAxis.Scale.Max = 24; myPane_obs.XAxis.Scale.MajorStep = 4; myPane_obs.XAxis.Scale.MinorStep = 1;
/// <summary> /// X軸刻度重定義 /// </summary> /// <param name="pane"></param> /// <param name="axis"></param> /// <param name="val"></param> /// <param name="index"></param> /// <returns></returns> string XAxis_ScaleFormatEvent(GraphPane pane, Axis axis, double val, int index) { if (val >= 0 && val < 24) return val.ToString(); else if (val >= 24) return (val % 24).ToString(); else return (24-Math.Abs(val % 24)).ToString(); }


免責聲明!

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



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