【问题标题】:python 3.5 tkinter.listbox change sizepython 3.5 tkinter.listbox 改变大小
【发布时间】:2016-08-22 07:07:06
【问题描述】:

谁能告诉我以下代码有什么问题?我尝试构建一个可以使用 .config 命令更改尺寸的 tkinker.listbox,但失败了。相反,它会产生“AttributeError:'MovListbox'对象没有属性'tk'”的错误代码附在下面供您参考。

非常感谢。

import tkinter

def test():
    root = tkinter.Tk()

    list = ['  1','2','  3','4','5','  6','7','8','  9','10']
    a = MovListbox(root, list)
    a._setup_style(200, 200, EXTENDED)

class MovListbox(tkinter.Listbox):    

    def __init__(self, master=None, inputlist=None):
#        super(MovListbox, self).__init__()

        global NewsClassify_catList
        NewsClassify_catList = tkinter.Listbox(master)
        NewsClassify_catList.grid(row = 0 , column = 0, columnspan=2, sticky=N)    

        '''populate the news category onto the listbox'''
        for i in range (0, inputlist.__len__()):
            NewsClassify_catList.insert(END, inputlist[i])

        master.mainloop()

    def _setup_style(self, height=100, width=100, mode=EXTENDED):
        self.config(height=height, width=width, selectmode=mode)

if __name__ == '__main__':
    test()     

【问题讨论】:

  • 我对 Tkinter 不是很熟悉,但我认为您不应该使用 _setup_style 方法。以下划线开头的属性通常不被视为公共 api 的一部分。另外,您是否意识到直到窗口关闭才到达a._setup_style,因为您在MovListBox 构造函数中执行master.mainloop()
  • 感谢 Rawing 的 cmets。将主循环放在外面的一个很好的提醒。我已经这样做了,并且还删除了 _setup_style 之前的下划线(即到 setup_style)。但是属性错误消息仍然显示。我想知道问题是否与如何告诉计算机定位要配置的列表框有关,即 self.config(height=height, width=width, selectmode=mode)) 有人有想法吗?
  • 糟糕,我刚刚意识到 _setup_style 是你自己的函数,而不是 Tkinter 函数。
  • 我不太确定您要做什么。为什么要在您的 MovListbox 中创建另一个列表框(NewsClassify_catList)?为什么不将 MovListbox 放入根窗口?
  • @ PM 2Ring:感谢 cmets。它只是在这里提问的简化版本。实际上,列表框是更大程序的一部分。为简单起见,我将 Listbox 小部件放在另一个类中,以便在主语法中调用。由于我是 Python 的新手,所以我也在尝试编写类结构。如果有任何更简单的方法可以在类结构中编写它并解决配置问题。请告诉我。

标签: python python-3.x tkinter listbox


【解决方案1】:

我对您的代码做了一些修改;它可能不是您想要的,但您应该会发现它很有帮助。

列表框的宽度和高度选项不是像素测量值;他们根据字符指定尺寸,因此height=12 使列表框的文本行高为 12 行,width=40 使列表框的宽度为 40 个字符。

import tkinter as tk

def test():
    root = tk.Tk()
    lst = ['  1', '2', '  3', '4', '5', '  6', '7', '8', '  9', '10']
    a = MovListbox(root, lst)
    a.grid(row=0, column=0, columnspan=2, sticky=tk.N)
    a.setup_style(12, 40, tk.EXTENDED)
    root.mainloop()

class MovListbox(tk.Listbox):
    def __init__(self, master=None, inputlist=None):
        super(MovListbox, self).__init__(master=master)

        # Populate the news category onto the listbox
        for item in inputlist:
            self.insert(tk.END, item)

    def setup_style(self, height=10, width=20, mode=tk.EXTENDED):
        self.config(height=height, width=width, selectmode=mode)

if __name__ == '__main__':
    test()

如果您愿意,您可以删除 test() 中的 a.setup_style(12, 40, tk.EXTENDED) 调用,改为这样做

self.setup_style(12, 40, tk.EXTENDED)

MovListbox.__init__() 方法的末尾。

我已将您的 list 变量更改为 lstlist 不是变量名的好选择,因为它会遮蔽内置的 list 类型,这可能会造成混淆,并且还会导致神秘的错误。


super 内置函数用于访问父类的方法。来自the docs

super([type[, object-or-type]])

返回一个代理对象,它将方法调用委托给父对象或 类型的兄弟类。这对于访问继承的方法很有用 已在类中被覆盖。搜索顺序与此相同 由 getattr() 使用,除了类型本身被跳过。

这样

super(MovListbox, self).__init__(master=master)

表示调用MovListbox类的父类的__init__方法,也就是tk.Listbox.__init__方法。我们需要这样做,因为 MovListbox 是从 tk.Listbox 派生的,我们需要为我们的 MovListbox 实例设置所有常用的 Listbox 内容,然后再开始使用它进行额外的操作,例如插入来自inputlist 的字符串。

如果派生类没有定义自己的__init__ 方法,则在创建派生类的实例时会自动调用父类的__init__ 方法。但是因为我们已经为 MovListbox 定义了一个 __init__ 方法,所以新的 __init__ 会被调用。因此,要为MovListbox 执行通常的Listbox 初始化,我们需要手动调用Listbox 的__init__,而优雅地执行此操作的习惯方法是使用super

实际上,在 Python 3 中,super 调用可以简化:

super().__init__(master)

我之前使用的形式在 Python 2 中是必需的。但是,super 仅适用于新式类(Python 3 支持的唯一一种类),但不幸的是 Python 2 Tkinter 使用了古老的旧式类对于它的小部件,并且在此类类上调用 super 会引发 TypeError 异常。 :( 使用旧式类时,我们必须通过显式指定父类来进行调用,如下所示:

tk.Listbox.__init__(self, master)

该语法在 Python 3 中也有效,但通常首选使用 super(如果可用)。

【讨论】:

  • 非常感谢。这正是我正在寻找的。好像你通过添加“super(MovListbox,self).__init__(master = master)”解决了这个问题,我不知道它是什么。你能更详细地解释一下吗?
  • @CL.L:我添加了一些关于super 的更多细节。如果我的回答对您有所帮助,请考虑accepting
  • 酷,非常详细的解释。我现在明白了,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多