Tkinter

GUI toolkit included in Python standard library. Based on Tcl/Tk, immediately usable without additional installation. Optimal for simple applications and prototyping with low learning cost.

DesktopPythonGUIStandard LibraryLightweight

Framework

Tkinter

Overview

Tkinter is a lightweight GUI framework included in Python's standard library. No additional installation required, enabling simple desktop application development. Ideal for learning, prototyping, and lightweight tool development, widely used as an introduction to desktop app development for Python programmers.

Details

Tkinter holds a solid position as the "first choice" for Python desktop development in 2025. As part of Python's standard library for over 20 years, it has advantages in stability and compatibility over other GUI frameworks.

The key feature is no additional installation required. GUI application development is immediately possible with just Python installed, making it the most accessible GUI framework for beginners. Based on Tcl/Tk, it's lightweight, memory-efficient, and provides sufficient functionality for simple applications.

Widely adopted in education, prototype development, internal tools, data analysis GUIs, and configuration screens. Tkinter is used in IDLE editor, pip-GUI, and many Python learning material sample applications, serving as the foundation for Python developers' desktop application development.

Pros and Cons

Pros

  • Standard Library: Available immediately without additional installation
  • Lightweight: Minimal resource consumption for simple GUI creation
  • Low Learning Curve: Few concepts needed for basic GUI creation
  • Stability: Over 20 years of proven track record and high compatibility
  • Cross-platform: Windows, macOS, Linux support
  • Rich Information: Numerous tutorials and learning resources
  • Prototyping: Suitable for rapid UI prototyping
  • No Dependencies: Development environment complete with Python only

Cons

  • Appearance Limitations: Not suitable for modern UI design
  • Limited Widgets: Only basic components, few advanced widgets
  • Customization: Limited appearance customization options
  • Responsiveness: Not suitable for complex layouts
  • Animation: Difficult to implement dynamic UI effects
  • Scalability: Not suitable for large-scale applications

Key Links

Code Examples

Hello World Application

# hello_world.py
import tkinter as tk
from tkinter import ttk

class HelloWorldApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Tkinter Hello World")
        self.root.geometry("300x150")
        
        # Main frame
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # Label
        self.label = ttk.Label(self.main_frame, text="Hello, Tkinter!")
        self.label.grid(row=0, column=0, columnspan=2, pady=10)
        
        # Button
        self.button = ttk.Button(
            self.main_frame, 
            text="Click me", 
            command=self.on_button_click
        )
        self.button.grid(row=1, column=0, columnspan=2, pady=5)
        
        # Counter display
        self.counter_label = ttk.Label(self.main_frame, text="Click count: 0")
        self.counter_label.grid(row=2, column=0, columnspan=2, pady=5)
        
        # Window resize settings
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        self.main_frame.columnconfigure(0, weight=1)
        
        self.click_count = 0
    
    def on_button_click(self):
        self.click_count += 1
        self.counter_label.config(text=f"Click count: {self.click_count}")
        if self.click_count == 1:
            self.label.config(text="Button clicked!")
        else:
            self.label.config(text=f"Clicked {self.click_count} times!")

if __name__ == "__main__":
    root = tk.Tk()
    app = HelloWorldApp(root)
    root.mainloop()

Basic Widget Usage

# basic_widgets.py
import tkinter as tk
from tkinter import ttk, messagebox

class BasicWidgetsApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Basic Widgets Example")
        self.root.geometry("400x500")
        
        # Scrollable frame
        self.setup_scrollable_frame()
        self.create_widgets()
    
    def setup_scrollable_frame(self):
        # Frame with scrollbar
        self.canvas = tk.Canvas(self.root)
        self.scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = ttk.Frame(self.canvas)
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )
        
        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)
        
        self.canvas.pack(side="left", fill="both", expand=True)
        self.scrollbar.pack(side="right", fill="y")
    
    def create_widgets(self):
        # Title
        title = ttk.Label(self.scrollable_frame, text="Basic Widget Collection", font=("Arial", 16, "bold"))
        title.pack(pady=10)
        
        # Input fields
        self.create_entry_section()
        
        # Buttons
        self.create_button_section()
        
        # Checkboxes and radio buttons
        self.create_checkbox_radio_section()
        
        # Listbox and combobox
        self.create_listbox_combobox_section()
        
        # Scale and progress bar
        self.create_scale_progress_section()
        
        # Text area
        self.create_text_section()
    
    def create_entry_section(self):
        # Entry fields
        entry_frame = ttk.LabelFrame(self.scrollable_frame, text="Text Input", padding=10)
        entry_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(entry_frame, text="Name:").grid(row=0, column=0, sticky="w")
        self.name_entry = ttk.Entry(entry_frame, width=30)
        self.name_entry.grid(row=0, column=1, padx=5, pady=2)
        
        ttk.Label(entry_frame, text="Password:").grid(row=1, column=0, sticky="w")
        self.password_entry = ttk.Entry(entry_frame, show="*", width=30)
        self.password_entry.grid(row=1, column=1, padx=5, pady=2)
        
        # Show entry content button
        ttk.Button(
            entry_frame, 
            text="Show Content", 
            command=self.show_entry_content
        ).grid(row=2, column=1, sticky="e", pady=5)
    
    def create_button_section(self):
        # Buttons
        button_frame = ttk.LabelFrame(self.scrollable_frame, text="Buttons", padding=10)
        button_frame.pack(fill="x", padx=10, pady=5)
        
        button_row = ttk.Frame(button_frame)
        button_row.pack(fill="x")
        
        ttk.Button(button_row, text="Info", command=lambda: messagebox.showinfo("Info", "Information message")).pack(side="left", padx=2)
        ttk.Button(button_row, text="Warning", command=lambda: messagebox.showwarning("Warning", "Warning message")).pack(side="left", padx=2)
        ttk.Button(button_row, text="Error", command=lambda: messagebox.showerror("Error", "Error message")).pack(side="left", padx=2)
    
    def create_checkbox_radio_section(self):
        # Checkboxes and radio buttons
        check_radio_frame = ttk.LabelFrame(self.scrollable_frame, text="Selection", padding=10)
        check_radio_frame.pack(fill="x", padx=10, pady=5)
        
        # Checkboxes
        self.check_vars = {}
        check_frame = ttk.Frame(check_radio_frame)
        check_frame.pack(fill="x")
        
        ttk.Label(check_frame, text="Favorite languages:").pack(anchor="w")
        for lang in ["Python", "JavaScript", "Java", "C++"]:
            var = tk.BooleanVar()
            self.check_vars[lang] = var
            ttk.Checkbutton(check_frame, text=lang, variable=var).pack(anchor="w")
        
        # Radio buttons
        radio_frame = ttk.Frame(check_radio_frame)
        radio_frame.pack(fill="x", pady=(10, 0))
        
        ttk.Label(radio_frame, text="Experience level:").pack(anchor="w")
        self.radio_var = tk.StringVar(value="Beginner")
        for level in ["Beginner", "Intermediate", "Advanced"]:
            ttk.Radiobutton(radio_frame, text=level, variable=self.radio_var, value=level).pack(anchor="w")
        
        # Show selection button
        ttk.Button(
            check_radio_frame, 
            text="Show Selection", 
            command=self.show_selection
        ).pack(pady=5)
    
    def create_listbox_combobox_section(self):
        # Listbox and combobox
        list_combo_frame = ttk.LabelFrame(self.scrollable_frame, text="Lists and Combos", padding=10)
        list_combo_frame.pack(fill="x", padx=10, pady=5)
        
        list_frame = ttk.Frame(list_combo_frame)
        list_frame.pack(fill="x")
        
        # Listbox
        ttk.Label(list_frame, text="City selection:").pack(anchor="w")
        self.listbox = tk.Listbox(list_frame, height=4)
        cities = ["Tokyo", "Osaka", "Nagoya", "Fukuoka", "Sapporo", "Sendai"]
        for city in cities:
            self.listbox.insert(tk.END, city)
        self.listbox.pack(fill="x", pady=2)
        
        # Combobox
        ttk.Label(list_frame, text="Country selection:").pack(anchor="w", pady=(10, 0))
        self.combobox = ttk.Combobox(list_frame, values=["Japan", "USA", "UK", "Germany", "France"])
        self.combobox.pack(fill="x", pady=2)
        self.combobox.set("Japan")
    
    def create_scale_progress_section(self):
        # Scale and progress bar
        scale_progress_frame = ttk.LabelFrame(self.scrollable_frame, text="Scale and Progress", padding=10)
        scale_progress_frame.pack(fill="x", padx=10, pady=5)
        
        # Scale
        ttk.Label(scale_progress_frame, text="Value setting:").pack(anchor="w")
        self.scale_var = tk.DoubleVar()
        self.scale = ttk.Scale(
            scale_progress_frame, 
            from_=0, 
            to=100, 
            variable=self.scale_var,
            command=self.on_scale_change
        )
        self.scale.pack(fill="x", pady=2)
        
        self.scale_label = ttk.Label(scale_progress_frame, text="Value: 0")
        self.scale_label.pack(anchor="w")
        
        # Progress bar
        ttk.Label(scale_progress_frame, text="Progress:").pack(anchor="w", pady=(10, 0))
        self.progress = ttk.Progressbar(scale_progress_frame, mode='determinate')
        self.progress.pack(fill="x", pady=2)
        
        ttk.Button(
            scale_progress_frame, 
            text="Start Progress", 
            command=self.start_progress
        ).pack(pady=5)
    
    def create_text_section(self):
        # Text area
        text_frame = ttk.LabelFrame(self.scrollable_frame, text="Text Area", padding=10)
        text_frame.pack(fill="x", padx=10, pady=5)
        
        self.text_area = tk.Text(text_frame, height=5, wrap=tk.WORD)
        text_scrollbar = ttk.Scrollbar(text_frame, orient="vertical", command=self.text_area.yview)
        self.text_area.configure(yscrollcommand=text_scrollbar.set)
        
        self.text_area.pack(side="left", fill="both", expand=True)
        text_scrollbar.pack(side="right", fill="y")
        
        self.text_area.insert("1.0", "Enter your text here...")
    
    def show_entry_content(self):
        name = self.name_entry.get()
        password = self.password_entry.get()
        messagebox.showinfo("Input Content", f"Name: {name}\nPassword: {'*' * len(password)}")
    
    def show_selection(self):
        # Checkbox selection
        selected_langs = [lang for lang, var in self.check_vars.items() if var.get()]
        langs_text = ", ".join(selected_langs) if selected_langs else "None"
        
        # Radio button selection
        level = self.radio_var.get()
        
        messagebox.showinfo("Selection", f"Favorite languages: {langs_text}\nExperience level: {level}")
    
    def on_scale_change(self, value):
        self.scale_label.config(text=f"Value: {float(value):.1f}")
        self.progress['value'] = float(value)
    
    def start_progress(self):
        # Progress bar animation
        self.progress['value'] = 0
        self.animate_progress()
    
    def animate_progress(self):
        current_value = self.progress['value']
        if current_value < 100:
            self.progress['value'] = current_value + 2
            self.root.after(50, self.animate_progress)

if __name__ == "__main__":
    root = tk.Tk()
    app = BasicWidgetsApp(root)
    root.mainloop()

Layout Management (Grid, Pack, Place)

# layout_examples.py
import tkinter as tk
from tkinter import ttk

class LayoutExamples:
    def __init__(self, root):
        self.root = root
        self.root.title("Layout Management Examples")
        self.root.geometry("600x400")
        
        # Create notebook (tabs)
        self.notebook = ttk.Notebook(root)
        self.notebook.pack(fill="both", expand=True, padx=10, pady=10)
        
        # Create tabs for each layout
        self.create_grid_tab()
        self.create_pack_tab()
        self.create_place_tab()
    
    def create_grid_tab(self):
        # Grid layout tab
        grid_frame = ttk.Frame(self.notebook)
        self.notebook.add(grid_frame, text="Grid Layout")
        
        # Calculator-like layout
        ttk.Label(grid_frame, text="Grid Layout - Calculator Style", font=("Arial", 12, "bold")).grid(row=0, column=0, columnspan=4, pady=10)
        
        # Display
        self.display_var = tk.StringVar(value="0")
        display = ttk.Entry(grid_frame, textvariable=self.display_var, font=("Arial", 14), justify="right", state="readonly")
        display.grid(row=1, column=0, columnspan=4, sticky="ew", padx=5, pady=5)
        
        # Button layout
        buttons = [
            ['C', '±', '%', '÷'],
            ['7', '8', '9', '×'],
            ['4', '5', '6', '-'],
            ['1', '2', '3', '+'],
            ['0', '', '.', '=']
        ]
        
        for row_idx, row in enumerate(buttons):
            for col_idx, text in enumerate(row):
                if text:
                    if text == '0':
                        btn = ttk.Button(grid_frame, text=text, command=lambda t=text: self.calculator_click(t))
                        btn.grid(row=row_idx+2, column=col_idx, columnspan=2, sticky="ew", padx=2, pady=2)
                    else:
                        btn = ttk.Button(grid_frame, text=text, command=lambda t=text: self.calculator_click(t))
                        btn.grid(row=row_idx+2, column=col_idx, sticky="ew", padx=2, pady=2)
        
        # Grid weight configuration
        for i in range(4):
            grid_frame.columnconfigure(i, weight=1)
    
    def create_pack_tab(self):
        # Pack layout tab
        pack_frame = ttk.Frame(self.notebook)
        self.notebook.add(pack_frame, text="Pack Layout")
        
        ttk.Label(pack_frame, text="Pack Layout - Toolbar Style", font=("Arial", 12, "bold")).pack(pady=10)
        
        # Top toolbar
        toolbar = ttk.Frame(pack_frame, relief="raised", borderwidth=1)
        toolbar.pack(fill="x", padx=5, pady=2)
        
        ttk.Button(toolbar, text="New").pack(side="left", padx=2)
        ttk.Button(toolbar, text="Open").pack(side="left", padx=2)
        ttk.Button(toolbar, text="Save").pack(side="left", padx=2)
        ttk.Separator(toolbar, orient="vertical").pack(side="left", fill="y", padx=5)
        ttk.Button(toolbar, text="Copy").pack(side="left", padx=2)
        ttk.Button(toolbar, text="Paste").pack(side="left", padx=2)
        
        # Main area
        main_area = ttk.Frame(pack_frame)
        main_area.pack(fill="both", expand=True, padx=5, pady=5)
        
        # Left sidebar
        sidebar = ttk.LabelFrame(main_area, text="Sidebar", width=150)
        sidebar.pack(side="left", fill="y", padx=(0, 5))
        sidebar.pack_propagate(False)  # Fixed size
        
        for i in range(5):
            ttk.Button(sidebar, text=f"Menu {i+1}").pack(fill="x", padx=5, pady=2)
        
        # Central content
        content = ttk.LabelFrame(main_area, text="Content Area")
        content.pack(side="left", fill="both", expand=True)
        
        ttk.Label(content, text="Main content is displayed here", font=("Arial", 14)).pack(expand=True)
        
        # Bottom status bar
        statusbar = ttk.Frame(pack_frame, relief="sunken", borderwidth=1)
        statusbar.pack(fill="x", side="bottom", padx=5, pady=2)
        
        ttk.Label(statusbar, text="Status: Ready").pack(side="left", padx=5)
        ttk.Label(statusbar, text="Line: 1, Col: 1").pack(side="right", padx=5)
    
    def create_place_tab(self):
        # Place layout tab
        place_frame = ttk.Frame(self.notebook)
        self.notebook.add(place_frame, text="Place Layout")
        
        ttk.Label(place_frame, text="Place Layout - Absolute Positioning", font=("Arial", 12, "bold")).place(x=10, y=10)
        
        # Relative positioning
        ttk.Label(place_frame, text="Top Left", background="lightblue").place(relx=0.1, rely=0.2, relwidth=0.2, relheight=0.1)
        ttk.Label(place_frame, text="Top Right", background="lightgreen").place(relx=0.7, rely=0.2, relwidth=0.2, relheight=0.1)
        ttk.Label(place_frame, text="Center", background="lightyellow").place(relx=0.4, rely=0.5, relwidth=0.2, relheight=0.1, anchor="center")
        ttk.Label(place_frame, text="Bottom Left", background="lightcoral").place(relx=0.1, rely=0.8, relwidth=0.2, relheight=0.1)
        ttk.Label(place_frame, text="Bottom Right", background="lightpink").place(relx=0.7, rely=0.8, relwidth=0.2, relheight=0.1)
        
        # Absolute positioning
        ttk.Button(place_frame, text="Absolute Button 1").place(x=50, y=100, width=120, height=30)
        ttk.Button(place_frame, text="Absolute Button 2").place(x=200, y=140, width=120, height=30)
        
        # Overlapping example
        canvas = tk.Canvas(place_frame, width=200, height=100, background="white")
        canvas.place(x=350, y=250)
        
        canvas.create_rectangle(10, 10, 90, 50, fill="red", tags="rect1")
        canvas.create_rectangle(50, 30, 130, 70, fill="blue", tags="rect2")
        canvas.create_text(100, 80, text="Overlapping", tags="text1")
    
    def calculator_click(self, text):
        current = self.display_var.get()
        if text == 'C':
            self.display_var.set("0")
        elif text in "0123456789":
            if current == "0":
                self.display_var.set(text)
            else:
                self.display_var.set(current + text)
        elif text == ".":
            if "." not in current:
                self.display_var.set(current + ".")
        else:
            # Operators (simple implementation)
            self.display_var.set(current + " " + text + " ")

if __name__ == "__main__":
    root = tk.Tk()
    app = LayoutExamples(root)
    root.mainloop()

File Operations and Dialogs

# file_operations.py
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
from pathlib import Path

class FileOperationsApp:
    def __init__(self, root):
        self.root = root
        self.root.title("File Operations and Dialogs")
        self.root.geometry("600x500")
        
        self.current_file = None
        self.setup_ui()
    
    def setup_ui(self):
        # Menu bar
        self.create_menu()
        
        # Toolbar
        toolbar = ttk.Frame(self.root)
        toolbar.pack(fill="x", padx=5, pady=2)
        
        ttk.Button(toolbar, text="New", command=self.new_file).pack(side="left", padx=2)
        ttk.Button(toolbar, text="Open", command=self.open_file).pack(side="left", padx=2)
        ttk.Button(toolbar, text="Save", command=self.save_file).pack(side="left", padx=2)
        ttk.Button(toolbar, text="Save As", command=self.save_as_file).pack(side="left", padx=2)
        ttk.Separator(toolbar, orient="vertical").pack(side="left", fill="y", padx=5)
        ttk.Button(toolbar, text="Select Folder", command=self.select_folder).pack(side="left", padx=2)
        
        # Main area
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill="both", expand=True, padx=5, pady=5)
        
        # File info display
        info_frame = ttk.LabelFrame(main_frame, text="File Information", padding=5)
        info_frame.pack(fill="x", pady=(0, 5))
        
        self.file_info_label = ttk.Label(info_frame, text="File: New Document")
        self.file_info_label.pack(anchor="w")
        
        # Text editor
        editor_frame = ttk.LabelFrame(main_frame, text="Text Editor", padding=5)
        editor_frame.pack(fill="both", expand=True)
        
        # Text widget and scrollbar
        self.text_widget = tk.Text(editor_frame, wrap=tk.WORD, undo=True)
        scrollbar = ttk.Scrollbar(editor_frame, orient="vertical", command=self.text_widget.yview)
        self.text_widget.configure(yscrollcommand=scrollbar.set)
        
        self.text_widget.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # Text change event
        self.text_widget.bind('<Modified>', self.on_text_modified)
        
        # Status bar
        self.status_var = tk.StringVar(value="Ready")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief="sunken", anchor="w")
        status_bar.pack(fill="x", side="bottom", padx=5, pady=2)
    
    def create_menu(self):
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # File menu
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="New", command=self.new_file, accelerator="Ctrl+N")
        file_menu.add_command(label="Open", command=self.open_file, accelerator="Ctrl+O")
        file_menu.add_separator()
        file_menu.add_command(label="Save", command=self.save_file, accelerator="Ctrl+S")
        file_menu.add_command(label="Save As", command=self.save_as_file, accelerator="Ctrl+Shift+S")
        file_menu.add_separator()
        file_menu.add_command(label="Exit", command=self.root.quit)
        
        # Edit menu
        edit_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Edit", menu=edit_menu)
        edit_menu.add_command(label="Undo", command=lambda: self.text_widget.edit_undo(), accelerator="Ctrl+Z")
        edit_menu.add_command(label="Redo", command=lambda: self.text_widget.edit_redo(), accelerator="Ctrl+Y")
        edit_menu.add_separator()
        edit_menu.add_command(label="Select All", command=self.select_all, accelerator="Ctrl+A")
        
        # Keyboard shortcuts
        self.root.bind('<Control-n>', lambda e: self.new_file())
        self.root.bind('<Control-o>', lambda e: self.open_file())
        self.root.bind('<Control-s>', lambda e: self.save_file())
        self.root.bind('<Control-S>', lambda e: self.save_as_file())
        self.root.bind('<Control-a>', lambda e: self.select_all())
    
    def new_file(self):
        if self.check_unsaved_changes():
            self.text_widget.delete(1.0, tk.END)
            self.current_file = None
            self.update_file_info()
            self.status_var.set("Created new file")
    
    def open_file(self):
        if not self.check_unsaved_changes():
            return
        
        file_path = filedialog.askopenfilename(
            title="Open File",
            filetypes=[
                ("Text files", "*.txt"),
                ("Python files", "*.py"),
                ("All files", "*.*")
            ]
        )
        
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    content = file.read()
                    self.text_widget.delete(1.0, tk.END)
                    self.text_widget.insert(1.0, content)
                    self.current_file = file_path
                    self.update_file_info()
                    self.text_widget.edit_modified(False)
                    self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
            except UnicodeDecodeError:
                try:
                    with open(file_path, 'r', encoding='shift_jis') as file:
                        content = file.read()
                        self.text_widget.delete(1.0, tk.END)
                        self.text_widget.insert(1.0, content)
                        self.current_file = file_path
                        self.update_file_info()
                        self.text_widget.edit_modified(False)
                        self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
                except Exception as e:
                    messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
            except Exception as e:
                messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
    
    def save_file(self):
        if self.current_file:
            self.save_to_file(self.current_file)
        else:
            self.save_as_file()
    
    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(
            title="Save As",
            defaultextension=".txt",
            filetypes=[
                ("Text files", "*.txt"),
                ("Python files", "*.py"),
                ("All files", "*.*")
            ]
        )
        
        if file_path:
            self.save_to_file(file_path)
            self.current_file = file_path
            self.update_file_info()
    
    def save_to_file(self, file_path):
        try:
            content = self.text_widget.get(1.0, tk.END + "-1c")  # Exclude last newline
            with open(file_path, 'w', encoding='utf-8') as file:
                file.write(content)
            self.text_widget.edit_modified(False)
            self.status_var.set(f"Saved: {os.path.basename(file_path)}")
        except Exception as e:
            messagebox.showerror("Error", f"Could not save file:\n{str(e)}")
    
    def select_folder(self):
        folder_path = filedialog.askdirectory(title="Select Folder")
        if folder_path:
            self.show_folder_contents(folder_path)
    
    def show_folder_contents(self, folder_path):
        # Show folder contents in new window
        folder_window = tk.Toplevel(self.root)
        folder_window.title(f"Folder Contents: {os.path.basename(folder_path)}")
        folder_window.geometry("400x300")
        
        # Listbox and scrollbar
        frame = ttk.Frame(folder_window)
        frame.pack(fill="both", expand=True, padx=10, pady=10)
        
        listbox = tk.Listbox(frame)
        scrollbar = ttk.Scrollbar(frame, orient="vertical", command=listbox.yview)
        listbox.configure(yscrollcommand=scrollbar.set)
        
        # Display files and folders
        try:
            items = os.listdir(folder_path)
            for item in sorted(items):
                item_path = os.path.join(folder_path, item)
                if os.path.isdir(item_path):
                    listbox.insert(tk.END, f"📁 {item}")
                else:
                    listbox.insert(tk.END, f"📄 {item}")
        except Exception as e:
            listbox.insert(tk.END, f"Error: {str(e)}")
        
        listbox.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # Double-click to open file
        def on_double_click(event):
            selection = listbox.curselection()
            if selection:
                item_name = listbox.get(selection[0])[2:]  # Remove icon
                item_path = os.path.join(folder_path, item_name)
                if os.path.isfile(item_path):
                    folder_window.destroy()
                    self.open_specific_file(item_path)
        
        listbox.bind('<Double-1>', on_double_click)
    
    def open_specific_file(self, file_path):
        if not self.check_unsaved_changes():
            return
        
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()
                self.text_widget.delete(1.0, tk.END)
                self.text_widget.insert(1.0, content)
                self.current_file = file_path
                self.update_file_info()
                self.text_widget.edit_modified(False)
                self.status_var.set(f"Opened file: {os.path.basename(file_path)}")
        except Exception as e:
            messagebox.showerror("Error", f"Could not open file:\n{str(e)}")
    
    def check_unsaved_changes(self):
        if self.text_widget.edit_modified():
            result = messagebox.askyesnocancel(
                "Unsaved Changes",
                "File has unsaved changes. Save them?"
            )
            if result is True:  # Yes
                self.save_file()
                return True
            elif result is False:  # No
                return True
            else:  # Cancel
                return False
        return True
    
    def update_file_info(self):
        if self.current_file:
            file_path = Path(self.current_file)
            file_info = f"File: {file_path.name} ({file_path.parent})"
            try:
                stat = file_path.stat()
                size = stat.st_size
                mtime = stat.st_mtime
                from datetime import datetime
                mtime_str = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
                file_info += f" | Size: {size} bytes | Modified: {mtime_str}"
            except:
                pass
        else:
            file_info = "File: New Document"
        
        self.file_info_label.config(text=file_info)
    
    def on_text_modified(self, event):
        if self.text_widget.edit_modified():
            title = self.root.title()
            if not title.endswith(" *"):
                self.root.title(title + " *")
        else:
            title = self.root.title()
            if title.endswith(" *"):
                self.root.title(title[:-2])
    
    def select_all(self):
        self.text_widget.tag_add(tk.SEL, "1.0", tk.END)
        self.text_widget.mark_set(tk.INSERT, "1.0")
        self.text_widget.see(tk.INSERT)
        return "break"

if __name__ == "__main__":
    root = tk.Tk()
    app = FileOperationsApp(root)
    root.mainloop()

Setup and Environment

# Tkinter is included in Python standard library - no additional installation needed

# Check Python environment
python -c "import tkinter; print('Tkinter available')"

# Check available themes (ttk.Style)
python -c "import tkinter as tk; from tkinter import ttk; root=tk.Tk(); print(ttk.Style().theme_names()); root.destroy()"

# Install Pillow if image processing is needed
pip install Pillow

# Run application
python hello_world.py

# Create standalone executable
pip install pyinstaller
pyinstaller --onefile --windowed hello_world.py

# Linux environment tkinter check
# Ubuntu/Debian
sudo apt-get install python3-tk

# CentOS/RHEL
sudo yum install tkinter
# or
sudo dnf install python3-tkinter

Example Project Structure

my_tkinter_app/
├── main.py                 # Main application
├── widgets/
│   ├── __init__.py
│   ├── custom_widgets.py   # Custom widgets
│   └── dialogs.py          # Custom dialogs
├── utils/
│   ├── __init__.py
│   ├── file_handler.py     # File operations
│   └── config.py           # Configuration management
├── resources/
│   ├── icons/              # Icon files
│   └── images/             # Image files
├── tests/
│   ├── __init__.py
│   └── test_widgets.py     # Test files
├── requirements.txt
└── README.md