我正在尝试将我的过程编程Python项目转换为面向对象的编程。在我的项目中,我使用Tkinter。
程序版本运行得很好,但在OOP中,我得到了
第2493行,在grid_configure self.tk.call中( _tkinter.TclError:无法调用"grid“命令:应用程序已被销毁)
当我试图网格第一个标签时出错。
我的代码:
from tkinter import *
class Document:
root = Tk()
root.geometry("1000x500")
file_name = Label(text="File Name")
document_title = Label(text="Document Title")
def gridding(self):
self.file_name.grid(row=1,column=2)
self.document_title.grid(row=2,column=2)
root.mainloop()
doc1 = Document()
doc1.gridding()错误信息根本没有帮助,所以希望这篇文章也能帮助到其他人。
非常感谢你事先的帮助。
发布于 2021-03-15 15:14:52
关于您的代码,有很多事情要考虑,我将解决所有这些问题。
tkinter,而没有任何别名root为"doc1“,这意味着您认为您将生成"doc2”、"doc3“等等。在那门课之外,这是行不通的。您不可能有很多root实例。充其量,这应该是Toplevel,但前提是您打算为每个新文档打开一个新窗口。mainloop。您应该使用模块约定。这样,您就可以将这个脚本的元素导入到另一个脚本中,而不必担心这个脚本会自动运行。至少,为mainloop创建一个包装器是愚蠢的。您已经可以调用mainloop了,将其粘贴到另一个方法中的目的是什么?(doc1.root.mainloop())mixin将是一种更好的方法。没有必要为小部件创建一个自定义包装器,但是如果您要在所有部件上添加一个gridding方法,那么为什么不创建一个更好的gridding方法,并让它自动“混合”到所有应用程序中呢?只要你走到这一步,你最好还包括一些其他的便利,就像well.Document (也就是你可能需要很多东西或经常改变的东西)可能不应该是root。应该在root里。当然,它不应该把root作为一种财产埋在里面。下面给出了我上面提到的许多例子。这些例子可以而且应该加以修饰。例如,BaseWidget可以包括x、rootx、y、rooty等的属性.按照ParentWidget的设计方式,您可以使用range作为rowcfg和colcfg的第一个参数,在一个调用中进行“大规模配置”。它们都返回self,因此它们可以内联使用。
import tkinter as tk
from typing import Iterable
class BaseWidget:
@property
def width(self) -> int:
self.update_idletasks()
return self.winfo_width()
@property
def height(self) -> int:
self.update_idletasks()
return self.winfo_height()
def grid_(self, r=None, c=None, rs=1, cs=1, s='nswe', **kwargs):
#this allows keyword shorthand, as well as original keywords
#while also allowing you to rearrange the above arguments
#so you know the exact order they appear and don't have to use the keyword, at all
self.grid(**{'row':r, 'column':c, 'rowspan':rs, 'columnspan':cs, 'sticky':s, **kwargs})
#return self so this can be used inline
return self
class ParentWidget:
@property
def descendants(self):
return self.winfo_children()
#inline and ranged grid_rowconfigure
def rowcfg(self, index, **options):
index = index if isinstance(index, Iterable) else [index]
for i in index:
self.grid_rowconfigure(i, **options)
#so this can be used inline
return self
#inline and ranged grid_columnconfigure
def colcfg(self, index, **options):
index = index if isinstance(index, Iterable) else [index]
for i in index:
self.grid_columnconfigure(i, **options)
#so this can be used inline
return self
class Custom_Label(tk.Label, BaseWidget):
@property
def text(self) -> str:
return self['text']
@text.setter
def text(self, value:str):
self['text'] = value
def __init__(self, master, **kwargs):
tk.Label.__init__(self, master, **kwargs)
class Document(tk.Frame, ParentWidget, BaseWidget):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
#the rest of this class is an example based on what little code you posted
#the results are not meant to be ideal. It's a demo of usage ... a gist
self.file_name = Custom_Label(self, text='File Name').grid_(1,2)
self.doc_title = Custom_Label(self, text='Document Title').grid_(2,2)
#possible
#r = range(len(self.descendants))
#self.colcfg(r, weight=1).rowcfg(r, weight=1)
self.colcfg(2, weight=1).rowcfg([1,2], weight=1)
class Root(tk.Tk, ParentWidget):
def __init__(self, title, width, height, x, y, **kwargs):
tk.Tk.__init__(self)
self.configure(**kwargs)
self.title(title)
self.geometry(f'{width}x{height}+{x}+{y}')
self.rowcfg(0, weight=1).colcfg(0, weight=1)
doc1 = Document(self).grid_()
if __name__ == '__main__':
Root('MyApplication', 800, 600, 200, 200, bg='#000000').mainloop()发布于 2021-03-15 13:10:32
就快到了:您应该在__init__方法中构建类,并且只在设置结束时调用mainloop:
from tkinter import Tk
from tkinter import Label
class Document:
def __init__(self):
self.root = Tk()
self.root.geometry("1000x500")
self.file_name = Label(text="File Name")
self.document_title = Label(text="Document Title")
self.gridding()
def gridding(self):
self.file_name.grid(row=1, column=2)
self.document_title.grid(row=2, column=2)
def start(self):
self.root.mainloop()
doc1 = Document()
doc1.start()这将像预期的那样创建一个带有两个标签的窗口。
干杯!
https://stackoverflow.com/questions/66638550
复制相似问题