首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python - Tkinter和OOP

Python - Tkinter和OOP
EN

Stack Overflow用户
提问于 2021-03-15 13:04:00
回答 2查看 632关注 0票数 0

我正在尝试将我的过程编程Python项目转换为面向对象的编程。在我的项目中,我使用Tkinter。

程序版本运行得很好,但在OOP中,我得到了

第2493行,在grid_configure self.tk.call中( _tkinter.TclError:无法调用"grid“命令:应用程序已被销毁)

当我试图网格第一个标签时出错。

我的代码:

代码语言:javascript
复制
    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()

错误信息根本没有帮助,所以希望这篇文章也能帮助到其他人。

非常感谢你事先的帮助。

EN

回答 2

Stack Overflow用户

发布于 2021-03-15 15:14:52

关于您的代码,有很多事情要考虑,我将解决所有这些问题。

  1. --您正在导入所有的tkinter,而没有任何别名
  2. ,称您的root为"doc1“,这意味着您认为您将生成"doc2”、"doc3“等等。在那门课之外,这是行不通的。您不可能有很多root实例。充其量,这应该是Toplevel,但前提是您打算为每个新文档打开一个新窗口。
  3. 您根本不应该在类内调用mainloop。您应该使用模块约定。这样,您就可以将这个脚本的元素导入到另一个脚本中,而不必担心这个脚本会自动运行。至少,为mainloop创建一个包装器是愚蠢的。您已经可以调用mainloop了,将其粘贴到另一个方法中的目的是什么?(doc1.root.mainloop())
  4. Creating --一种非常特定的网格布局方法是不可重用的。我认为,使某些特性更加可用但保持动态的mixin将是一种更好的方法。没有必要为小部件创建一个自定义包装器,但是如果您要在所有部件上添加一个gridding方法,那么为什么不创建一个更好的gridding方法,并让它自动“混合”到所有应用程序中呢?只要你走到这一步,你最好还包括一些其他的便利,就像well.
  5. Something一样,Document (也就是你可能需要很多东西或经常改变的东西)可能不应该是root。应该在root里。当然,它不应该把root作为一种财产埋在里面。

下面给出了我上面提到的许多例子。这些例子可以而且应该加以修饰。例如,BaseWidget可以包括xrootxyrooty等的属性.按照ParentWidget的设计方式,您可以使用range作为rowcfgcolcfg的第一个参数,在一个调用中进行“大规模配置”。它们都返回self,因此它们可以内联使用。

代码语言:javascript
复制
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()
票数 2
EN

Stack Overflow用户

发布于 2021-03-15 13:10:32

就快到了:您应该在__init__方法中构建类,并且只在设置结束时调用mainloop

代码语言:javascript
复制
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()

这将像预期的那样创建一个带有两个标签的窗口。

干杯!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66638550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档