Tkinter通过exec调用外部Python程序时组件显示位置异常问题咨询
问题原因
- 核心原因是
Timer类实例化时没有传入你在prog2中创建的窗口对象作为父容器:你调用的是Timer(),而__init__方法的window参数默认值为None,此时tkinter会自动将当前程序的主窗口(也就是main.py的窗口)作为这些未指定父容器组件的父级,因此ButtonShow、progress、outText会显示在main窗口中。单独运行prog2时,程序只有prog2自己创建的这一个Tk窗口,所以就算未传入参数,默认父容器也是该窗口,因此所有组件显示正常。 - 额外不规范点:你通过exec运行prog2的代码时,两个脚本共享tkinter上下文,main.py已经存在一个主
Tk实例,prog2中再创建tk.Tk()属于错误用法,同一个tkinter应用不应该存在多个Tk实例,副窗口应该用Toplevel实现;同时你的代码存在导入规则混用的问题,from tkinter import *之后不应该再用tk.前缀调用组件,且缺失action_VNC变量定义,单独运行本应报错,是exec共享了main的上下文才没有触发报错。
修复方案
方案1:最小改动修复当前问题
仅修改prog2.py末尾的Timer实例化代码,传入你创建的window对象即可:
把Timer()改为Timer(window=window)
方案2:更规范的完整修复(推荐)
1. 重写main.py,放弃exec执行方式,改为导入函数调用
import tkinter as tk def open_prog2(): import prog2 prog2.create_window() # 明确指定main窗口的主实例 root = tk.Tk() buttonHMI = tk.Button(root, text="Program HMI", width=15, font=("Arial", 14), command=open_prog2) buttonHMI.grid(column=0, row=3, columnspan=1, padx=20, pady=10, sticky=tk.W) root.mainloop()
2. 重写prog2.py,封装为独立函数,副窗口用Toplevel实现
import tkinter as tk from tkinter import ttk def create_window(): # 副窗口使用Toplevel,不要新建Tk实例 window = tk.Toplevel() # 补充缺失的变量定义 action_VNC = tk.BooleanVar() CB1 = tk.Checkbutton(window, text="Enable VNC", font=("Arial", 12), variable=action_VNC) CB1.grid(row=0, sticky=tk.W, padx=10) CB1.configure(bg='#34aeeb') ButtonClose= tk.Button(window, text="Close", width=20, font=("Arial", 14), command=window.destroy) ButtonClose.grid(columnspan=2, column = 3, row=9, sticky=tk.W, padx=10, pady=10) class Timer: def __init__(self, window): self.sv = tk.StringVar() # 所有组件明确指定父容器为传入的window ButtonShow = tk.Button(window, text="Program HMI", width=20, font=("Arial", 14), command=self.actions) ButtonShow.grid(columnspan=2, row=9, column = 0, sticky=tk.W, padx=10, pady=10) progress = ttk.Progressbar(window, orient = tk.HORIZONTAL, length = 500, mode = 'determinate') progress.grid(row=10, columnspan = 4, sticky=tk.W, padx=10, pady=10) outText = tk.Text(window, width=50, height=20, wrap=tk.WORD) outText.grid(row=11, columnspan=4, padx=10) def actions(self): print("action") # 实例化时明确传入窗口对象 Timer(window)
内容的提问来源于stack exchange,提问作者nearbyatom
相关产品推荐
相关产品推荐

