You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter使用多进程/多线程时程序冻结问题求助

问题根因

你的代码存在4个核心错误,直接导致了进程阻塞、执行顺序异常:

  • 多进程启动逻辑未做平台兼容:Windows系统下multiprocessing模块的进程启动代码必须放在if __name__ == "__main__":判断块内,否则模块导入时会重复执行代码,导致逻辑混乱
  • multiprocessing.Process传参逻辑完全错误:你定义p2的时候直接执行了os.system(f"{filedialog.askopenfilename(title = 'Choose the execution File')}")这行代码,相当于先同步执行完弹框选文件、运行选中程序直到退出的全流程,才会把os.system返回的整数状态码当成target传给Process,根本没有实现把这部分逻辑放到子进程运行的效果
  • Tkinter组件跨进程调用违规:Tkinter所有GUI相关操作只能在创建Tk实例的线程/进程中执行,跨进程调用文件选择框会出现未定义行为
  • 技术选型冗余:调用独立外部程序不需要额外开进程/线程,直接用subprocess.Popen就可以实现非阻塞启动,完全不会卡住GUI主线程
修复方案

推荐你完全放弃用多进程启动外部程序的逻辑,把文件选择、启动外部程序的逻辑放到GUI的回调函数里,用非阻塞接口启动即可,修复后的参考代码如下:

import os
import subprocess
import tkinter.messagebox as msgbox
import io, hashlib, queue, sys, time, threading, traceback
from tkinter import *
import tkinter as tk
from tkinter import filedialog

class Layout(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)
        self.canvas = tk.Canvas(self, width=200, height=750, background="white")
        self.xsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        self.ysb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set)
        self.canvas.configure(scrollregion=(0,0,1000,1000))

        self.xsb.grid(row=1, column=0, sticky="ew")
        self.ysb.grid(row=0, column=1, sticky="ns")
        self.canvas.grid(row=0, column=0, sticky="nsew")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.canvas.fontSize = 12

        # 鼠标拖动支持
        self.canvas.bind("<ButtonPress-1>", self.move_start)
        self.canvas.bind("<B1-Motion>", self.move_move)
        # Linux缩放支持
        self.canvas.bind("<Button-4>", self.zoomerP)
        self.canvas.bind("<Button-5>", self.zoomerM)
        # Windows缩放支持
        self.canvas.bind("<MouseWheel>",self.zoomer)

    # 拖动方法
    def move_start(self, event):
        self.canvas.scan_mark(event.x, event.y)
    def move_move(self, event):
        self.canvas.scan_dragto(event.x, event.y, gain=1)

    # Windows缩放方法
    def zoomer(self, event):
        if (event.delta > 0):
            self.canvas.scale("all", event.x, event.y, 1.1, 1.1)
            self.canvas.fontSize = self.canvas.fontSize * 1.1
        elif (event.delta < 0):
            self.canvas.scale("all", event.x, event.y, 0.9, 0.9)
            self.canvas.fontSize = self.canvas.fontSize * 0.9
        for child_widget in self.canvas.find_withtag("text"):
            self.canvas.itemconfigure(child_widget, font = ("Helvetica", int(self.canvas.fontSize)))
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))

    # Linux放大方法
    def zoomerP(self, event):
        self.canvas.scale("all", event.x, event.y, 1.1, 1.1)
        self.canvas.fontSize = self.canvas.fontSize * 1.1
        for child_widget in self.canvas.find_withtag("text"):
            self.canvas.itemconfigure(child_widget, font = ("Helvetica", int(self.canvas.fontSize)))
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))
    # Linux缩小方法
    def zoomerM(self,event):
        self.canvas.scale("all", event.x, event.y, 0.9, 0.9)
        self.canvas.fontSize = self.canvas.fontSize * 0.9
        for child_widget in self.canvas.find_withtag("text"):
            self.canvas.itemconfigure(child_widget, font = ("Helvetica", int(self.canvas.fontSize)))
        self.canvas.configure(scrollregion = self.canvas.bbox("all"))

def run_external_program():
    # 弹出文件选择框
    exe_path = filedialog.askopenfilename(title = 'Choose the execution File')
    if not exe_path:
        return
    # 非阻塞启动外部程序,完全不卡GUI
    subprocess.Popen(exe_path, shell=True)

def main_window():
    root = Tk()
    root.title("Seoul Cell")
    root.geometry("1300x1000")
    root.resizable(True, True)

    monitor1 = Layout(root)
    monitor1.pack(fill="both", expand=True)

    # 메뉴바 생성
    menu = Menu(root)
    root.config(menu=menu)

    menu_file = Menu(menu, tearoff=0)
    menu_file.add_command(label="Open Cell Information")
    menu_file.add_command(label="Partitioning")
    menu_file.add_command(label="Pairing")
    menu_file.add_command(label="Placement")
    menu_file.add_command(label="Routing")
    # 新增启动外部程序的菜单选项
    menu_file.add_command(label="Run External Program", command=run_external_program)
    menu.add_cascade(label="Task", menu = menu_file )

    menu_work = Menu(menu, tearoff= 0)
    menu_work.add_command(label="Open layerinfo file")
    menu_work.add_command(label="save as layerinfo.txt")
    menu.add_cascade(label="TechInfo", menu = menu_work)

    # 第二菜单栏
    menu2_frame = Frame(root)
    menu2_frame.pack(fill = "x")
    layer_but = Button(menu2_frame, text = "Layers")
    layer_but.pack(side = "left", padx=3, pady=3)

    # 脚本区域
    script_frame = LabelFrame(root, text = "script")
    script_frame.pack(fill='x', side="bottom",padx=10, pady=10)

    script_menu_frame = Frame(script_frame)
    script_menu_frame.pack(fill='x')

    # 脚本文本框
    scrollbar_script = Scrollbar(script_frame)
    scrollbar_script.pack(side='right',fill="y")

    script = Text(script_frame, height=20, yscrollcommand=scrollbar_script.set)
    script.pack(fill='x', side="bottom", padx=10, pady=10)
    scrollbar_script.config(command=script.yview)

    root.mainloop()

if __name__ == "__main__":
    main_window()

修复后你可以点击Task菜单下的Run External Program选项唤起文件选择框,选中程序后会直接非阻塞启动,GUI全程不会卡顿。

内容的提问来源于stack exchange,提问作者onixcurve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:39:00