正文

GUI+图像处理42007-02-10 08:20:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/iamben250/23215.html

分享到:

Setting Up Data Source   First, let’s generate some data to display via the chart.   We will create it at design time  to allow us to get on with the core Graphics Class parts of the project.  If you prefer to have the data input by the user at run time then you can adapt the techniques covered in Part 3.   Create Data   Shown below is what has become  our standard code  to create initial variables and to generate  and store some data.   I won’t trundle through the details as they are fully covered in earlier articles:   Option Strict On Imports System.Drawing.Drawing2DImports System.Collections   Structure GraphData        Dim Country As String        Dim Sales As Integer        Dim BarColor As Color        Sub New(ByVal country As String, ByVal sales As Short, ByVal barcol As Color)            Me.Country = country            Me.Sales = sales            Me.BarColor = barcol        End Sub    End Structure   '  Create Variables ‘ # of pixels vertical Axis is inset from PictureBox Left    Dim LeftMargin As Integer = 35    '  # of Pixels left unused at right side of PictureBox    Dim RightMargin As Integer = 15    '  The number of pixels above bottom of baseline    Dim BaseMargin As Integer = 35    '  Margin at Top    Dim TopMargin As Integer = 10    '   Set size of gap between each bar     Dim BarGap As Integer = 12     Dim SalesData As New ArrayList      Dim HighSale As Double  ' Maximum sales figure    Dim VertScale As Double  ' Scaling used for bar heights   '   Minor changes for this version:  '   Declare a variable to hold a Graphics object        Dim g As Graphics  '  Variable for Bitmap to be displayed in (PictureBox) control    Dim bmap As Bitmap  '  Length of vertical axis    Dim VertLineLength As IntegerDim BarWidth As Integer  ' width of barsDim BaseLineLength As Integer  ' X Axis length Private Sub GetData()        SalesData.Clear() ' Avoid data duplication        '  Generate some data and store it in the arraylist        SalesData.Add(New GraphData("Belgium", 934, Color.Blue))        SalesData.Add(New GraphData("Greece", 385, Color.DarkOrange))        SalesData.Add(New GraphData("Portugal", 1029, Color.Green))        SalesData.Add(New GraphData("Spain", 729, Color.IndianRed))        SalesData.Add(New GraphData("Turkey", 1472, Color.Tomato))        SalesData.Add(New GraphData("UK", 1142, Color.Aquamarine))End Sub   Controls    Add a PictureBox named PBBarChart and a Button named btnDraw to the Form.      Place the button somewhere down in the bottom corner of the Form.      Stretch the PictureBox so that it is close to the top, right and left edges of the form.   Set its Anchor property so that it is anchored to all four sides.  Doing this will allow the user to click the button for a resized version of the chart to be displayed whenever the form size is altered .   (As we will see in later articles, there are more dynamic ways of achieving this, but we’ll stick with this method for now.) Draw Vertical Axis Graphics Object and BitmapNext, we set up Graphics and Bitmap objects.   Put this initialising code in a separate procedure named GetGraphics: Private Function GetGraphics() As Graphics        '  Make bmap the same size and resolution as the PictureBox        bmap = New Bitmap(PBBarChart.Width, PBBarChart.Height, PBBarChart.CreateGraphics)        '   Assign the Bitmap object to the Graphics object        '   and return it        Return Graphics.FromImage(bmap)    End Function Vertical Axis  If you have read the previous articles, you may notice that the various stages are now being broken up into smaller code chunks and put into separate procedures.    The code for the vertical axis is now placed in its own procedure and remains largely unchanged from previous versions.  The first part looks like this: Private Sub DrawVerticalAxis(ByVal g As Graphics)'   Draw a line for the Vertical Axis.        Dim StartPoint As New Point(LeftMargin, PBBarChart.Height - BaseMargin)        Dim EndPoint As New Point(LeftMargin, TopMargin)        '  Basic Pen        Dim LinePen As New Pen(Color.Black, 2)        '  Draw the vertical line (without tick marks)        g.DrawLine(LinePen, StartPoint, EndPoint)         '  Draw the Tickmarks and Display Numbers        '   Calculate length of the vertical axis        VertLineLength = PBBarChart.Height - (BaseMargin + TopMargin) '  Identify the highest sales figure        For Each gd As GraphData In SalesData            If gd.Sales > HighSale Then HighSale = gd.Sales        Next' :  Scaled Tick Marks code follows Scaled Tick Marks   Here’s a change from the earlier article.    In Part 2,  we fixed the maximum number of sales at a figure of 1000.  Not very realistic, but helped to keep the code less complicated.    This time round we will adjust the maximum sales figure (and therefore the number and the spacing of tick marks) in accordance with whatever value is held in the HighSale variable above.   This means that you can change the sales data to  allow a total sales value of more than 1000 at any time in the future and your graph won’t become distorted.    To do this, we identify the highest sales figure, then round up until we get to the next round value of 100.  For example,  if the HighSale figure is 1675 then the maximum value on the scale will be set to 1700.   Here is the code that does this: ' DrawVerticalAxis procedure continued:     ' Round up to next hundred above highest sales figure        Dim NextCent As Integer = CInt(HighSale)        Do While NextCent Mod 100 <> 0            NextCent += 1        Loop    '  Identify how many TickMarks required (one per hundred):        Dim TotalTicks As Integer = CInt(NextCent / 100)   Now we know how many hundreds we have to allow for, we can divide the vertical axis proportionately into 100s, draw the tick marks and the values as text, just as we did in Part 2: ' Calc gaps between vertical tick marks        Dim YPos As Integer = CInt(VertLineLength / TotalTicks)        '  Variables for Start and End Points of Tick Marks        Dim TickSP As New Point(LeftMargin - 5, StartPoint.Y - YPos)        Dim TickEP As New Point(LeftMargin, StartPoint.Y - YPos)        '  Font for values  - declared here for readability        Dim ValueFont As New Font("Arial", 8, FontStyle.Regular)         For i As Integer = 1 To TotalTicks            g.DrawLine(New Pen(Color.Black), TickSP, TickEP)   '  Tick mark            '  Tick Values as text :            g.DrawString(CStr(i * 100), ValueFont, Brushes.Black, 2, TickSP.Y - 5)            '  Resetx, y positions, proportionately up vertical line            TickSP.Y = CInt(TickSP.Y - (VertLineLength / TotalTicks))            TickEP.Y -= CInt(VertLineLength / TotalTicks)        NextEnd Sub Testing 1, 2, 3    Well, to be strictly accurate, it’s more a case of “Testing 1, 2, ... 1500”.    If at this stage you want to see if the code so far is working, put the next code snippet in the btnDraw’s Click event and then click the button.      Private Sub btnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDraw.Click        '  The various actions are now split into separate procedures to make        '  the project more modular         '  1.  Get the data        GetData()        '  2.  Get a Graphics object to use for the drawing methods        g = GetGraphics()        '  3.   Draw the Vertical Axis        DrawVerticalAxis(g)         '  :  More code to come ....         ' n.   Assign the bitmap with the vertical axis drawn to the PictureBox        PBBarChart.Image = bmap    End Sub   As you will see, the Tick Marks now range from 100 to 1500, reflecting the current highest sales figure of 1472 (Turkey).You can tweak these values, run the project again and you will see that the vertical axis adjusts accordingly. Draw The Horizontals   Baseline (The X Axis)   You can include a horizontal axis if you like the look of it.    Create a new procedure named Draw3DBars. Private Sub Draw3DBars()        g.DrawLine(New Pen(Color.Black), LeftMargin, PBBarChart.Height - BaseMargin, _             PBBarChart.Width - RightMargin, PBBarChart.Height - BaseMargin)        '  Calculate length of baseline drawn by the code aboveBaseLineLength = pbBarChart.Width - (LeftMargin + RightMargin) '  More code to follow 3D Bars       I came across a C# method for building up bars with a 3D effect on codeproject.com.  The author,  Michael Damron, had used the simple but effective idea of building a series of  polygons one above the other.   Topping the bar off with a lighter coloured polygon completes the effect.     So I’ve re-jigged his original basic idea for this project.  Here’s the way I’ve gone about it:   The first few code items deal with some of the core calculations required.   For example, we can calculate the optimum width of each bar by using the total width available and dividing it by the number of bars; not forgetting to take into account the required gaps between each bar.    Most of these are the same as were used in Part 2: ' Calculate width of each bar making full use of space availableBarWidth = CInt((BaseLineLength / SalesData.Count) - BarGap)            '  Set the start point for the first bar  Dim BarStartX As Integer = LeftMargin + BarGap            '  Set the baseline of the graph            Dim BaseLine As Integer = PBBarChart.Height - BaseMargin '  Calc scaling  (new in this project)            VertScale = VertLineLength / HighSale    '  : More code to follow  - the only new item being the VertScale variable, which is used to ensure that the bars are drawn to the correct height, allowing for the scaling we applied in the DrawVerticalAxis procedure earlier.  This procedure continues with the following block of code which draws each of the bars in turn.   I have added quite a lot of commenting and (especially if you have read any of the previous articles) it should all make sense to you.   For Each gd As GraphData In SalesData '  Set the positions of the four points of the bottom-most '  parallelogram and store in an array    Dim Corners(3) As Point     Corners(0) = New Point(BarStartX, BaseLine - 10)     Corners(1) = New Point(BarStartX + BarWidth - 5, BaseLine - 10)     Corners(2) = New Point(BarStartX + BarWidth, BaseLine)     Corners(3) = New Point(BarStartX + 5, BaseLine) '  Calculate the height of this bar, taking scale into account:      Dim BarHeight As Integer = CInt(gd.Sales * VertScale) '  Create brushes to draw the bars'  Colors will change according to settings in GraphData    Dim barmainBrush As New HatchBrush(HatchStyle.Percent50, gd.BarColor)    Dim bartopBrush As New SolidBrush(gd.BarColor)  '  Draw one complete bar     For i As Integer = 0 To BarHeight - 11‘  (“BarHeight - 11” might be confusing.   This makes allowance for‘  a.   the 10 pixels which are added to create the 3D depth effect‘  plus‘  b.  the final rhombus is to be drawn in a lighter color, so we‘  need to stop drawing these hatched ones 1 pixel below the ‘  total bar height.  '  Fill next polygon using the hatchbrush      g.FillPolygon(barmainBrush, Corners) '  Move  all the Y positions up the picture box by 1 pixel      Corners(0).Y -= 1      Corners(1).Y -= 1      Corners(2).Y -= 1      Corners(3).Y -= 1     Next  '  Finally, top it off with a lighter rhombus      g.FillPolygon(bartopBrush, Corners)   '  Move the startpoint for the next bar       BarStartX += CInt(BarWidth + BarGap) ‘   Dispose of brushes       barmainBrush.Dispose()       bartopBrush.Dispose()  NextEnd Sub   (If you want to test the above procedure, don't forget to add a call to it in the btnDraw_Click event. ) Finishing Touches   Just to finish it off, the names of the countries are written below each bar.   This is very similar to what we did in Part 2, with the addition of a code line that adjusts the font size according to the width available.    Private Sub WriteTheNames()        '  X position for start of country name(s).  It is placed        '  under the left edge of the bar, plus 5 pixels for better look        Dim TextStartX As Integer = LeftMargin + BarGap + 5         '  Create a Brush to draw the text        Dim TextBrsh As Brush = New SolidBrush(Color.Black)        '  Create a Font object instance for text display        '  dynamically adjusted font size would be useful:        Dim fntSize As Integer = CInt(BarWidth / 7)        Dim TextFont As New Font("Verdana", fntSize, FontStyle.Bold)        '   Write them:        For Each gd As GraphData In SalesData            g.DrawString(gd.Country, TextFont, TextBrsh, TextStartX, CInt(PBBarChart.Height - (BaseMargin - 4)))            TextStartX += CInt(BarWidth + BarGap)        Next    End Sub Again, you will need to add a call to this procedure in the Draw Button’s click event.  The complete code for that event would therefore look like this:   Private Sub btnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDraw.Click        '  The various actions are now split into separate procedures to make        '  the project more modular         '  1.  Get the data        GetData()        '  2.  Get a Graphics object        g = GetGraphics()        '  3.   Draw the Vertical Axis        DrawVerticalAxis(g)        '  4.  Draw bars        Draw3DBars()        '  5.  Write the titles        WriteTheNames()        ' All Done!   Assign the bitmap with the vertical axis drawn to the picturebox        pbBarChart.Image = bmap  g.Dispose()    End Sub Summary   This project creates a more versatile and better looking bar chart.   It splits the main drawing tasks into separate procedures.  However, the code is still rather unwieldy and this makes a strong case for  creating a  3DBar class with settable properties for width, depth, height, color, etc.   It would then be possible to include  properties well beyond the UI choices we have used here, and of course it conforms more closely to the OOP approach to developing in VB.NET. In this article I explained or used the following:  Bitmap object  Brushes  Dispose  Do While Loop  DrawLine  DrawString  FillPolygon  Font object  Graphics Object  Pen  Structure    In the next article in this series, we will move on to another, sometimes more dynamic, type of chart - the line chart.  

阅读(3484) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册