閱讀320 返回首頁    go 阿裏雲 go 技術社區[雲棲]


C# 數據庫係統中使用GDI+繪製柱狀圖

在C#+SQL Server數據庫做係統中,通常需要對數據庫中的數據進行繪製圖形報表方便經理查看,雖然有很多實用的水晶報表控件和圖表控件實現該功能,但我還是想講講如何使用GDI繪製簡單的柱狀圖.(推薦大家不要手畫,盡量使用已有控件函數繪製)

一.前言

我們在使用C#+SQL Server做的簡單應用係統是一個手機銷售的係統,所以它有不同手機品牌和不同年份銷售手機的利潤和數量的柱狀圖,方便公司經理查看那個月和那種品牌手機銷售更好,方便進貨增加企業利潤.其中它點擊"輸入年份",查看"2013"年的銷售柱狀圖數據如下所示:(其實效果還行)

二.繪製坐標

下麵就首先講述如何使用GDI+繪製簡單的柱狀圖,首先上麵圖中我定義為是靜態柱狀圖,因為它X(橫坐標)隻有12個月份的數據,不會改變,而後麵講解的我定義的動態柱狀圖會根據手機品牌動態更新數據的,後麵將介紹.
首先第一步需要繪製坐標,創建一個"C# Windows窗體應用程序",添加一個簡單的button.然後雙擊button,進入button1_Click(object sender, EventArgs e)事件.添加如下代碼.

//定義變量
Graphics graphic;                                      //GDI+繪圖圖麵
SolidBrush Bfill = new SolidBrush(Color.Black);        //定義單色畫刷用於填充圖形
Pen Rpen = new Pen(Color.Red, 3);                      //創建紅色畫筆 
//該函數用於繪製坐標
private void CreateTable()
{
    graphic = this.CreateGraphics();                   
    Rectangle rect = new Rectangle(120, 20, 380, 300); //繪製黑色背景
    graphic.FillRectangle(Bfill, rect);                //填充這個矩形
    //Y坐標 (150,40)不變
    graphic.DrawLine(Rpen, new Point(150, 40), new Point(150, 300));   //Y坐標
    graphic.DrawLine(Rpen, new Point(150, 40), new Point(140, 50));    //Y坐標 左箭頭
    graphic.DrawLine(Rpen, new Point(150, 40), new Point(160, 50));    //Y坐標 右箭頭 
    //X坐標 (470,300)不變
    graphic.DrawLine(Rpen, new Point(150, 300), new Point(470, 300));  //X坐標 
    graphic.DrawLine(Rpen, new Point(460, 290), new Point(470, 300));  //X坐標 上箭頭
    graphic.DrawLine(Rpen, new Point(460, 310), new Point(470, 300));  //X坐標 下箭頭 
}

在private void button1_Click(object sender, EventArgs e)事件中增加"CreateTable();"代碼即可點按鈕時擊創建坐標,如圖:

它具體的坐標如下圖所示,其中Rectangle(120, 20, 380, 300)對應Rectangle(int x, int y, int width, int height)表示一個矩形對用起始位置和長寬;使用graphic.DrawRectangle是繪製一個空心的矩形,而graphic.FillRectangle(畫刷,矩形)對矩形進行填充.使用graphic.DrawLine(Pen,Point1,Point2)表示畫筆,起始坐標xy,終止坐標xy,是繪製直線,其中在繪製箭頭需要注意它的相應坐標.其實在草稿紙上設計好在繪製,感覺還是很方便的.

注意:在C#中load事件中是不能畫圖的,因為Windows的GDI必須在擁有屏幕資源的時候才能有效,FormLoad時窗體還沒有繪圖資源,所以不能畫出.在窗體創建完成後如果再調用FormLoad時間就可以繪製圖形.所以我是在點擊按鈕時創建坐標.

三.靜態的柱狀圖

 下麵是繪製靜態的柱狀圖,它的運行效果如下圖所示,繪製了12個等高的柱狀圖:

它的源代碼如下,通過調用DrawTable()繪製靜態的圖形.為什麼我定義它為靜態的後麵將介紹:

//定義變量
Brush Bbrush = Brushes.Blue;                         //創建藍色畫刷 文字
Font myFont = new Font("黑體", 12);                  //創建字體
Font tFont = new Font("宋體", 8);                    //創建字體 顯示在直方圖上的數量
SolidBrush Wfill = new SolidBrush(Color.White);      //定義單色畫刷用於填充圖形   
//該函數用於繪製靜態報表
private void DrawTable()
{ 
    //輸出文字
    graphic.DrawString("月份", myFont, Bbrush, new RectangleF(115, 280, 40, 40));
    graphic.DrawString("月份銷售數量", myFont, Bbrush, new RectangleF(260, 40, 200, 40));
    //繪製月份 12個
    for (int i = 1; i <= 12; i++)
    {
        graphic.DrawString(i.ToString(), myFont, Bbrush, 155 + (i-1) * 26, 300);  
    }
    //定義繪製柱狀圖坐標|寬|高
    int x, y, width, heigh;
    x = 160;                 //X坐標定值=160 Y軸的x坐標為150
    width = 13;              //width坐標=(470-150)/(12*2)=13
    heigh = 200;             //X軸y坐標=300 heigh=200
    y = 100;                 //Y坐標 y=300-200 
            
    for (int i = 0; i < 12; i++)
    {
        //填充圖形
        Rectangle rect = new Rectangle(x+i*26, y, width, heigh);  
        graphic.FillRectangle(Wfill, rect);      
        //顯示數量
        graphic.DrawString("100", tFont, Brushes.Yellow, x + i * 26, y - 15);
    }
}

這裏的有幾個地方需要注意,其中26=(470-150)/12表示把X軸分成12個等分,其中每個等分寬為26,再在每個等分繪製一半13的白色矩形.如下圖:



四.動態的柱狀圖

如果動態顯示的柱狀圖,就是獲取數據庫中具體的數量,在進行繪製圖形的基本過程為定義:int num[12]分別記錄12個月份中的銷售數量,在sumNum+=num[i];計算12個月總的銷售數量,通過百分比計算具體的每個月的高度,這樣的好處在於當其中一個月的銷售數量很大時,會出現那個矩形很高,超出界麵範圍.
num[i]/sumNum=具體高度/總高度(其中總高度我們在上麵設置為heigh=200)
同樣,如果在做品牌銷售業績時,如下圖所示:

這是銷售3中品牌手機"諾基亞"、"三星"、"蘋果"的情況,如果想增加一個新的品牌"HTC"時,這是就會顯示4條柱狀圖,因此也需要動態的生成.我們已經求出了它的總寬度為(470-150)=320,再通過320/具體的品牌數量,即可平均分配每個品牌的數量,再求出具體的坐標即可.
分享文章:https://www.cnblogs.com/stg609/archive/2008/03/30/1129221.html
最後補充下獲取數據庫品牌的代碼:

//獲取手機品牌信息 (靜態生成5個品牌)
private void SelectName()
{
    string sql = "select * from SellList";
    string consqlserver = "Data Source=.;Initial Catalog=TelephoneMS;Integrated Security=True;";
    SqlConnection con = new SqlConnection(consqlserver);     //定義SQL Server連接對象               
    SqlDataAdapter da = new SqlDataAdapter(sql, con);        //數據庫命令和數據庫連接
    con.Open();
    DataSet ds = new DataSet();                              //聲明一個DataSet對象
    da.Fill(ds);                                             //裝入數據
    //清零
    for (int i = 0; i < 5; i++) {
        price[i] = 0;
        num[i] = 0;
    }
    try
    {
        //獲取實際銷售價格總和
        for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
        {
            if (ds.Tables[0].Rows[i]["phonename"].ToString() == "諾基亞")
            {
                //利潤 = 實際銷售價格 - 進貨價格
                price[0] += float.Parse(ds.Tables[0].Rows[i]["sellmoney"].ToString()) -
                    float.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                num[0]++;
            }
            else if (ds.Tables[0].Rows[i]["phonename"].ToString() == "iphone")
            {
                price[1] += float.Parse(ds.Tables[0].Rows[i]["sellmoney"].ToString()) -
                    float.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                num[1]++;
            }
            else if (ds.Tables[0].Rows[i]["phonename"].ToString() == "三星")
            {
                price[2] += float.Parse(ds.Tables[0].Rows[i]["sellmoney"].ToString()) -
                    float.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                num[2]++;
            }
            else if (ds.Tables[0].Rows[i]["phonename"].ToString() == "HTC")
            {
                price[3] += float.Parse(ds.Tables[0].Rows[i]["sellmoney"].ToString()) -
                    float.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                num[3]++;
            }
            else if (ds.Tables[0].Rows[i]["phonename"].ToString() == "OPPO")
            {
                price[4] += float.Parse(ds.Tables[0].Rows[i]["sellmoney"].ToString()) -
                    float.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                num[4]++;
            }
        }
    }
    catch (Exception msg)
    {
        MessageBox.Show(msg.Message);
    }
    finally
    {
        con.Close();
        con.Dispose();
        da.Dispose();
    }
}

總結:回想起來使用GDI+繪製柱狀圖,確實很蛋疼,也就沒繼續貼上代碼了有具體的控件卻不用,但我還是希望該文章對那些不知道在做使用C#做係統中如何生成柱狀圖報表的有幫助(盡量使用已有的控件).
如果知道如何使用Dundas Chart for .NET\ReportViewer\FormCrystal等製作報表的就當該文章簡單幫助你回顧一些GDI+的知識吧!如果文章中有錯誤或不足的地方,見諒!
(BY:Eastmount 2013-9-14 夜1點https://blog.csdn.net/eastmount/)

最後更新:2017-04-03 15:21:44

  上一篇:go Android之GridView的Item移動
  下一篇:go arm-linux-gcc下載與安裝