1. 程式人生 > >關於ZedGraph幾個難點 (節點顯示懸停提示和懸停提示閃爍問題)

關於ZedGraph幾個難點 (節點顯示懸停提示和懸停提示閃爍問題)

1.引言

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

2.相關資料

相信認真參研上面的幾篇博文,尤其是第一個之後,你對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 }

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();
        }

這裡寫圖片描述