3
votes

I am currently learning pygame. When programming rectangles with rounded corners I encountered a problem.

pygame.draw.rect() draw a rectangle rect(surface, color, rect) -> Rect rect(surface, color, rect, width=0, border_radius=0, border_radius=-1, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1) -> Rect Draws a rectangle on the given surface.

border_radius (int) -- (optional) used for drawing rectangle with rounded corners. The supported range is [0, min(height, width) / 2], with 0 representing a rectangle without rounded corners.

This is the description of the official pygame documentation.

username_rect = pg.rect.Rect(screenwidth/2 - 1/8*screenwidth, screenheight*1/5, 1/4*screenwidth, username_title_render.get_height() + 10)
pg.draw.rect(screen, (0,0,0), username_rect,border_radius = 15)

Here the main part. But then I get this error message:

TypeError: 'border_radius' is an invalid keyword argument for this function

I already tried to add a "width=2" argument but then it says that there are too many arguments. Unfortunately taking other numbers does not help either. I am currently using pygame version 2.0.0.dev6 (SDL 2.0.10, python 3.8.1)

I would be very happy if you could help me, thanks a lot in advance!

2
I ran into this and had to do it myself already. Try the routines in my answer below. - Glenn Mackintosh

2 Answers

4
votes

The documentation is for 2.0.0.dev7, and according to this PR, border_radius was added after 2.0.0.dev6, GitHub reference, was released. So you're trying to use something that hasn't come out yet. You could try building from source and using the keyword (though stability is not a promise). Or you could try using a combination of rectangles and circles to achieve the effect.

2
votes

I ran into this and had to do it myself already, I might as well share.

Try these, one draws rectangles with rounded corners and the other draws bordered rounded rectangles. They use anti-aliased circles to draw the corners because otherwise they look pretty jagged:

import pygame.gfxdraw

def draw_rounded_rect(surface, rect, color, corner_radius):
    ''' Draw a rectangle with rounded corners.
    Would prefer this: 
        pygame.draw.rect(surface, color, rect, border_radius=corner_radius)
    but this option is not yet supported in my version of pygame so do it ourselves.

    We use anti-aliased circles to make the corners smoother
    '''
    if rect.width < 2 * corner_radius or rect.height < 2 * corner_radius:
        raise ValueError(f"Both height (rect.height) and width (rect.width) must be > 2 * corner radius ({corner_radius})")

    # need to use anti aliasing circle drawing routines to smooth the corners
    pygame.gfxdraw.aacircle(surface, rect.left+corner_radius, rect.top+corner_radius, corner_radius, color)
    pygame.gfxdraw.aacircle(surface, rect.right-corner_radius-1, rect.top+corner_radius, corner_radius, color)
    pygame.gfxdraw.aacircle(surface, rect.left+corner_radius, rect.bottom-corner_radius-1, corner_radius, color)
    pygame.gfxdraw.aacircle(surface, rect.right-corner_radius-1, rect.bottom-corner_radius-1, corner_radius, color)

    pygame.gfxdraw.filled_circle(surface, rect.left+corner_radius, rect.top+corner_radius, corner_radius, color)
    pygame.gfxdraw.filled_circle(surface, rect.right-corner_radius-1, rect.top+corner_radius, corner_radius, color)
    pygame.gfxdraw.filled_circle(surface, rect.left+corner_radius, rect.bottom-corner_radius-1, corner_radius, color)
    pygame.gfxdraw.filled_circle(surface, rect.right-corner_radius-1, rect.bottom-corner_radius-1, corner_radius, color)

    rect_tmp = pygame.Rect(rect)

    rect_tmp.width -= 2 * corner_radius
    rect_tmp.center = rect.center
    pygame.draw.rect(surface, color, rect_tmp)

    rect_tmp.width = rect.width
    rect_tmp.height -= 2 * corner_radius
    rect_tmp.center = rect.center
    pygame.draw.rect(surface, color, rect_tmp)


def draw_bordered_rounded_rect(surface, rect, color, border_color, corner_radius, border_thickness):
    if corner_radius < 0:
        raise ValueError(f"border radius ({corner_radius}) must be >= 0")

    rect_tmp = pygame.Rect(rect)
    center = rect_tmp.center

    if border_thickness:
        if corner_radius <= 0:
            pygame.draw.rect(surface, border_color, rect_tmp)
        else:
            draw_rounded_rect(surface, rect_tmp, border_color, corner_radius)

        rect_tmp.inflate_ip(-2*border_thickness, -2*border_thickness)
        inner_radius = corner_radius - border_thickness + 1
    else:
        inner_radius = corner_radius

    if inner_radius <= 0:
        pygame.draw.rect(surface, color, rect_tmp)
    else:
        draw_rounded_rect(surface, rect_tmp, color, inner_radius)