0

Color outside the border

Button is created like:

        style.configure('Dark.TButton', background=button_base, foreground=colors['text'], borderwidth=1,
            bordercolor=edge, lightcolor=edge, darkcolor=edge, padding=(10, 4))
        style.map('Dark.TButton',
             background=[('pressed', pressed_bg or hover_bg or button_base),
                      ('active', hover_bg or button_base),
                      ('!disabled', 'red')],
               foreground=[('active', colors['text']), ('pressed', colors['text'])],
               bordercolor=[('pressed', edge), ('active', edge)],
               lightcolor=[('pressed', edge), ('active', edge)],
               darkcolor=[('pressed', edge), ('active', edge)])
                
        style.layout('Dark.TButton', [
            ('Button.border', {'sticky': 'nswe', 'children': [
                ('Button.padding', {'sticky': 'nswe', 'children': [
                    ('Button.label', {'sticky': 'nswe'})
                ]})
            ] })
        ])

Colored red so the effect is more obvious, i have tried setting borderwidth higher but that just pushes the border further out while keeping its thickness the same

With Tk.button I lose the beveled border but at least it doesn't leak outside:

whole UI shown

1 Answer 1

2

ttk buttons don't handle custom background colors well so they are designed to use OS native themes. That red bleeding is because the theme engine doesn't properly clip custom backgrounds.

The easiest solution is to use regular tk.Button instead of ttk.Button if you need full color control because tkinter is usually pain for developers on python.

btn = tk.Button(parent, 
    text="Compile",
    bg=button_base,
    fg=colors['text'],
    activebackground=hover_bg,
    bd=1,
    relief='solid',
    highlightthickness=0)

If you must use ttk, you can try wrapping it in a Frame with the border color, but honestly tk.Button gives you way more control over colors and borders.

Update:

If you want to stick with ttk and avoid the bleeding, try using relief='flat' and handling borders differently.

style.configure('Dark.TButton', 
    background=button_base,
    foreground=colors['text'],
    relief='flat',              #remove the beveled border
    borderwidth=0,
    padding=(10, 4))

Then wrap the button in a ttk.Frame with the border color to fake the border without bleeding. Not ideal, but cleaner than reimplementing everything in tk.

Sign up to request clarification or add additional context in comments.

4 Comments

I know tk widgets give more control, but I lose all theme-aware styling and have to manually re-implement borders, colors, hover/press states, and remove the focus ring. tk.Button also shifts the text on click, so getting it to look like a ttk button becomes a PITA and ends up being 300+ lines just to match the beveled border and behavior. I’ll upload a screenshot of my current tk version, but I’m still hoping for a simpler ttk-based fix, so I won’t mark the answer as accepted yet.
@maj mac Fair point. For ttk try relief='flat' and use a ttk.Frame as a border container instead of borderwidth the bleeding happens because ttk border rendering doesn't clip custom backrounds properly. Not perfect but beats 300 lines of tk workarounds.
my answer has been updated, please check if that works for you.
That works fine, thanks, my solution is pretty similar to the one i had for tk.button but now at least i don't have to manage theme changes and on click/enter/exit stuff since style handles that

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.