简体   繁体   中英

Setting the relief of a button in ttk

Hopefully I've narrowed this down as much as possible.

I am working on a program in which I need very small buttons on screen and containing text. I originally was using tk but I was not able to get the buttons specified to the size that I wanted (it has to be a very specific size).

When I switched to ttk I now am unable to change the relief of the buttons. This is the only option that I cannot figure out how to change.

This should run a simple window with a single button:

import Tkinter as tk
import ttk
from ttk import Button, Style, Frame

root = tk.Tk()
style = ttk.Style()
style.configure('TButton', foreground='red', relief='sunken', padding=20)
mainframe = Frame(root)
button = Button(mainframe, text='test')
button.pack(padx=20, pady=20)
mainframe.pack()
root.mainloop()

This is what I see both with relief = 'sunken' and no relief option specified:

ttkButton

As you can see I have a style declared to set foreground to red and this works... so I know that the style is applying. I also know that the sunken property is there because the button uses it while you are pressing it.

Why is the relief setting not working?

I do not need a tk solution, I am aware of how to set relief of a button in tk but that won't work here.

The Tk themeing system redefines widgets in terms of separate visual elements that are composed together using a layout and style configuration options to yield a visual representation of the widget that depends on the chosen theme and the widget state. This allows Tk to request that the Windows Visual Styles API be used to draw certain elements so that we can match the standard user experience for the platform correctly.

In the example above you have a Ttk button. This has a number of elements which can be seen using ttk.Style().layout('TButton') . This layout depends upon the current theme and under Windows 7 this looks like the following:

[('Button.button', {'children':
    [('Button.focus', {'children':
        [('Button.padding', {'children':
            [('Button.label', {'sticky': 'nswe'})],
        'sticky': 'nswe'})],
    'sticky': 'nswe'})],
'sticky': 'nswe'})]

This shows that the base element is a button element. This is defined to be the VSAPI BP_PUSHBUTTON part and depending on the widget state (disabled, active, pressed etc) the element will be drawn using one of the Windows defined states (eg: PBS_PRESSED when in the pressed state). Note also that there is no border element in the layout - just a focus element, padding and a label .

The result of all this is that there simply is nothing to draw any relief when using the vista theme. The button background is drawn by Windows depending on a state flag using predefined image-based UI elements with some other elements rendered on top. In a different theme that uses Tk APIs to draw everything the layout might include a border element that understands and uses the borderwidth and relief options. This is done in the 'default' and 'classic' themes for instance.

If you really want to customize a Ttk widget then the way to do this is to define new elements that support the visual representations you need. You can do this by importing an element from another theme or defining a new one using one of the element engines (image or vsapi). You then declare a new layout using this element and create a compatible widget using the new style.

I realize this is an old question, but I was trying to accomplish the same thing, and there's a much simpler way of replicating the tk.Button.configure(relief='sunken') behavior: ttk.Button.state(['pressed']) . It can be cleared with ttk.Button.state(['!pressed']) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM