Day 27 - Tkinter, *args, **kwargs & Creating GUIs

Day 27 - Tkinter, *args, **kwargs & Creating GUIs

Learning more about Tkinter, a standard Python library for building simple GUIs.

Β·

7 min read

Where's day 26????

I skipped it.....fight me about it πŸ˜„. But for real, skipped writing up and pushing a PR for day 26 cause it wasn't anything new and felt like a waste of time. I was also still in a bad headspace (quick context at the end of this post), so I kept it moving. That leads us to Day 27!

Understanding *args and **kwargs

For day 27, the focus was on *args and **kwargs. *args and **kwargs are special operators that allow functions to accept an arbitrary number of arguments and keyword arguments respectively. Below is a quick definition of both and how they can be useful:

  • *args allows you to pass any number of positional arguments to a function. This is handy when you want to write functions that can handle varying amounts of input data.

  • **kwargs lets you handle named arguments that you have not explicitly defined in advance. This is great for working with functions where you might have a variety of configuration options.

Pros:

  • Flexibility: Both *args and **kwargs provide flexibility in function calls, allowing for more general and adaptable code.

  • Convenience: They can make initializing objects and calling functions cleaner and more intuitive. Let's say, for example, when dealing with a complex set of parameters.

Cons:

  • Readability: Functions using *args and **kwargs can be less explicit, which might lead to code that is harder to understand.

  • Debugging: It can be more challenging to debug issues as the source of incorrect values can be obscured.

A few code examples for my visual folks

Here’s how you might use these in your own Python scripts:

Basic Usage of *args

def my_function(*args):
    for arg in args:
        print(arg)

my_function('Hello', 'World', 123, true)

This function will accept any number of arguments and print each one. So if i wanted to pass 4 arguments, I'd just need to call my_function('Hello', 'World', 123, True) . With the 4th argument being a boolean.

Basic Usage of **kwargs

def my_function(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

my_function(name='Alice', age=25)

This function prints out key-value pairs, accepting any number of named arguments. The same thing goes for **kwargs when it comes to adding boolean values. It gets a bit trickier though but hopefully the updated example helps:

def my_function(**kwargs):
    # Print all keyword arguments
    for key, value in kwargs.items():
        print(f"{key} = {value}")

    # Check if debug mode is enabled
    if kwargs.get("debug", False):  # Explicitly use default value for clarity
        print("Debug mode is enabled.")
    else:
        print("Debug mode is not enabled.")

    # Check if logging is on or off
    logging_status = 'on' if kwargs.get('logging', False) else 'off'
    print(f"Logging is {logging_status}.")

my_function(name='Alice', age=25, debug=True, logging=False)

The expected output of the above code is:

name = Alice
age = 25
debug = True
logging = False
Debug mode is enabled.
Logging is off.

How Tkinter heavily uses args and *kwargs

Tkinter uses *args and **kwargs extensively to make it flexible when creating widgets with varying configurations.

Widget Example

Here’s a Tkinter example from the day's project how *args and **kwargs are useful for creating UI elements with different configurations:

from tkinter import *


def button_clicked():
    print("I got clicked")
    new_text = input.get()
    my_label.config(text=new_text)


window = Tk()
window.title("My First GUI Program")
window.minsize(width=500, height=300)
window.config(padx=100, pady=200)

# Label
my_label = Label(text="I Am a Label", font=("Arial", 24, "bold"))
my_label.config(text="New Text")
my_label.grid(column=0, row=0)
my_label.config(padx=50, pady=50)

# Button
button = Button(text="Click Me", command=button_clicked)
button.grid(column=1, row=1)

new_button = Button(text="New Button")
new_button.grid(column=2, row=0)

# Entry
input = Entry(width=10)
print(input.get())
input.grid(column=3, row=2)


window.mainloop()

I'll run through a quick explanation of each important section.

Import Tkinter

pythonCopy codefrom tkinter import *

This line imports all classes, functions, and variables from the Tkinter module. It allows the script to access Tkinter's GUI components without prefixing them with tkinter. .

Define Button Click Function

def button_clicked():
    print("I got clicked")
    new_text = input.get()
    my_label.config(text=new_text)

This function button_clicked is called when the GUI's button is clicked. It performs a couple actions:

  1. Prints "I got clicked" to the console.

  2. It retrieves text from an entry widget (input), and sets this text as the new label for my_label using config().

Set the Main Window

window = Tk()
window.title("My First GUI Program")
window.minsize(width=500, height=300)
window.config(padx=100, pady=200)

These lines set up the main window of the application:

  • Tk() creates the main window.

  • title() sets the window's title.

  • minsize() specifies the minimum size of the window.

  • config() adds padding around the inside of the window (100 pixels on the sides, 200 pixels on the top and bottom).

Create Label

my_label = Label(text="I Am a Label", font=("Arial", 24, "bold"))
my_label.config(text="New Text")
my_label.grid(column=0, row=0)
my_label.config(padx=50, pady=50)

This section creates a label widget:

  • Label() creates a label with initial text "I Am a Label" and specifies the font.

  • The label text is immediately changed to "New Text" with config().

  • grid() places the label in the grid layout (at column 0, row 0).

  • Additional padding is added around the label.

Create Buttons

button = Button(text="Click Me", command=button_clicked)
button.grid(column=1, row=1)

new_button = Button(text="New Button")
new_button.grid(column=2, row=0)

This code creates two buttons:

  • The first button, when clicked, triggers button_clicked().

  • The buttons are placed using grid(); the first button at column 1, row 1, and the second button at column 2, row 0.

  • The second button is just filler. There is no command attached to it.

Create an Entry Widget

input = Entry(width=10)
print(input.get())
input.grid(column=3, row=2)
  • Entry() creates an entry widget allowing users to input text.

  • input.get() is used to retrieve the current text in the entry widget, which is empty initially and its result ('') is printed.

  • grid() positions the entry widget in the grid.

Start the GUI

window.mainloop()

This line starts the Tkinter event loop, which is necessary to keep the window displaying and responding to user inputs.

That's it, a pretty vanilla GUI created with just Tkinter πŸ™‚.

Conclusion

Using *args and **kwargs can significantly increase the flexibility and reusability of your Python code, making it easier to handle functions with a variable number of parameters. When paired with Tkinter, these operators allow you to create more dynamic and configurable GUIs without committing to a fixed number of parameters in your functions. While they offer great advantages, no need to go crazy and use them everywhere lol. Use it if it helps maintain code clarity and simplicity.

I still have plans to add authentication to my FanFlix project and have been making some adjustments behind the scenes in how I want to tackle my Finance tracker app πŸ™ƒ. I can never make up my mind

Hiatus Context for whoever cares

Emerging from the shadows of sadness

My life is defined by shake-ups, I'm almost certain of it now. Needed to take yet another break away from leveling up and Python projects because of a few things (that I won't go in-depth over):
1. Long-term relationship was getting rocky and ultimately ended last month.
2. Had to make a quick move recently out of our shared home causing me to drop a ton of money in a very short time.
3. And worst of all, a couple of weeks ago, lost a relative that I was extremely close to.

It's hard to keep my focus on leveling up when my world and the general world is in chaos. My heart aches for myself and my family, but it also aches for the innocent lives in the DR Congo, Haiti, Sudan, and Gaza. It's really grim times out here and I've had to shift focus on family and friends. At the end of the day, time is the only thing we can't get back, so for the people I care about, I need to dedicate more time to just having fun and experiencing joy with them. Who knows, anything unexpected can happen just like it did for my fam.

Did you find this article valuable?

Support Kyle Leonard by becoming a sponsor. Any amount is appreciated!

Β