我是编程,Python,这个网站的新手,并且实际上通常使用这些类型的网站,所以请听我说。
我一直在使用tkinter模块和ttk模块为一个更大的程序编写一个模块,当我将自己的模块导入主程序时,由于某种原因,没有任何ttk的东西可以正常工作。我的意思是,它似乎,但我为它写的风格(s = ttk.Style(); s.configure ...等)无论如何都不会改变它。当我自己运行模块时,一切正常。当它被导入主程序时,它就没有。
不仅仅是这样,但是当使用输入框时,我只是发现了我被告知使用它们的方式,例如,var = StringVar()作为textvariable(当它变得很好时)模块是自己运行的),现在只需在调用var.get()时将变量var保留为空。现在我已经通过删除所有提到的StringVar()来对它进行排序(希望我知道它们实际上是多么冗余),但是我仍然想知道为什么将它们导入主程序导致它们如此严重故障。我会给你一些示例代码,但是我很难选择足够的选择......
我很感激您提供的任何指导。
编辑:给你这样的东西有帮助吗?stackoverflowmodule.py
import sys
from tkinter import *
from tkinter import ttk
import time
from random import randint, choice
class Decimals():
def Question1(self):
DECFrame.destroy()
frame1=ttk.Frame(DECmaster, height=height, width=width, style="NewFrame.TFrame")
frame1.pack()
Q1Label=ttk.Label(frame1, text="Question 1:", style="TitleLabel.TLabel")
Q1Label.grid(column=0, row=0, pady=(50,0))
answer=StringVar()
entry1=ttk.Entry(frame1, textvariable=answer)
entry1.grid(column=0, row=1, pady=(200,0))
# Typing in Hello should give a correct answer.
def Question1Attempt():
attempt=answer.get()
if attempt!="Hello":
print("Incorrect")
else:
print("Correct")
button=ttk.Button(frame1, text="Ok", command=Question1Attempt)
button.grid(column=0, row=2, pady=(30,0))
def Start():
global DECmaster
global s
global DECFrame
global DEC
global width
global height
DECmaster = Tk()
width=str(1000)
height=str(800)
x1=str(0)
y1=str(0)
DECmaster.geometry(width+"x"+height+"+"+x1+"+"+y1)
DECmaster.configure(bg="#8afff0")
s=ttk.Style()
s.configure("NewFrame.TFrame", background="#8afff0")
s.configure("TitleLabel.TLabel", foreground= "blue", background="#8afff0")
DECFrame=ttk.Frame(DECmaster, style="NewFrame.TFrame")
DECFrame.pack()
TitleLabel=ttk.Label(DECFrame, text="Test for Decimals", style="TitleLabel.TLabel")
TitleLabel.grid(column=1, row=0, pady=(50,0), sticky=N)
DEC=Decimals()
button=ttk.Button(DECFrame, text="Start", command=DEC.Question1)
button.grid(column=2, row=2, pady=(200,0), sticky=N)
DECmaster.mainloop()
stackoverflowprogram.py
from tkinter import *
from tkinter import ttk
import time
import stackoverflowmodule
root = Tk()
width=str(1000)
height=str(800)
x1=str(0)
y1=str(0)
##width=str(1228)
##height=str(690)
##x1=str(-1)
##y1=str(-22)
root.geometry(width+"x"+height+"+"+x1+"+"+y1)
root.configure(bg="#8afff0")
s=ttk.Style()
s.configure("NewFrame.TFrame", background="#8afff0")
s.configure("TitleLabel.TLabel", foreground= "blue", background="#8afff0")
Testframe=ttk.Frame(root, height=height, width=width, style="NewFrame.TFrame")
Testframe.pack()
Titlelabel=ttk.Label(Testframe, text="Start Test:", style="TitleLabel.TLabel")
Titlelabel.grid(column=0, row=0, pady=(50,0))
def StartTest():
stackoverflowmodule.Start()
button=ttk.Button(Testframe, text="Start", command=StartTest)
button.grid(column=0, row=1, pady=(100,0))
root.mainloop()
我意识到那里有很多,但如果没有这一切,我无法真正证明自己的观点。再次感谢。
答案 0 :(得分:1)
您无法创建tkinter.Tk
的两个实例。如果你这样做,将会发生以下两件事之一。
脚本中的大多数代码可能都没有运行,因为它正在等待模块的mainloop
完成,这在你退出之前不会发生。
如果以不同的方式构造事物,最终会有两个Tk
个实例,其中只有一个实际运行。你的脚本中的一些代码会碰巧找到正确的Tk
实例(或者正确的实际Tk对象),因为有很多共享的全局内容只假设有一个Tk“某处或其他”并设法找到。但是其他代码会找到错误的代码,并且没有任何效果。或者,偶尔会出现错误的效果,或导致崩溃,或者谁知道什么。
您需要将顶级应用程序放在一个位置,模块或使用它的脚本,并让另一个位置从那里访问它。
执行此操作的一种方法是以这样的方式编写模块,即可以使用Tk
实例调用其代码。然后,使用__main__
技巧,这样,如果您直接将模块作为脚本运行(而不是从另一个脚本中导入),它会创建一个Tk
实例并调用该代码。这是一个非常简单的例子。
tkmodule.py:
from tkinter import *
def say_hi():
print("Hello, world!")
def create_interface(window):
hi = Button(window, text='Hello', command=say_hi)
hi.pack()
if __name__ == '__main__':
root = Tk()
create_interface(root)
root.mainloop()
tkscript.py:
from tkinter import *
import tkmodule
i = 0
def count():
global i
i += 1
print(i)
def create_interface(window):
countbtn = Button(window, text='Count', command=count)
countbtn.pack()
root = Tk()
create_interface(root)
window = Toplevel(root)
tkmodule.create_interface(window)
root.mainloop()
现在,当您运行tkscript.py
时,它拥有一个Tk
个实例,并将其传递给自己的create_frame
和tkmodule.create_frame
。但是,如果你只是运行tkmodule.py
,它拥有一个Tk
实例,它会传递给它自己的create_frame
。无论哪种方式,只有一个Tk
实例和一个主循环,每个人都可以使用它。
请注意,如果您需要两个顶级窗口,则必须在某处明确创建Toplevel
。 (并且您不希望总是在tkmodule.py
中创建一个,或者当您运行模块本身时,它将创建一个新窗口并保持默认窗口为空。)
当然,更简单的方法是将所有GUI内容放入从不创建自己的Tk
实例的模块中,并编写导入相应模块的脚本开车送他们。
答案 1 :(得分:1)
问题的根源在于您创建的Tk
实例不止一次。 Tkinter应用程序只能包含Tk
类的单个实例,您必须只调用mainloop
一次。如果您需要其他窗口,则应创建Toplevel
(http://effbot.org/tkinterbook/toplevel.htm)的实例。
如果要创建具有可重用代码的模块,请让模块创建Frame
的子类(如果您正在创建拨号,则创建Toplevel
)。然后,您的主脚本将创建Tk
的实例,并将这些帧放在主窗口或子窗口中。
如果您希望有时将模块用作可重用的组件,有时将其用作可运行的程序,请将“runnable program”部分放在特殊的if语句中:
# module1.py
import Tkinter as tk
class Module1(tk.Frame):
def __init__(self, *args, **kwargs):
label = tk.Label(self, text="I am module 1")
label.pack(side="top", fill="both", expand=True)
# this code will not run if this module is imported
if __name__ == "__main__":
root = tk.Tk()
m1 = Module1(root)
m1.pack(side="top", fill="both", expand=True)
在上面的代码中,如果你像python module1.py
那样运行它,那么最后的if语句中的代码将会运行。它将创建一个根窗口,创建一个框架实例,并使该框架填充主窗口。
但是,如果将上述代码导入另一个程序,则if语句中的代码将不运行,因此您不会获得多个Tk
实例。
假设您有两个类似上面的模块,并且想要编写一个使用它们的程序,并且每个模块应该放在一个单独的窗口中。您可以通过编写使用它们的第三个脚本来完成此操作:
# main.py
import Tkinter as tk
from module1 import Module1
from module2 import Module2
# create the main window; every Tkinter app needs
# exactly one instance of this class
root = tk.Tk()
m1 = Module1(root)
m1.pack(side="top", fill="both", expand=True)
# create a second window
second = tk.Toplevel(root)
m2 = Module2(second)
m2.pack(side="top", fill="both", expand=True)
# run the event loop
root.mainloop()
通过上述内容,您可以在两个模块中使用代码,这些模块可以通过三种方式使用:作为独立程序,作为单个窗口中的单独帧,或作为单独窗口中的单独帧。