Drawing Text within a Circle in VB.NET

I've found an example of placing Text within a Rectangle (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/_gdiplus_the_state_of_a_graphics_object_usecsharp.asp)

However I need to place text within a Circle and also a polygon shape. I've tried to find examples using the eclipse but no luck yet.

To be clear I need the text to auto-wrap within the circle not just clip it off. I've been able to create a clipping region but not the wrapping effect I need within a circle.

LVL 1
brian2k1Asked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
RonaldBiemansConnect With a Mentor Commented:
Hi Brian2k1,

try this, the code still needs some tweaking (error handling etc.. I'll leave that up to you) but I think it will do what you want, I haven't build in the option of the location (I have to work on my own projects aswell ;-))

Let me know if it works

   Public Class MyFillCircle
        Public Myfont As Font
        Public MyString As String
        Private Points As New ArrayList
        Private myArray() As String

        Sub New(ByVal Str As String, ByVal f As Font)
            Myfont = f
            MyString = Str
        End Sub

        Public Sub FillCircle(ByVal e As PaintEventArgs)
            Dim myrect As New RectangleF(0, 0, 475, 475)
            myArray = Split(MyString)
            Dim ht As SizeF = e.Graphics.MeasureString(MyString, Myfont)
            Dim n As Integer = CInt(((myrect.Width / 2) / ht.Height))
            Dim nt As Integer = (n * 2) - 1
            For x As Single = n To 1 Step -1
                Points.Add(New RectangleF((myrect.Width / 2) * (1 - Math.Cos(Math.Asin(((x - 0.5) * ht.Height) / (myrect.Width / 2)))), _
                (myrect.Width / 2) - ((x - 0.5) * ht.Height), _
                myrect.Width * Math.Cos(Math.Asin((((x) - 0.5) * ht.Height) / (myrect.Width / 2))), _
                ht.Height))
            Next
            For x As Single = n - 2 To 0 Step -1
                Points.Add(New RectangleF(CType(Points(x), RectangleF).X, myrect.Height - CType(Points(x), RectangleF).Y - ht.Height, CType(Points(x), RectangleF).Width, ht.Height))
            Next
            e.Graphics.DrawEllipse(New Pen(Color.Black), myrect)
            Dim StringsToPrint As New ArrayList
            Dim PRSTR As String = ""
            Dim PRSTR2 As String = ""
            Dim IPoint As Integer = nt - 1
            For x As Integer = 0 To myArray.GetUpperBound(0)
                PRSTR += myArray(x) & " "
                If e.Graphics.MeasureString(PRSTR, Myfont).Width <= CType(Points(IPoint), RectangleF).Width Then
                    PRSTR2 = PRSTR
                Else
                    PRSTR2 = PRSTR2.TrimEnd
                    StringsToPrint.Add(PRSTR2)
                    PRSTR = ""
                    IPoint -= 1
                    If IPoint < 0 Then
                        Exit Sub
                    End If
                End If
            Next
            If PRSTR <> "" Then
                StringsToPrint.Add(PRSTR2)
            End If
            For y As Integer = 0 To StringsToPrint.Count - 1
                Dim ff As Single
                Dim ww As SizeF
                ww = e.Graphics.MeasureString(StringsToPrint(y), Myfont)
                ff = ((CType(Points(y), RectangleF).Width - ww.Width) / 2)
                Points(y) = New RectangleF(ff + CType(Points(y), RectangleF).X, CType(Points(y), RectangleF).Y, CType(Points(y), RectangleF).Width, CType(Points(y), RectangleF).Height)
                e.Graphics.DrawString(StringsToPrint(y), Myfont, New SolidBrush(Color.Black), Points(y))
            Next
        End Sub

    End Class

call like

    Dim f As MyFillCircle

    Dim b As Boolean = False



    Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
        If b Then
            f.FillCircle(e)
        End If
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        f = New MyFillCircle(TextBox1.Text, Me.Font)
        b = True
        Panel1.Invalidate()
    End Sub
0
 
Bob LearnedCommented:
I have figured out one way of wrapping the text, but it is not an elegant solution, but it worked for me.  I needed to put multi-line text into a diamond shape.  The direction I took was to break the shape up into a series of rectangles that have coordinates calculated from the slope of the edges, with each one the heighth of the measured text.

Bob
0
 
RonaldBiemansCommented:
In don't think setclip will work for this because it makes the underlying graphic only draw within the clip area but it will start outside of it using the original region (does this make sense).

This will draw and wrap text within the boundaries of a elipse (or circle) (in this case I use a panel to draw on)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim g As Graphics
        g = Panel1.CreateGraphics
        Dim myrect As New RectangleF(0, 0, 100, 100)
        Dim w As Single = CSng(((myrect.Width / 2) * Math.Cos(135 * (Math.PI / 180))) + (myrect.Width / 2))
        Dim myrect2 As New RectangleF(w, w, myrect.Width - w,myrect.Height  - w)

        g.DrawEllipse(New Pen(Color.Black), myrect)
        g.DrawString("bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla", Me.Font, New SolidBrush(Color.Black), myrect2)
    End Sub



0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
Bob LearnedCommented:
See, I told you that it wasn't the best way :)  I never pretend to be the graphics expert, but I am trying to learn.

Bob
0
 
brian2k1Author Commented:
That works to some degree however when I change the eclipse to 475x475 (CD size) the text is off to the right a little bit and is in a rectangle shape instead of the circle.
0
 
Bob LearnedCommented:
I got totally psyched out, and thought that Ronald suggested was going to work, since it usually does :)

Bob
0
 
RonaldBiemansCommented:
Sorry to let you down TheLearnedOne ;-).

And sorry Brian2k1, I though that was what you wanted, it is indeed in a rectangle since drawstring only excepts a rectangle or a point. About the slightly to the right that has probably to do with the single instead of a double.

I will have a look and see if I can make it to fill the whole circle (not much hope though without splitting the string)





0
 
Bob LearnedCommented:
No problem, I just struggled with a solution, and to find out that it could have been that easy--it was inticing :)

Bob
0
 
RonaldBiemansCommented:
Hi Brian2k,

I'm almost there, I think :-)  just a question.

The method I've been working on starts at the top of the circle and goes down from there, so if there is little text it will all be at the top of the circle, is that a problem ?
0
 
brian2k1Author Commented:
no that will work. :-)
0
 
RonaldBiemansCommented:
Ok, I'll have it finished tomorrow morning (Going home now).
Bye the way I think I'm able to make you choose if you want to start at the top, center or bottom.



0
 
brian2k1Author Commented:
Ronald,

I'm not sure if it works exactly yet but I'm giving you the points anyway for effort ;-)

I'll follow up in this message with any changes should they be required.

Thanks a ton for your effort it has helped me understand the GDI better.
0
 
RonaldBiemansCommented:
Well if you do experience problems let me know and we will figure it out. One thing though to keep in mind is I use
myArray = Split(MyString) (which splits the string on spaces which means no CRLF are allowed in the string)


TheLearnedOne, am I back in your grace yet ?

0
 
brian2k1Author Commented:
you were never out of it. you the man!
0
 
RonaldBiemansCommented:
Thanks Brian2k1, Let me know how you are getting along with your project.

another note, I put in this piece of code to center the string if it is too short to fill the complete rectangle if you don't want that
              Dim ff As Single
                Dim ww As SizeF
                ww = e.Graphics.MeasureString(StringsToPrint(y), Myfont)
                ff = ((CType(Points(y), RectangleF).Width - ww.Width) / 2)
                Points(y) = New RectangleF(ff + CType(Points(y), RectangleF).X, CType(Points(y), RectangleF).Y, CType(Points(y), RectangleF).Width, CType(Points(y), RectangleF).Height)
                e.Graphics.DrawString(StringsToPrint(y), Myfont, New SolidBrush(Color.Black), Points(y))

use just this part

                e.Graphics.DrawString(StringsToPrint(y), Myfont, New SolidBrush(Color.Black), Points(y))
0
All Courses

From novice to tech pro — start learning today.