In this project we combine Python Tkinter with threading to repeatedly fetch external data without freezing the desktop interface.
Our example retrieves the latest available intraday stock price using
yfinance. A background worker thread performs the network request,
while Tkinter remains responsive.
The worker sends its result through a Python Queue. The Tkinter main thread then reads the Queue and updates the displayed price.
External data
|
v
Worker thread
|
v
Queue
|
v
Tkinter main thread
|
+--> Price
+--> Time
+--> Status
Show Table of Contents
Tkinter uses an event loop to process Button clicks, keyboard input, window drawing and other GUI events.
If a network request runs directly on the Tkinter main thread, the window can stop responding while Python waits for the request to finish.
A worker thread allows the network operation to run separately:
Tkinter main thread
|
+--> GUI remains responsive
Worker thread
|
+--> Fetch external data
However, Tkinter widgets should be updated from the Tkinter main thread. Therefore we should not directly update a StringVar from the worker thread.
Install the yfinance package before running the project.
pip install yfinance
Matplotlib is not required for this page. We will use it later in the real-time stock graph project.
The data-fetching function receives the stock symbol and returns normal Python values. It does not update any Tkinter widget.
def fetch_stock_price(symbol):
stock=yf.Ticker(symbol)
data=stock.history(
period='1d',
interval='1m'
)
if data.empty:
raise ValueError(
'No intraday data was returned.'
)
close_values=data['Close'].dropna()
if close_values.empty:
raise ValueError(
'No price data is available.'
)
price=float(
close_values.iloc[-1]
)
timestamp=close_values.index[-1]
return price,timestamp
iloc[-1] returns the most recent value in the
Close series.
A Python Queue provides a simple way to transfer the result from the worker thread back to the main Tkinter thread.
result_queue=queue.Queue()
The worker places either a successful result or an error in the Queue.
def fetch_worker(symbol):
try:
price,timestamp=fetch_stock_price(
symbol
)
result_queue.put(
(
'ok',
symbol,
price,
timestamp
)
)
except Exception as e:
result_queue.put(
(
'error',
symbol,
str(e),
None
)
)
The worker does not call:
price_var.set()
status_var.set()
Label.config()
Those GUI operations are performed by the main thread.
The example requests one-minute intraday data, so we use a 60-second refresh interval:
REFRESH_MS=60000
After receiving a result, Tkinter schedules the next request with
after().
if tracking:
schedule_id=root.after(
REFRESH_MS,
start_fetch
)
This is preferable to continuously running a
while True loop with time.sleep().
The complete example allows the user to enter a ticker symbol, start tracking, stop tracking and view the timestamp of the latest returned data.
A Tkinter Entry widget lets the user enter a ticker such as:
AAPL
MSFT
GOOG
The program converts the input to uppercase before requesting the data.
The Start Tracking Button calls:
start_tracking()
This launches a daemon thread that executes:
fetch_worker(symbol)
The worker creates a yfinance Ticker object and requests one-minute intraday history.
The result is not applied directly to the GUI. Instead it is placed in
result_queue.
The main thread runs:
root.after(
200,
process_queue
)
This checks for completed worker results without blocking the GUI.
When tracking remains active, another request is scheduled after 60 seconds.
A requested ticker may be invalid, the network may be unavailable, the upstream service may return an error, or no intraday data may be available.
Before reading the latest Close value, the program checks:
if data.empty:
raise ValueError(
'No intraday data was returned.'
)
It also checks the Close series:
if close_values.empty:
raise ValueError(
'No price data is available.'
)
The worker sends the error through the same Queue used for successful results.
The earlier example used:
while True:
...
time.sleep(5)
and requested:
interval='1m'
This can request the same one-minute data many times before a new data point is available.
The revised example uses:
REFRESH_MS=60000
and lets Tkinter schedule each new request using after().
This application gives us a reusable foundation for more practical Tkinter projects.
Save the stock symbol, price and timestamp to SQLite and display the saved records using Treeview.
View Stored Stock DataUse Matplotlib to visualize the collected price history.
Real-Time Stock Monitoring with GraphsThe same background-update architecture can be reused with other financial data sources.
AMFI Fund Explorer Tutorial Mutual Fund NAV Tracker using Tkinter GUIA network request can take time. Running it in a worker thread keeps the Tkinter event loop responsive.
Tkinter GUI operations should stay on the Tkinter main thread. The worker passes normal Python data through a Queue and the main thread updates the StringVars and widgets.
No. The application displays the latest available intraday value returned by the data source. Availability and delays may vary.
The example requests one-minute interval data. Requesting it every five seconds usually creates unnecessary repeated requests.
Yes. Enter another supported ticker symbol in the Entry field before starting the tracker.
The program detects an empty result and sends an error back to the Tkinter interface instead of trying to read a missing last row.
Yes. The same worker-thread, Queue and root.after pattern can be used for periodic API calls, databases, sensors, files and other external data sources.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.