15

I was wondering if you could help me with a style options issue in ttk. I've managed to change most of the basic ttk widgets to the style of my preference. I'm only stuck at changing the style of a scrollbar. I've searched for hours looking for an answer, unfortunately to no avail.

Here's a sample code using the scrollbar style option:

import tkinter as tk                 
from tkinter import ttk

class Gui:
    def __init__(self,mainframe):

        #set the style
        style = ttk.Style()
        style.configure('Horizontal.TScrollbar',background = "blue" )   

        #Create a mainframe
        self.mainframe = mainframe
        self.mainframe.title("example")


        #creating scrollbar frame
        scrl_attr_frame = ttk.Frame(self.mainframe)                            
        scrl_attr_frame.grid(column=0,row=5,sticky="ns")                                           
        scrl_attr_frame.rowconfigure(0, weight=1)                                                   
        attr_canvas = tk.Canvas(scrl_attr_frame)                                                   
        h_scroll = ttk.Scrollbar(scrl_attr_frame,orient="horizontal", command=attr_canvas.xview)
        attr_canvas.configure(xscrollcommand=h_scroll.set)                                       
        attr_canvas.grid(column=0,row=0,sticky="ns")                                                                            
        h_scroll.grid(column=0, row=1,sticky="we") 
        attr_frame = ttk.Frame(attr_canvas)                                                        
        attr_frame.grid(column=0,row=0,sticky="ns")                                                 
        attr_canvas.create_window((0,0),window=attr_frame, anchor='nw')
        attr_frame.bind("<Configure>",lambda event, canvas=attr_canvas : canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200,takefocus=False,highlightthickness=0))#attribute_frame.winfo_height()/20,highlightthickness=0))

        #setup treeview widget
        tree_columns = ("c1", "c2", "c3")

        self.tree = ttk.Treeview(attr_frame,columns=tree_columns, show="headings",takefocus=False)
        self.tree.grid(column=0, row=0, sticky='nsew')

        for head in tree_columns:
            self.tree.heading(head,text=head,anchor="w")


root = tk.Tk()
myapp = Gui(root)
root.mainloop()

I also tried several combinations including;

style.configure('TScrollbar',background='blue') 

#and
style.configure('CustomScroll.Horizontal.TScrollbar',background='blue')

#in combination with
h_scroll = ttk.Scrollbar(scrl_attr_frame,orient="horizontal", command=attr_canvas.xview)
h_scroll['style'] = "CustomScroll.Horizontal.TScrollbar" 

Many thanks for your help!

StephanL
  • 151
  • 1
  • 1
  • 5
  • It would be nice if when someone creates something gave also the complete documentation with examples, otherwise doing nothing would be more productive. – nbro Feb 06 '15 at 22:33
  • What platform? Some native widgets on some platforms are not able to be changed. – Bryan Oakley Feb 06 '15 at 22:44
  • @StephanL I suppose you are on a Mac and that you cannot even see the horizontal Scrollbar... – nbro Feb 06 '15 at 22:54
  • I'm working on windows 7. Thanks for your time! – StephanL Feb 06 '15 at 22:55
  • @Rinzler. Just updated my question with a sample code using the style options. The scrollbar works fine in the above example aside from the refusal to change appearance. – StephanL Feb 06 '15 at 22:59
  • @StephanL I will try to see what I can do, but I don't promise I will be able to help... – nbro Feb 06 '15 at 23:00
  • 1
    Great! thanks for your time and effort. I appreciate your help regardless of the outcome. – StephanL Feb 06 '15 at 23:02
  • @Rinzler,@Bryan. I just checked the above code on a linux device. It turns out it works correct on this platform. Is there an explanation as to why it doesn't work on windows? Or even better a work around to fix this issue altogether? – StephanL Feb 06 '15 at 23:12
  • @StephanL I think there's no workaround, as far as I know. There are a lot of these problems regarding a specific platform when setting the Style, unfortunately. – nbro Feb 06 '15 at 23:14
  • @StephanL I have tested it also on my Windows 7 and on my mac and the color does not change. – nbro Feb 06 '15 at 23:18
  • possible duplicate of [Change the look of the Tkinter scrollbar widget Python](http://stackoverflow.com/questions/26899716/change-the-look-of-the-tkinter-scrollbar-widget-python) – timeyyy Apr 15 '15 at 19:07

4 Answers4

10

It looks like you just want to change the trough for a horizontal scrollbar under the Windows theme. The ttk widgets are constructed from a set of elements provided by a styling engine and combined using the declared layout. Under Windows the styling engine is the Windows Visual Styles API which means the programmer doesn't have any control over the colours or images used to draw most of the common elements. The button background, scrollbar trough and buttons and the thumb and even the grip drawn inside the scrollbar thumb are all provided by Windows.

It is possible to take control of this for application customization but at a cost of making your application no longer look standard on the given platform. To do this you have to provide your own UI elements and define new widget layouts. Ultimately this can turn into defining your own theme. The tcl scripts in the ttk library provide good examples to follow and there are even some complete (if old) themes using bitmaps to declare image based theme elements in the original version of ttk which was called 'tile'.

In this specific example to get a Windows horizontal scrollbar with a custom coloured background we need to redefine the layout to use the scrollbar trough from the Tk drawn elements. The elements used in the 'default' theme can be copied in and are defined using style configuration parameters and are then drawn by Tk itself and not passed off to a third party engine. The following code generates a scrollbar like this which uses the standard buttons and thumb provided by the vsapi styling engine but replaces the trough. This imported trough understands the troughcolor style configuration option and so we can define a colour to use now. All scrollbars using this style will use the same colour as the widget itself will not accept a troughcolor option. ie: you can't have one scrollbar be blue and another be red unless you define a new style for each new colour.

enter image description here

from tkinter import *
from tkinter.ttk import *

def main():
    app = Tk()
    style = Style()

    # import the 'trough' element from the 'default' engine.
    style.element_create("My.Horizontal.Scrollbar.trough", "from", "default")

    # Redefine the horizontal scrollbar layout to use the custom trough.
    # This one is appropriate for the 'vista' theme.
    style.layout("My.Horizontal.TScrollbar",
        [('My.Horizontal.Scrollbar.trough', {'children':
            [('Horizontal.Scrollbar.leftarrow', {'side': 'left', 'sticky': ''}),
             ('Horizontal.Scrollbar.rightarrow', {'side': 'right', 'sticky': ''}),
             ('Horizontal.Scrollbar.thumb', {'unit': '1', 'children':
                 [('Horizontal.Scrollbar.grip', {'sticky': ''})],
            'sticky': 'nswe'})],
        'sticky': 'we'})])
    # Copy original style configuration and add our new custom configuration option.
    style.configure("My.Horizontal.TScrollbar", *style.configure("Horizontal.TScrollbar"))
    style.configure("My.Horizontal.TScrollbar", troughcolor="red")

    # Create and show a widget using the custom style
    hs = Scrollbar(app, orient="horizontal", style="My.Horizontal.TScrollbar")
    hs.place(x=5, y=5, width=150)
    hs.set(0.2,0.3)

    app.mainloop()

if __name__ == '__main__':
    main()
patthoyts
  • 32,320
  • 3
  • 62
  • 93
9

It's easier if you use the clam theme:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
style = ttk.Style()
style.theme_use('clam')

# list the options of the style
# (Argument should be an element of TScrollbar, eg. "thumb", "trough", ...)
print(style.element_options("Horizontal.TScrollbar.thumb"))

# configure the style
style.configure("Horizontal.TScrollbar", gripcount=0,
                background="Green", darkcolor="DarkGreen", lightcolor="LightGreen",
                troughcolor="gray", bordercolor="blue", arrowcolor="white")

hs = ttk.Scrollbar(root, orient="horizontal")
hs.place(x=5, y=5, width=150)
hs.set(0.2,0.3)

root.mainloop()
Aivar
  • 6,814
  • 5
  • 46
  • 78
1

Here's a stand-alone solution - works for both horizontal and vertical scrollbars.


def make_scrollbar_styles(
        troughcolor='black',
        background='grey',
        arrowcolor='white',
) -> Tuple[str, str]:
    """
    Style the scrollbars.  Usage:
        parent_frame = ... # tk.Frame(...) or tk.Tk() or whatever you're using for the parent
        hstyle, vstyle = make_scrollbar_styles()
        self._vbar = ttk.Scrollbar(parent_frame, orient='vertical', style=vstyle)
        self._hbar = ttk.Scrollbar(parent_frame, orient='horizontal', style=hstyle)
    """
    style = Style()

    for is_hori in (True, False):
        v = "Horizontal" if is_hori else "Vertical"
        style.element_create(f'CustomScrollbarStyle.{v}.Scrollbar.trough', 'from', 'default')
        style.element_create(f'CustomScrollbarStyle.{v}.Scrollbar.thumb', 'from', 'default')
        style.element_create(f'CustomScrollbarStyle.{v}.Scrollbar.leftarrow', 'from', 'default')
        style.element_create(f'CustomScrollbarStyle.{v}.Scrollbar.rightarrow', 'from', 'default')
        style.element_create(f'CustomScrollbarStyle.{v}.Scrollbar.grip', 'from', 'default')
        style.layout(
            f'CustomScrollbarStyle.{v}.TScrollbar',
            [(f'CustomScrollbarStyle.{v}.Scrollbar.trough', {
                'children': [
                    # Commenting in these 2 lines adds arrows (at least horizontally)
                    # (f'CustomScrollbarStyle.{v}.Scrollbar.leftarrow', {'side': 'left', 'sticky': ''}) if is_hori else (f'CustomScrollbarStyle.{v}.Scrollbar.uparrow', {'side': 'top', 'sticky': ''}),
                    # (f'CustomScrollbarStyle.{v}.Scrollbar.rightarrow', {'side': 'right', 'sticky': ''})  if is_hori else (f'CustomScrollbarStyle.{v}.Scrollbar.downarrow', {'side': 'bottom', 'sticky': ''}),
                    (f'CustomScrollbarStyle.{v}.Scrollbar.thumb', {
                        'unit': '1',
                        'children': [(f'CustomScrollbarStyle.{v}.Scrollbar.grip', {'sticky': ''})],
                        'sticky': 'nswe'}
                     )
                ],
                'sticky': 'we' if is_hori else 'ns'}),
             ])
        style.configure(f'CustomScrollbarStyle.{v}.TScrollbar', troughcolor=troughcolor, background=background, arrowcolor=arrowcolor)
        # Comment in the following to customize disable/active colors, whatever that means
        # style.map(f'CustomScrollbarStyle.{v}.TScrollbar', background=[('pressed', '!disabled', disabledcolor), ('active', 'orange')])
    return "CustomScrollbarStyle.Horizontal.TScrollbar", "CustomScrollbarStyle.Vertical.TScrollbar"

Peter
  • 12,274
  • 9
  • 71
  • 86
  • `) -> Tuple[str, str]: NameError: name 'Tuple' is not defined` https://stackoverflow.com/a/70780002 – Lod Aug 23 '23 at 19:50
  • `style = Style() NameError: name 'Style' is not defined` How to fix that? Not familiar with `type annotations`. Could you share a quick demo how to use it like this one: https://www.tutorialspoint.com/changing-the-appearance-of-a-scrollbar-in-tkinter-using-ttk-styles Thanks! – Lod Aug 23 '23 at 19:53
-1

This does not appear to be possible in tkinter on Windows. The below answer says so: ScrolledText Scrollbar Color (Python Tkinter)

Scrollbar documentation: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/scrollbar.html Supported style fields: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Scrollbar.html

I tried passing both 'background' and 'troughcolor' unsuccessfully on my Windows machine. I also tried applying the style to the general scrollbar: style.configure('TScrollbar', background="blue") None of my solutions worked.

Also another forum post agrees that you can't style the scrollbar background here: http://www.gossamer-threads.com/lists/python/python/822292

Community
  • 1
  • 1
spacether
  • 2,136
  • 1
  • 21
  • 28