Canvas - Rectangle with rounded ends

gawie007

Member
Licensed User
Longtime User
I am reading in a Gerber file and drawing it on the screen.
So far it all works well until I need is a simple rectangle with rounded (semi-circle) ends.

I have tried the ABExtDrawing library which would do it but it would mean converting my whole program all for the sake of one small item.

Would it be possible to use this:
Canvas | Android Developers

with the reflection library, and if so, how would I do it?
Any guidance will be greatly appreciated!!!
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here:
SS-2013-06-26_08.29.48.png


B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim cvs As Canvas
   cvs.Initialize(Activity)
   Dim cd As ColorDrawable
   cd.Initialize(Colors.Red, 10dip)
   Dim r As Rect
   r.Initialize(100dip, 100dip, 300dip, 200dip)
   cvs.DrawDrawable(cd, r)
   Activity.Invalidate
End Sub
 
Upvote 0

gawie007

Member
Licensed User
Longtime User
Hi Erel,

Thank you for your reply.

What I am doing is drawing a solder screen for a PCB.
The application so far is shown on the attached image.

The Gerber file also has instructions to add rounded rectangles in the same format.
This will all then be converted to a DXF file so that I can cut it out on my lazer cutter.
The path is quite important because that will be my cut line.
 

Attachments

  • ScreenshotCrop5.jpg
    ScreenshotCrop5.jpg
    96.6 KB · Views: 666
Upvote 0

klaus

Expert
Licensed User
Longtime User
It's not that difficult with the ABExtDrawing library:
B4X:
Sub Globals
    Dim cvsMain As Canvas
    Dim rec1 As Rect
End Sub

Sub Activity_Create(FirstTime As Boolean)
    cvsMain.Initialize(Activity)
    rec1.Initialize(10dip, 20dip, 200dip, 100dip)
    DrawRoundedRectangle(cvsMain, rec1, 20dip, 10dip,Colors.Red, True, 5dip)

    rec1.Initialize(10dip, 120dip, 200dip, 200dip)
    DrawRoundedRectangle2(cvsMain, rec1, Colors.Blue, False, 5dip)

    rec1.Initialize(220dip, 20dip, 280dip, 200dip)
    DrawRoundedRectangle2(cvsMain, rec1, Colors.Green, False, 5dip)
End Sub

'Draw a rounded corner rectangle
'cvs = Canvas to draw with
'Rect1 = rectangle to draw
'rx = x radius
'ry = y radius
'Color = color
'Filled = False = line, True = filled
'StrokeWidth = line width
Sub DrawRoundedRectangle(cvs As Canvas, Rect1 As Rect, rx As Float, ry As Float, Color As Int, Filled As Boolean, StrokeWidth As Float)
    Dim drw As ABExtDrawing
    Dim r1 As ABRectF
    Dim pt As ABPaint
    
    r1.Initialize(Rect1.Left, Rect1.Top, Rect1.Right, Rect1.Bottom)
    pt.Initialize
    pt.SetStrokeWidth(StrokeWidth)
    pt.SetColor(Color)
    If Filled Then
        pt.SetStyle(pt.Style_FILL)
    Else
        pt.SetStyle(pt.Style_STROKE)
    End If
    drw.drawRoundRect(cvs, r1, rx, ry, pt)
End Sub

'Draw a rounded corner rectangle, the radius is half the smallest value of height or width
'cvs = Canvas to draw with
'Rect1 = rectangle to draw
'Color = color
'Filled = False = line, True = filled
'StrokeWidth = line width
Sub DrawRoundedRectangle2(cvs As Canvas, Rect1 As Rect, Color As Int, Filled As Boolean, StrokeWidth As Float)
    Dim drw As ABExtDrawing
    Dim r1 As ABRectF
    Dim pt As ABPaint
    Dim r As Float
    
    r1.Initialize(Rect1.Left, Rect1.Top, Rect1.Right, Rect1.Bottom)
    r = Min(Rect1.Bottom - Rect1.Top, Rect1.Right - Rect1.Left) / 2
    pt.Initialize
    pt.SetStrokeWidth(StrokeWidth)
    pt.SetColor(Color)
    If Filled Then
        pt.SetStyle(pt.Style_FILL)
    Else
        pt.SetStyle(pt.Style_STROKE)
    End If
    drw.drawRoundRect(cvs, r1, r, r, pt)
End Sub
Attached the test project.

Best regards.
 

Attachments

  • RoundedRectangles.zip
    6.2 KB · Views: 545
Upvote 0

gawie007

Member
Licensed User
Longtime User
Thank you, Klaus.

I have just ran your program.

Your Stars and Medals are so well deserved!!!!!!!!!

That is exactly what I was looking for.

Furthermore, from what you have shown/taught me, I should be able to adapt all my drawing code to use this library.

Give a man a fish, he will eat for a day. Teach him to fish and he will eat for a lifetime.....or something like that.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
I should be able to adapt all my drawing code to use this library.
Sure, or use it directly.
The ABExtDrawing is a wrapper of the whole set of functions of the Android Canvas object.
The B4A Canvas is a subset of the Android Canvas.

Best regards.
 
Upvote 0

gawie007

Member
Licensed User
Longtime User
Hi Klaus,

To use it directly would be the ultimate since all the documentation is available in the Android website.
I would assume that the library would be obsolete too since the android code would be called directly.
This would also give me access to all properties and methods.

I am unfortunately not very good at using reflection etc.....yet.
A lot of the examples (I am not knocking the AB library) hide the simple things by building complex things (to show their capabilities).

Your example was so simple, I could see at an instant what and why something is used.

Reflection is also a little difficult for me to understand at the moment. I have tried many times already - it just won't sink in.
If it had an example like what you have done for me it would show anyone how to use it.

I would so love to know how to use reflection etc since I must have about 15 Android books that I would love to tap into without having to use Eclipse.

If you could provide a similar example, I would be indebted to you. I will understand however if you don't.
I can't thank you enough so far for teaching me these more difficult tasks!
 
Upvote 0

ivan.tellez

Active Member
Licensed User
Longtime User
Hi Klaus,

To use it directly would be the ultimate since all the documentation is available in the Android website.
I would assume that the library would be obsolete too since the android code would be called directly.
This would also give me access to all properties and methods.

I am unfortunately not very good at using reflection etc.....yet.
A lot of the examples (I am not knocking the AB library) hide the simple things by building complex things (to show their capabilities).

Your example was so simple, I could see at an instant what and why something is used.

Reflection is also a little difficult for me to understand at the moment. I have tried many times already - it just won't sink in.
If it had an example like what you have done for me it would show anyone how to use it.

I would so love to know how to use reflection etc since I must have about 15 Android books that I would love to tap into without having to use Eclipse.

If you could provide a similar example, I would be indebted to you. I will understand however if you don't.
I can't thank you enough so far for teaching me these more difficult tasks!


A little too late, but if someone is looking for the answer, the code its here:

DrawRoundRect on any Canvas Native Code
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
Here:
SS-2013-06-26_08.29.48.png


B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim cvs As Canvas
   cvs.Initialize(Activity)
   Dim cd As ColorDrawable
   cd.Initialize(Colors.Red, 10dip)
   Dim r As Rect
   r.Initialize(100dip, 100dip, 300dip, 200dip)
   cvs.DrawDrawable(cd, r)
   Activity.Invalidate
End Sub

Hello Erel,

It's possible use the same way to do an empty rounded rect but with stroke of some size?

Thanks
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
You should draw two rectangles.
If you dont want a stroke then:
One for the border (Fill True) and a second one for the transparent part (Fill True).
If you want a stroke thickness then:
One for the transparent part (Fill True) and a second one for the border Fill = False and Stroke width.
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
You should draw two rectangles.
If you dont want a stroke then:
One for the border (Fill True) and a second one for the transparent part (Fill True).
If you want a stroke thickness then:
One for the transparent part (Fill True) and a second one for the border Fill = False and Stroke width.
Hello klaus, thanks for reply.

I've realized now that my question was not complete.
The round rectangle must have a thickness and must be transparent inside.
I need that to sign an area parimeter.
Do you think it can be done avoiding use of libraries?
Following the Erel's example, can you provide a little piece of code that show how to do that?

Thank you
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
this creates a look through hole.

unfortunately it doesn't seem to work with rounded corner for the hole.


B4X:
Dim cd As ColorDrawable
Dim r As Rect
cvs.Initialize(ImageView1)
cd.Initialize(Colors.Red, 10dip )
r.Initialize(0dip, 0dip, 100dip, 100dip)
cvs.DrawDrawable(cd, r)
r.Initialize(20dip, 20dip, 80dip, 80dip)
cvs.DrawRect(r,Colors.Transparent,True,0) 
ImageView1.Invalidate
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
this creates a look through hole.

unfortunately it doesn't seem to work with rounded corner for the hole.
I like your solution thank you.

But, as you said, it's not working with round corner inside.
The screen area I'm trying to surround have such property. It's a rectangular area with round corner.

BTW thanks for your help
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached you find a sample program.
Unfortunately the principle with a ColorDrawable doesn't work with a transparent color.
The three upper rectangles are drawn with ColorDrawable.
The secaond on the Activity and the third on a panel.
But the transparent color is not drawn.
B4X:
'Draw a rounded corner rectangle with a border
'cvs = Canvas to draw with
'Left, Top, Width, Height = rectangle dimensions
'Radius = outer corner radius
'BorderWidth
'BorderColor
'FillColor
Sub DrawRoundRectBorder1(cvs As Canvas, Left As Int, Top As Int, Width As Int, Height As Int, Radius As Int, BorderWidth As Int, BorderColor As Int, FillColor As Int)
  
    Dim cd1 As ColorDrawable
    cd1.Initialize(BorderColor, Radius)
    Dim r As Rect
    r.Initialize(Left, Top, Left + Width, Top + Height)
    cvs.DrawDrawable(cd1, r)
  
    Dim cd2 As ColorDrawable
    cd2.Initialize(FillColor, Max(0, Radius - BorderWidth))
    Dim r As Rect
    r.Initialize(Left + BorderWidth, Top + BorderWidth, Left + Width - BorderWidth, Top + Height - BorderWidth)
    cvs.DrawDrawable(cd2, r)
  
    Activity.Invalidate  
End Sub

With the ABExtDrawing library it works, forth rectangle.
B4X:
'Draw a rounded corner rectangle with a
'cvs = Canvas to draw with
'Rect1 = rectangle to draw
'Radius = radius
'StrokeColor = border color
'FillColor = internal color
'StrokeWidth = line width
Sub DrawRoundedRectangle(cvs As Canvas, Rect1 As Rect, Radius As Float, StrokeColor As Int, FillColor As Int, StrokeWidth As Float)
    Dim drw As ABExtDrawing
    Dim r1 As ABRectF
    Dim pt1, pt2 As ABPaint

    r1.Initialize(Rect1.Left, Rect1.Top, Rect1.Right, Rect1.Bottom)
    pt1.Initialize
    pt1.SetStrokeWidth(1)
    pt1.SetColor(FillColor)
    pt1.SetStyle(pt1.Style_FILL)
    drw.drawRoundRect(cvs, r1, Radius, Radius, pt1)

    pt2.Initialize
    pt2.SetStrokeWidth(StrokeWidth)
    pt2.SetColor(StrokeColor)
    pt2.SetStyle(pt1.Style_STROKE)
    drw.drawRoundRect(cvs, r1, Radius, Radius, pt2)
End Sub
You could also adapt this code using the JavaObject library.
Or this code using the AcceleratedSurface Library.
 

Attachments

  • DrawRoundRectWithBorder.zip
    6.7 KB · Views: 394
  • DrawRoundRectWithBorder.png
    DrawRoundRectWithBorder.png
    28.8 KB · Views: 756
Upvote 0

Saverio

Member
Licensed User
Longtime User
Attached you find a sample program.
Unfortunately the principle with a ColorDrawable doesn't work with a transparent color.
The three upper rectangles are drawn with ColorDrawable.
The secaond on the Activity and the third on a panel.
But the transparent color is not drawn.
Thank you Klaus.

But my question was if it is possible to do a rectangle with transparent inside and also with round corner
in the transparent area, avoiding the use of any library but the core. See my reply #16.

Anyway thanks for your time
 
Upvote 0

sorex

Expert
Licensed User
Longtime User
Not possible.

sure is :)

B4X:
Sub Globals
Private ImageView1,ImageView2 As ImageView
Dim cvs,cvs2 As Canvas
Dim bm As Bitmap
Dim x,y As Int
Dim cd As ColorDrawable
Dim r1 As Rect
End Sub

Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Layout1")

bm.InitializeMutable(100,100)
cvs.Initialize2(bm)
cvs2.Initialize(ImageView2)
cd.Initialize(Colors.Red, 10dip )
roundtangle(0dip, 0dip, 100dip, 100dip,Colors.Red,Colors.Red)
roundtangle(20dip, 20dip, 100-20dip, 100-20dip,Colors.Red,Colors.Transparent)
ImageView2.Invalidate   
End Sub

Sub roundtangle(l,t,r,b,sc,rc)
r1.Initialize(l,t,r,b)
cvs.DrawDrawable(cd, r1)
bm.Initialize3(cvs.Bitmap)
For y=0 To 100-1
    For x=0 To 100-1
        If bm.GetPixel(x,y)=sc Then cvs2.DrawPoint(x,y,rc)
    Next
Next
cvs.DrawRect(r1,Colors.Transparent,True,0)
End Sub


a dirty hack but it gives you rounded outer corners and a rounded transparent inner box.
 
Upvote 0
Top