Creating a Python Graphical User Interface Application with Tkinter

By:   |   Updated: 2023-03-06   |   Comments   |   Related: > Python


Problem

Data analysis and business automation can utilize many Python libraries (Desai, 2019). Some business users must run small Python applications that perform many daily tasks to implement their business strategies. When running a Python application, they may prefer a responsive graphical user interface (GUI) that is user-friendly. Unfortunately, it seems Python developers mainly focus on web, mobile, and server-side programming, and desktop GUI application development does not get much attention (Moore & Harwani, 2019). Therefore, some Python developers may want to learn about building simple GUI tools.

Solution

We can use a standard GUI library for Python, i.e., tkinter, to create GUI applications. The tkinter library comes with Graphical Tool Kit controls (namely widgets) such as labels, entries, radio buttons, drop-down lists, and buttons. In addition, the tkinter.ttk module provides some advanced features like tree views and comboboxes. We need not learn a new programming language to use this library. As Love mentioned, tkinter is the easiest and best library for those new to GUI development (Love, 2018). However, the tkinter library may not be preferable for commercial applications due to limitations, such as a lack of more complex widgets.

The article walks through the steps to build a desktop application that can download stock market data from Yahoo Finance (Smigel, 2022). Figure 1 illustrates the layout of the GUI application. First, the textbox on the window allows users to enter a stock ticker symbol. Then, users should use radio boxes to select a dataset name of interest. Next, users must choose a period and an interval when downloading historical data. Finally, clicking the "Get Data" button triggers a callback function to download data and populates a tree view in the top-level window.

Figure 1 Basic GUI design for the desktop application

Figure 1 Basic GUI design for the desktop application

The tkinter library in Python defines many GUI elements and their functionality. With this library, we often employ these four steps to create a simple GUI application:

  1. Import the tkinter module.
  2. Create a main GUI window.
  3. Add widgets to the window.
  4. Run the window's main loop.

When adding widgets to the main window, we use the tkinter pack or grid geometry managers to arrange them. This article covers several standard widgets, including labels, entries, radio buttons, comboboxes, treeviews, scrollbars, and frames. We also introduce how to connect events that occurred on these widgets to Python callback functions.

In practice, the callback functions may not always be in the same file as the widget definitions. Without loss of generality, we organize all source code into two Python files. The Python file, "MSSQLTips_GUI_app.py," implements the four steps and produces a front-end view of the application. The file "MSSQLTips_GUI_backend.py," includes all callback functions that handle all events that occurred in the window.

The author uses Microsoft Visual Studio 2022 to edit Python scripts and test these scripts using Python 3.10 (64-bit) on Windows 10 Pro 10.0 <X64>. We design the wireframe using WireframeSketcher (Severin, 2023). The application accesses Yahoo Finance data through the "yfinance" package. To create an isolated environment for the project, the author added a virtual environment to the project using this requirement.txt:

appdirs==1.4.4
beautifulsoup4==4.11.1
certifi==2022.12.7
cffi==1.15.1
charset-normalizer==3.0.1
cryptography==39.0.0
frozendict==2.3.4
html5lib==1.1
idna==3.4
lxml==4.9.2
MarkupSafe==2.1.2
multitasking==0.0.11
numpy==1.24.1
pandas==1.5.3
pip==22.3.1
pycparser==2.21
python-dateutil==2.8.2
pytz==2022.7.1
requests==2.28.2
setuptools==65.5.0
six==1.16.0
soupsieve==2.3.2.post1
urllib3==1.26.14
webencodings==0.5.1
yfinance==0.2.9

1 - Creating a Main Window

Creating a simple GUI application using tkinter is not intimidating since this library has a collection of classes defining various GUI elements' functionality. The following code demonstrates the four steps in creating an application window. By saving and running this code, we should see a window with a greeting message inside, as shown in Figure 2. The top-level window (i.e., root) has a frame with a title bar, three control buttons in the top-right, and an area to hold other widgets. These buttons allow users to minimize, maximize, or close a window.

#1, Imports the tkinter module.
import tkinter
#2, Creates a main GUI window.
root = tkinter.Tk()
root.title('MSSQLtips Finance')
#root.iconbitmap('SSQLtips.ico')
root.geometry('420x460+300+300')
root.resizable(0,0)
#3, Adds widgets to the window.
#3.1 Creates frames.
greeting_frame = tkinter.Frame(root)
#3.2 Arranges the frames.
greeting_frame.pack()
#3.3 Uses the greeting frame to organize widgets.
#3.3.1 Adds a label to the greeting frame.
greeting_label = tkinter.Label(greeting_frame, text='Welcome to MSSQLTips')
#3.3.2 Arranges the label.
greeting_label.pack()
#4, Runs the window's main loop.
root.mainloop()
Figure 2 The main window of the GUI application

Figure 2 The main window of the GUI application

The above code starts with importing the tkinter module. Next, the script creates a top-level GUI window by calling the Tk() function. The function returns a Python object that represents the window. Then, we invoke the object's methods to manipulate various attributes of the tkinter window. For example, the geometry() method defines the window's width, height, and position on the screen. In addition, the close button in the window's top right corner allows us to terminate the application.

We added two widgets to the window. i.e., a frame and a label. The frame is a simple rectangle that can hold other widgets. Since the project uses several widgets, we categorize these widgets into different groups and place one group into its respective frame. For example, this program adds the greeting frame to the top-level window and then adds the greeting label to the frame. To arrange these widgets, we invoke the geometry management pack command. When we use the default options of the command, the packer places widgets into their container sequentially. That said, when we add another frame to the window, the frame will be under the first frame.

Finally, the script calls the top-level window's mainloop() method to let the application be in an event listening loop. The event loop keeps the application window open and allows us to handle events that occurred. We can click the close button to terminate the event loop.

2 - Using Frames to Organize Widgets at Coding Level

The GUI application contains different kinds of widgets, and the wireframe indicates that we have the plan to arrange these widgets. We divide the window into several panels and work on each panel independently. In this case, changing the layout in one panel (for example, adding more radio buttons) should not affect the layout of others. Here are the six panels on the window, which stack on top of one another:

  1. The greeting panel contains a label that shows the greeting message.
  2. The textbox panel contains a label and a textbox for users to enter the stock ticker symbol.
  3. The radio panel contains a group of radio buttons.
  4. The combobox panel contains two labels and two comboboxes for users to select values of period and interval.
  5. The button panel contains a button that can trigger an API call.
  6. The tree view panel contains a treeview that visualizes the dataset returned from the API call.

We can use tkinter frame widgets to define the panels in the top-level window. A frame widget works like a container, which is responsible for arranging the position of other widgets. The following script creates and arranges the six frames corresponding to these panels. We pass the parent window as a parameter when creating these frames. We then use packers to place all these frames in the top-level window.

#3, Adds widgets to the window.
#3.1 Creates frames.
greeting_frame = tkinter.Frame(root)
textbox_frame = tkinter.Frame(root)
radio_frame = tkinter.LabelFrame(root, text='Select a dataset')
combobox_frame = tkinter.Frame(root)
button_frame = tkinter.Frame(root)
treeview_frame = tkinter.Frame(root)
#3.2 Arrange frames.
greeting_frame.pack()
textbox_frame.pack()
radio_frame.pack()
combobox_frame.pack()
button_frame.pack()
treeview_frame.pack()

The size and layout of the widgets in a frame determine the size of the frame. So, for example, the size of the greeting frame can be the same as the size of the label inside the frame. Note that we created a LabelFrame for the group of radio buttons. The LabelFrame widget, like the frame widget, can hold other widgets. Similar to the radio panel shown in the wireframe, the LabelFrame widget displays a label as part of the border around the area. This feature makes it an ideal container for radio buttons.

After placing all these frames in the top-level window, we can add widgets to these frames. The Python code in Section 1 demonstrated how to add a label widget to a frame. When we run the script, the application window should look like Figure 1. We cannot see the other five frames because the frames' width and height values are 0. The following sections introduce adding widgets to these frames.

3 - Creating a Single-line Textbox

According to the wireframe, the textbox panel contains a label that explains the purpose of the textbox and a single-line textbox for users to enter the stock ticker symbol. We use the Label and Entry widgets to create the label and textbox. We then use a geometry manager to organize these two GUI elements.

3.1 The Label Widget

We can use a tkinter label widget to display a text or image on the screen. For example, the following code creates a label inside the text box frame. The first argument to the widget is the parent container, i.e., the text box frame, and the second argument passes a string for displaying.

#3.4 Arrange the textbox frame.
#3.4.1 Adds a label to the textbox frame.
entry_label = tkinter.Label(textbox_frame, text='Stock Ticker Symbol:')

The abovementioned code passes a text message as an argument to the Label constructor. However, we may need to change the text after the script creates the widget. In this case, we can use the config() method to modify settings. This method enables us to change widget attributes dynamically. The following code demonstrates the use of this method.

greeting_label.config(text='Please Enter Stock Ticker Symbol:')

3.2 The Entry Widget

This exercise uses a tkinter entry widget to accept users' input. The widget allows users to enter a single-line text. For example, the following code creates a text box inside the text box frame. The parameter represents the parent frame in which we want to place the widget. We use the insert() method to add the initial text to the widget. The insert() method inserts the text at the given position. The first parameter specifies the character position, and the second represents a string to insert.

#3.4.2 Adds a text box to the textbox frame and set the initial value.
text_entry = tkinter.Entry(textbox_frame)
initial_value = 'GOOG'
text_entry.insert(0, initial_value)

When revising the text in the entry widget, we can call the delete() method to remove all existing text and then add the new text. The following code demonstrates the process. Note that, tkinter.END represents the character position just after the last character in the entry widget. Therefore, the range (0, tkinter.END) corresponds to all characters in the widget.

text_entry.delete(0, tkinter.END)
text_entry.insert(0, 'AAPL')

After users enter their text in the text box, we can use the get() method to fetch the text:

text_entry.get()

We can also bind the entry widget to a StringVar variable, which helps manage the value of the entry widget. The change in the variable's value automatically updates the text in the widget. The StringVar object has get() and set() methods, which operate data in the variable, and consequently set or get the entry text (Sharma, 2021). The following code demonstrates this technique:

text =  tkinter.StringVar(textbox_frame)
text_entry = tkinter.Entry(textbox_frame, textvariable = text)
text.set('GOOG')
text.get()

3.3 Geometry Management

The geometry management in tkinter means the interface's layout and design (Wheeler, 2011). The tkinter library provides three built-in geometry managers: the pack, grid, and place managers. The GUI application uses the pack and grid managers to arrange the widgets as specified. Note that a widget does not display if we add it to a frame without using a geometry manager.

The tkinter Pack Manager. The pack manager, a simple geometry manager, manages the widgets in blocks. We have already used this manager to place six frames in the top-level window. In this exercise, the pack manager stacks frames vertically. We also can use this manager to place widgets side by side. For example, the following code adds a label beside the entry:

#3.4.3 Defines the frame layout.
entry_label.pack(side = tkinter.LEFT)
text_entry.pack(side = tkinter.LEFT)

The script would create a window that should look like Figure 3.

Figure 3 The Pack Manager Arranges the Label and the Textbox Side by Side in the GUI.

Figure 3 The Pack Manager Arranges the Label and the Textbox Side by Side in the GUI.

The tkinter Grid Manager. The grid manager arranges the widgets into table-like structures. For example, Figure 4 illustrates a grid manager with four rows and three columns. Even though a pack manager can make such a layout, using a grid manager takes less effort. Moreover, a grid manager can use the columnspan or rowspan option to help widgets span more than one cell and therefore create complex forms.

Figure 4 A grid geometry manager that has four rows and three columns:

Figure 4 A grid geometry manager that has four rows and three columns.

The following two lines of code arrange the label widget and the entry widget in the same row but in different columns. The grid() method informs the grid manager in which grid cells the widgets should live. When we run the script, the GUI should look like Figure 3. It is worth noting that we should not mix grid and pack in the same container.

#3.4.3 Defines the frame layout.
entry_label.grid(row=0, column=0
text_entry.grid(row=0, column=1)

4 - Placing a Radio Button Group in the Frame

The GUI application allows users to pick a dataset name for downloading. The application provides two options, i.e., "Historical Data" and "Institutional Holders." These two options are mutually exclusive, and users must select one and only one of them. Therefore, we use a group of radio buttons to implement these requirements. All radio buttons in this group are associated with the same IntVar variable. In this case, clicking on one button sets the value of this variable. Correspondingly, this change deselects the previously selected button and selects the current one.

The following code adds a group of radio buttons in the radio frame. Note that the "Historical Data" radio button corresponds to a value of 1. By setting the value of the IntVar variable to 1, the application selects this option by default. When selecting the "Institutional Holders," we change the value of the IntVar variable to 2. Next, we use a grid manager to place these two radio buttons in the frame. The window should look like Figure 5. When there are many options in a radio group, we can use a loop to dynamically create all the radio buttons (Klein, 2022).

#3.5 Arranges the radio frame.
#3.5.1 Set initial value.
number = tkinter.IntVar()
number.set(1)
#3.5.2 Adds radio buttons to the radio frame. On selection we can display the value using one Label.
radio_historical_data = tkinter.Radiobutton(radio_frame, 
                                            text = 'Historical Data', 
                                            value = 1, 
                                            variable = number)
radio_institutional_holders = tkinter.Radiobutton(radio_frame, 
                                                  text='Institutional Holders', 
                                                  value=2, 
                                                  variable = number)
#3.5.3 Defines the frame layout.
radio_historical_data.grid(row=0, column=0)
radio_institutional_holders.grid(row=0, column=1)
Figure 5 Place a Group of Radio Buttons in the Frame

Figure 5 Place a Group of Radio Buttons in the Frame

5 - Using Comboboxes to Choose One of Several Choices

After users pick the "Historical Data" dataset using radio buttons, we want them to select valid values of period and interval from predefined options. The combobox widget, provided via the tkinter.ttk module, can satisfy our requirements. We can make the widget behave like a drop-down list, which does not allow users to enter their values when instantiating the widget as read-only. By the way, the combobox widget only works with strings. Therefore, the widget automatically converts other data types to a string type before adding data to the options list.

The following code creates two comboboxes. We also create two labels to explain these two comboboxes. Next, we use a grid manager to arrange these four widgets in one row. Note that we use the current() method to set a default selection. When we run the script, the window should look like Figure 6.

from tkinter import ttk
#3.6 Arranges the combobox frame.
#3.6.1 Add labels, comboboxes and the get button to the frame.
period_label = tkinter.Label(combobox_frame, text='Period:')
period_combobox = ttk.Combobox(combobox_frame, value=['1d','5d','1mo'], state="readonly")
interval_label = tkinter.Label(combobox_frame, text='Interval:')
interval_combobox = ttk.Combobox(combobox_frame, value=['15m','30m','1h'], state="readonly")
#3.6.2 Set default selection.
period_combobox.current(0)
interval_combobox.current(0)
#3.6.3 Define the frame layout
period_label.grid(row=0, column=0)
period_combobox.grid(row=0, column=1)
interval_label.grid(row=0, column=2)
interval_combobox.grid(row=0, column=3)
Figure 6 Add Tow Comboboxes to the Frame.

Figure 6 Add Tow Comboboxes to the Frame.

We can use the get() method to obtain the selected option. The following two lines of code demonstrate the syntax of using this method. The method always returns a string. If there is no selection, we obtain an empty string. When we allow users to enter their values, the combobox widget works like the entry widget.

        period = period_combobox.get()
        interval = interval_combobox.get()

6 - Adding a Button and Enabling Command Binding

After users configure the parameters for downloading a dataset, the GUI application provides a clickable button for users to start the downloading process. The button widget allows us to associate a callback function with an event using the command binding. We assign a function to the button's command option. The function gets called automatically when the left click event occurs on the button. The following code demonstrates the syntax:

# This function is for testing. We place all associated functions in a separated code file.
def greeting():
    greeting_label.config(text = 'You click on me.')
 
#3.7 Arrange the button frame.
#3.7.1 Adds a button to the button frame.
get_button = tkinter.Button(button_frame, 
                            text = "Get Data",
                            command = greeting)
#3.7.2 Defines the frame layout.
get_button.pack()

The Python code creates a button and places the button in the button frame using a pack manager. Meanwhile, we define a callback function and assign the function name to the command option of the button widget. Then, the program invokes the function automatically when the event occurs on the button. For example, when pressing the button, the callback function, greeting(), changes the text on the greeting label. Figure 7 shows the application window after we click on the button.

Figure 7 The GUI Responds to a Button Left Click Event

Figure 7 The GUI Responds to a Button Left Click Event

7 - Visualizing a Dataset Using a Treeview Widget

A data table is an efficient format for visualizing a small amount of quantitative data (Dunn, 2023). We can use a treeview widget to visualize a dataset. The following code demonstrates creating a table visualization using the ttk.Treeview widget. It is worth noting that the treeview widget can exhibit the hierarchy of items in a collection and respond to mouse-click actions.

#3.8 Arrange the treeview frame.
#3.8.1 Adds a treeview to the treeview frame.
columns = ['col0','col1','col2']
default_headings = ['Datetime', 'Open', 'Close']
tree = ttk.Treeview(treeview_frame, columns = columns, show = 'headings')
# Defines the headings
for index, col in enumerate(columns):
    tree.column(col, width = 100, anchor = 'center')
    tree.heading(col, text=default_headings[index])
#3.8.2 Add a scrollbar to the treeview frame.
scrollbar = ttk.Scrollbar(treeview_frame, orient = tkinter.VERTICAL, command = tree.yview)
tree.configure(yscroll = scrollbar.set)
#3.8.3 Defines the frame layout.
tree.grid(row = 0, column = 0)
scrollbar.grid(row = 0, column = 1)
#Add a fake list to the tree
dataset = [['2023-02-14','45.23', '42.65'],
           ['2023-02-15','42.70', '48.92'],
           ['2023-02-16','22.46', '20.98']
           ]
for index in range(len(dataset)):
    tree.insert('', tkinter.END, values=dataset[index])

This code starts with defining a list of columns and headings. Then, we create a Treeview widget and pass the list of columns to the column option. Next, the for-loop specifies the width and heading for each column. After we create a vertical treeview scrollbar which allows users to view all rows in the table, we place the Treeview and Scrollbar widgets in the tree view frame. Finally, we generate a two-dimension list and use the insert() method to add the list to the treeview. The treeview should look like Figure 8.

Figure 8 Using a Treeview Widget to Display Data in Tabular Structure

Figure 8 Using a Treeview Widget to Display Data in Tabular Structure

8 - Event Handling for Widgets

The widgets must respond to events to make the application interactive. For example, in Section 6, we assigned the callback function to the button command option so that pressing the button can change the text on the label. However, we put the function in the same code file as the widget definitions and configurations. When the GUI is complicated, reading and maintaining the source code becomes challenging. Therefore, putting these callback functions in a separate code file is a good idea. This exercise puts all widget definitions into the "MSSQLTips_GUI_app.py" file and all event handlers into the "MSSQLTips_GUI_backend.py" file. To make all callback functions available to the widgets, we import one code file into another:

import MSSQLTips_GUI_backend as backend

8.1 Passing Arguments to a Callback Function

Section 6 assigned the callback function to the command option of the button widget. However, we may need to pass arguments to the callback function. For example, we want to pass variables and widgets to an event handler in another module so that the event handler can perform operations on these widgets. In this case, we can use a lambda expression that allows us to send multiple data through the callback function.

We first define a callback function that accepts arguments, as demonstrated in the following code. The callback function takes four parameters. Based on the value in the number parameter, the function changes the setting of the treeview and the two comboboxes. The callback function can also invoke another function to delete all rows in the treeview.

import tkinter
import yfinance as yf
import pandas as pd
def clear_treeview(treeView):
    for row in treeView.get_children():
        treeView.delete(row)
def make_selection(treeView, number, period_combobox, interval_combobox):
    if number.get() == 1:
        column_headings = ['Datetime', 'Open', 'Close']
        col_anchor = ['center', 'center', 'center']
        period_combobox.config(state = "readonly")
        interval_combobox.config(state = "readonly")
    elif number.get() == 2:
        column_headings = ['Holder', 'Shares', 'Date Reported']
        col_anchor = ['w', 'e', 'center']
        period_combobox.config(state = tkinter.DISABLED)
        interval_combobox.config(state = tkinter.DISABLED)
    clear_treeview(treeView)    
    for index, col in enumerate(column_headings):
        treeView.heading(index, text = col)
        treeView.column(index, anchor=col_anchor[index])

Next, we define and assign a lambda expression to the command option of the widget. The following code shows the syntax. Note that the lambda expression invokes the callback function and passes four arguments.

#3.5.2 Adds radio buttons to the radio frame. On selection we can display the value using one Label.
radio_historical_data = tkinter.Radiobutton(radio_frame, 
                                            text = 'Historical Data', 
                                            value = 1, 
                                            variable = number,
                                            command = lambda:backend.make_selection(tree, number, period_combobox, interval_combobox))
radio_institutional_holders = tkinter.Radiobutton(radio_frame, 
                                                  text='Institutional Holders', 
                                                  value=2, 
                                                  variable = number,
                                                  command = lambda:backend.make_selection(tree, number, period_combobox, interval_combobox))

At this step, we should have two Python code files: MSSQLTips_GUI_app.py and MSSQLTips_GUI_backend.py. We also import the second file into the first one. Running the "MSSQLTips_GUI_app.py" displays a window that should look like Figure 8. The lambda expression executes when we click a radio button. The expression calls the make_selection() function and passes four arguments. Figure 9 illustrates how the window appearance changes when users select the "Institutional Holders" dataset.

Figure 9 The GUI Appearance Changes with the Radio Button Selection Changes

Figure 9 The GUI Appearance Changes with the Radio Button Selection Changes

8.2 Using Event Binding to Assign a Function to an Event

The command binding does not work for all widgets since some widgets (for example labels) do not provide the command option. In addition, the command binding cannot handle all events. When a widget or an event does not support the command option, we can use the event binding technique in which we use the bind() method to assign a function to an event. By default, the tkinter passes the event detail to the handler. We can use a lambda expression to pass more arguments besides the event.

When the application starts, the default stock ticket is "GOOG." We want the application to delete this text when users click the textbox. However, after users enter a new ticket in this textbox, clicking on the box should not delete the text. The following two-step process demonstrates how we achieve this requirement.

We first define a callback function that accepts two arguments, as demonstrated in the following code. The first one is an event that contains the event details. The second one contains the value of the initial message. After the function receives these arguments, it compares the current string in the entry widget to the initial message. If they are the same, the function deletes the initial message.

def entry_click(event, initial_message):
    if event.widget.get() == initial_message:
        event.widget.delete(0, tkinter.END)

Next, we bind a lambda expression to the entry widget. The following code shows the syntax. Note that the lambda expression invokes the callback function and passes the initial message to the function.

#3.4.4 Bind to the event
text_entry.bind("<ButtonPress-1>", lambda event, initial_message = initial_value: backend.entry_click(event, initial_value))

Running the "MSSQLTips_GUI_app.py" displays a window, as shown in Figure 8. The initial text "GOOG" disappears when we click on the textbox. We enter a new ticket, "AAPL," and click on the textbox again; the textbox should not change.

9 - The Complete Source Code

The exercise wants us to create a GUI application to download Yahoo Finance data. When users click the "Get Data" button, the application should invoke Yahoo Finance API and download a dataset according to users' selection. We use the button binding technique to assign a callback function to the command option of the button. The following code defines the callback function:

def get_data(tree, symbol_entry, number, period_combobox, interval_combobox):
    clear_treeview(tree)
    ticket = yf.Ticker(symbol_entry.get())
    if ticket.institutional_holders is None:
        symbol_entry.insert(0, "*")
        symbol_entry.insert(tkinter.END, "*")
        return
    if number.get() == 1:
        period = period_combobox.get()
        interval = interval_combobox.get()
        data = ticket.history(period = period, interval = interval)
        if data.empty == False:
            data.reset_index(inplace = True)
            dataset = data[['Datetime', 'Open', 'Close']].copy()
            dataset['Datetime'] = dataset['Datetime'].dt.strftime("%Y-%m-%d %H:%M")
            dataset[['Open', 'Close']] = dataset[['Open', 'Close']].applymap(lambda x: '{0:.4f}'.format(x))
        else:
            dataset = pd.DataFrame()
    elif number.get() == 2:
        dataset = ticket.institutional_holders[['Holder', 'Shares', 'Date Reported']].copy()
        dataset['Date Reported'] = dataset['Date Reported'].dt.date
    for index in range(len(dataset)):
        #https://tkdocs.com/tutorial/tree.html
        tree.insert('', tkinter.END, values=list(dataset.loc[index]))

Next, we assign the callback function in the "MSSQLTips_GUI_backend.py" file to the button definition in the "MSSQLTips_GUI_app" file, as shown in the following code:

#3.7.1 Adds a button to the button frame.
get_button = tkinter.Button(button_frame, 
                            text = "Get Data",
                            command = lambda:backend.get_data(tree, text_entry, number, period_combobox, interval_combobox))

At this step, the application implements all the business requirements. When we run the application and hit the "Get Data button" in the application window, we should receive a stock market dataset, as shown in Figure 10.

Figure 10 The GUI Application Downloads Data from Yahoo Finance

Figure 10 The GUI Application Downloads Data from Yahoo Finance

Many widgets share attributes such as dimensions, fonts, colors, sizes, and anchors that define the widget's appearance and behavior. So far, we have used the default settings. To make the application friendly, we can apply color to the GUI elements, adjust spaces between these elements, and select font styles for texts on the window. For demonstration purposes, the final product's appearance looks like Figure 11. When we select the "Institutional Holders" dataset, the window should look like Figure 12. Click here for the complete code.

Figure 11 The Appearance of the Final Product

Figure 11 The GUI Application Downloads the Historical Data

Figure 12 The GUI Application Downloads the Institutional Holders Dataset

Figure 12 The GUI Application Downloads the Institutional Holders Dataset

Summary

We created a simple GUI tool to download stock market data from Yahoo Finance. The application allows users to enter a stock ticker symbol in a textbox and select a dataset name from a group of radio buttons. Next, users can click on the "Get Data" button to trigger a callback function that obtains the dataset for users and puts the result into a table. The application also uses several static labels to help users figure out how to work the application.

We started with creating a top-level window. We then placed six frames in the window according to the wireframe. The exercise used these frames to organize other widgets visually and at the coding level. Next, we added widgets to these frames and used geometry managers to arrange these widgets.

This article covered the basics of tkinter widgets, including frames, labels, radio buttons, comboboxes, buttons, and treeview. We also introduced the use of pack managers and grid managers. Next, we explored the command binding and event binding techniques in which we used a lambda expression to help pass arguments to the bound callback functions. Finally, the article provided the complete source code that covers all steps to develop the GUI application.

Reference

Desai, R. (2019). Top 10 Python Libraries for Data Science. https://towardsdatascience.com/top-10-python-libraries-for-data-science-cd82294ec266.

Dunn, K. (2023). Process Improvement Using Data. https://learnche.org/pid/.

Klein, B. (2022). Radio Buttons in Tkinter. https://python-course.eu/tkinter/radio-buttons-in-tkinter.php.

Love, D. (2018). Python Tkinter By Example. https://github.com/Dvlv/Tkinter-By-Example.

Moore, D. A. & Harwani, M. B. (2019). Python GUI Programming - A Complete Reference Guide. Birmingham, UK: Packt Publishing.

Severin, P. (2023). WireframeSketcher. https://wireframesketcher.com.

Sharma, Y. (2021). Tkinter StringVar with Examples – Tkinter Tutorial. https://www.askpython.com/python-modules/tkinter/stringvar-with-examples.

Smigel, L. (2022). yfinance Python Tutorial (2023). https://analyzingalpha.com/yfinance-python.

Wheeler, B. (2011). Tcl/Tk 8.5 Programming Cookbook. Birmingham, UK: Packt Publishing.

Next Steps


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Nai Biao Zhou Nai Biao Zhou is a Senior Software Developer with 20+ years of experience in software development, specializing in Data Warehousing, Business Intelligence, Data Mining and solution architecture design.

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips


Article Last Updated: 2023-03-06

Comments For This Article

















get free sql tips
agree to terms