0

I'm using tkinter to make a calculator. However, whenever I use buttons I'm stuck with the ugly look of the macOS buttons and I's like to make them look like the ones on Windows. I'm also not able to change the background color. I've tried to use tkmacosx to change the background color but it didn't work.

My expected output:

enter image description here

My output:

enter image description here

My code:

import tkinter as tk


LARGE_FONT_STYLE = ("Arial", 40, "bold")
SMALL_FONT_STYLE = ("Arial", 16)
DIGITS_FONT_STYLE = ("Arial", 25, "bold")
DEFAULT_FONT_STYLE = ("Arial", 20)

OFF_WHITE = "#F8FAFF"
WHITE = "#FFFFFF"
LIGHT_BLUE = "#CCDDFF"
LIGHT_GRAY = "#F5F5F5"
LABEL_COLOR = "#25265E"


class Calculator:
    def __init__(self):
        self.window = tk.Tk()
        self.window.geometry("375x667")
        self.window.resizable(0, 0)
        self.window.title("Calculator")

        self.total_expression = "0"
        self.current_expression = "0"
        self.display_frame = self.create_display_frame()

        self.total_label, self.label = self.create_display_labels()

        self.digits = {
            7: (1, 1), 8: (1, 2), 9: (1, 3),
            4: (2, 1), 5: (2, 2), 6: (2, 3),
            1: (3, 1), 2: (3, 2), 3: (3, 3),
            0: (4, 2), ".": (4, 1)
        }
        self.operations = {"/": "\u00F7", "*": "\u00D7", "-": "-", "+": "+"}
        self.buttons_frame = self.create_buttons_frame()

        self.buttons_frame.rowconfigure(0, weight=1)
        for x in range(1, 5):
            self.buttons_frame.rowconfigure(x, weight=1)
            self.buttons_frame.columnconfigure(x, weight=1)

        self.create_digit_button()
        self.create_operator_button()
        self.create_special_button()

    def create_special_button(self):
        self.create_clear_button()
        self.create_equals_button()

    def create_display_labels(self):
        total_label = tk.Label(self.display_frame, text=self.total_expression, anchor=tk.E, bg=LIGHT_GRAY,
                               fg=LABEL_COLOR, padx=24, font=SMALL_FONT_STYLE)
        total_label.pack(expand=True, fill="both")

        label = tk.Label(self.display_frame, text=self.current_expression, anchor=tk.E, bg=LIGHT_GRAY,
                         fg=LABEL_COLOR, padx=24, font=LARGE_FONT_STYLE)
        label.pack(expand=True, fill="both")

        return total_label, label

    def create_display_frame(self):
        frame = tk.Frame(self.window, height=221, bg=LIGHT_GRAY)
        frame.pack(expand=True, fill="both")
        return frame

    def create_digit_button(self):
        for digit, grid_value in self.digits.items():
            button = tk.Button(self.buttons_frame, text=str(digit), bg=WHITE, fg=LABEL_COLOR, font=DIGITS_FONT_STYLE,
                               borderwidth=0)
            button.grid(row=grid_value[0], column=grid_value[1], sticky=tk.NSEW)

    def create_operator_button(self):
        i = 0
        for operator, symbol in self.operations.items():
            button = tk.Button(self.buttons_frame, text=symbol, bg=OFF_WHITE, fg=LABEL_COLOR, font=DEFAULT_FONT_STYLE,
                               borderwidth=0)
            button.grid(row=i, column=4, sticky=tk.NSEW)
            i += 1

    def create_clear_button(self):
        button = tk.Button(self.buttons_frame, text="C", bg=OFF_WHITE, fg=LABEL_COLOR, font=DEFAULT_FONT_STYLE,
                           borderwidth=0)
        button.grid(row=0, column=1, columnspan=3, sticky=tk.NSEW)

    def create_equals_button(self):
        button = tk.Button(self.buttons_frame, text="+", bg=LIGHT_BLUE, fg=LABEL_COLOR, font=DEFAULT_FONT_STYLE,
                           borderwidth=0)
        button.grid(row=4, column=3, columnspan=2, sticky=tk.NSEW)

    def create_buttons_frame(self):
        frame = tk.Frame(self.window)
        frame.pack(expand=True, fill="both")
        return frame

    def run(self):
        self.window.mainloop()


if __name__ == "__main__":
    calc = Calculator()
    calc.run()
Code With Anish
  • 95
  • 1
  • 1
  • 12
  • You could create images for those buttons and then use the `image` argument for buttons to add those images to the buttons – Matiiss Jul 12 '21 at 22:44

2 Answers2

1

macOS Big Sur (11.0.1)

So, tkmacosx must work perfectly. Maybe you import tkmacosx, but continued to use tkinter buttons?

Here is my code, and it change background, foreground color.

"borderless=1" removing borders of button.

"focuscolor=''" removing blue border, when you press the button.

buttonExit = tkmacosx.Button(mainWindow, text='✕', font=buttonFont, anchor='center', height=15, width=15, fg='#740000', bg='#ff5f56', activebackground='#be4741', activeforeground='#740000', borderless=1, focuscolor='', command=lambda: mainWindow.destroy())

buttonExit.place(x=0, y=0)
PCM
  • 2,881
  • 2
  • 8
  • 30
LNxD
  • 65
  • 8
  • Thanks, I was able to change the background color, and do you know any way to remove the borders on each button? – Code With Anish Jul 13 '21 at 00:08
  • I tried borderless=1 and it didn't do anything – Code With Anish Jul 13 '21 at 00:19
  • @CodeWithAnish, you can try "bordercolor", I tried right now, and it changes the color of border, but if I want to change border color to mainWindow color(remove or hide border), it does nothing, funny. borderless=1 still works, why not for you, idk :( – LNxD Jul 13 '21 at 08:23
  • @CodeWithAnish You could maybe try `borderless=True` (however for the computer that will probably be the same as 1, but You might as well try) – Matiiss Jul 13 '21 at 08:23
  • To format code add ``` at the top and bottom of Your code (those are backticks and NOT quotation marks) – Matiiss Jul 13 '21 at 08:23
1

The Button color issue on MacOS has been around for a long time, and it is interesting, especially since the issue doesn't exist with the Label widget.

I authored a project on PyPI called [TTWidgets][1] which will solve your Button background/foreground color issue. It won't help with the overall Mac look-and-feel of the buttons, however.

The TTWidgets project implements multi-color, multi-font, multi-graphic Buttons and Labels by implementing a collection of Tkinter Labels. Because the implementation is based on Labels rather than Buttons, your fg/bg color problem will be solved.

from ttwidgets import TTButton

The API for the TTButton is a superset of the tkinter.Button API, so you shouldn't have to make any other changes other than using a TTButton instead of a Tkinter Button. [1]: https://pypi.org/project/ttwidgets/

GaryMBloom
  • 5,350
  • 1
  • 24
  • 32