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