I am using Tkinter with Python 3.11 on Windows. The following program creates a simple window with a menu. The user would click "Game -> Select game directory", whereupon game_directory_selection() function is called for the user to select a directory. If the chosen directory contains a single file with the name utilX.dat (X being 0..9), the directory is used as game directory and some general game configuration is read here self.conf = Config(self.game_directory) and then the specific player configuration is read here self.player = Player(self.game_directory, self.player_id) because 'X' in utilX.dat would be the player_id. However, if the directory contains several player files (let's say util1.dat, util3.dat and util7.dat), then the self.display_file_selection() function is called to allow the player to choose one. This is done by reusing the window to create a new Frame, a Label, a Listbox with the player files and a Button. Once the user has chosen one player file, this Frame is destroyed and the player specific file can be read. import tkinter as tk from tkinter import Menu, Text, Label, Button, Listbox, StringVar, ttk from tkinter import filedialog, messagebox from tkinter import ttk import os.path import sys import time from pathlib import Path #from inventory_view import InventoryViewer from player import Player from config import Config class Game: def __init__(self, root): self.game_directory = None self.filelist = None self._selected_indices = '' self.playerfile = None self.conf = None self.root = root self.root.title("My Game Client") self.create_main_window() print('playerfile', self.playerfile) # (**) def create_main_window(self): # Create menu self.menu = Menu(self.root) self.root.config(menu=self.menu) # Game menu self.game_menu = Menu(self.menu, tearoff=0) self.menu.add_cascade(label="Game", menu=self.game_menu) self.game_menu.add_command(label="Select game directory", command=self.game_directory_selection) self.game_menu.add_separator() self.game_menu.add_command(label="Save game") # TO DO: add command self.game_menu.add_command(label="Inventory viewer", command=self.inventory_view) self.game_menu.add_command(label="Exit", command=self.root.quit) def game_directory_selection(self): """ Choose game directory, or quit.""" while True: self.game_directory = tk.filedialog.askdirectory() if not self.game_directory: if tk.messagebox.askyesno( icon='warning', title="Game directory selection", message="You haven't chosen a game directory. Do you want to quit?"): sys.exit(0) else: p = Path(self.game_directory) self.filelist = list(p.glob('util[0-9].dat')) if not self.filelist: tk.messagebox.showerror( title='Directory error', message='Player files not found in directory') else: # If there is more than one player file, # display a selection dialog to choose one. if len(self.filelist) > 1: filelist_tmp = [f.name for f in self.filelist] self.display_file_selection(filelist_tmp) else: self.playerfile = self.filelist[0] # Extract player ID from filename self.player_id = self.playerfile.stem[-1] print('self.player_id', self.player_id) break # Disable the menu entry for selecting game directory self.game_menu.entryconfigure('Select game directory', state=tk.DISABLED) # Read configuration files into self.conf variable self.conf = Config(self.game_directory) # Read player files into self.player variable self.player = Player(self.game_directory, self.player_id) # (*) def choose_file(self): self._selected_indices = self._listbox.curselection() self.playerfile = self.filelist[self._selected_indices[0]] # Extract player ID from filename self.player_id = self.playerfile.stem[-1] print('self.player_id in choose_file', self.player_id) self.gameselectionframe.destroy() def display_file_selection(self, filelist): # Destroy the previous frame if it exists # try: # _gameselectionframe = self.root.nametowidget('gameselectionframe') # if _gameselectionframe: # _gameselectionframe.destroy() # except KeyError: # pass self.gameselectionframe = ttk.Frame(self.root, padding=(2, 2, 2, 2), name='gameselectionframe') self.gameselectionframe.pack() display_label = ttk.Label(self.gameselectionframe, text="Several player files were found. Please choose one.", width=60) display_label.pack() pl = tk.StringVar(value=filelist) self._listbox = tk.Listbox(self.gameselectionframe, listvariable=pl, height=6, width=20) self._listbox.selection_set(0) self._listbox.pack() btn = ttk.Button(self.gameselectionframe, text='Select', command=self.choose_file) btn.pack() def inventory_view(self): if self.playerfile: self.player = Player(self.game_directory) #self.viewer = InventoryView(self.player.planets, self.conf) else: tk.messagebox.showerror( title='Player file error', message='No player file selected. Please select a game directory first.') if __name__ == "__main__": root = tk.Tk() game = Game(root) root.mainloop() The problem I have when there are several player files (like in the example with the 3 player files) is that self.player = Player(self.game_directory, self.player_id) # (*) is executed before the user has a chance to choose one player file. Then self.player_id is None and the file cannot be properly read. What I need in this case is to prevent the program from continuing until I have set self.player_id properly. I have tried making game_directory_selection() use a tk.Toplevel window with grab_set() to "halt" program/loop execution until the user chooses a file, but to no avail. I have also tried using quit() at the beginning of display_file_selection() to exit the main loop and then mainloop() at the end of display_file_selection() to resume the main loop. I have omitted the implementation of Config and Player classes because they are not relevant. They just read those files onto dictionaries for later use. Also, (**) prints None before the player chooses the directory. Which doesn't bother me because I don't want to print anything there, it is just there to illustrate the fact that the mainloop doest't wait for self.create_main_window() to finish before continuing. Of course, there may be a better way or best practice for doing this, instead of the way I am tackling it... In this question, they use wait_variable() but they say a normal GUI application does not generally work that way. I have also read this question. Thanks in advance. Continue reading...