【问题标题】:Create a class for tkinter widgets to call default attributes为 tkinter 小部件创建一个类以调用默认属性
【发布时间】:2019-08-04 16:13:06
【问题描述】:

我正在尝试使用 Python3 中的 tkinter 创建一个 GUI,该 GUI 将有几个按钮,我不想每次都为所有按钮键入相同的属性,如下所示:

tkinter.Button(topFrame, font=("Ariel", 16), width=10, height=10,
               fg="#ffffff", bg="#000000", text="Cake")

例如,fgbg color 和 size 在每个按钮上都是相同的。每个按钮上唯一改变的是文本以及屏幕上的放置位置。

我对编程和 Python 还很陌生,我想在创建新按钮时尝试重用代码。我想我错过了一些我在阅读时没有得到的课程的理解。

我想为每个按钮和不同的框架传递不同的文本,以便将其放置在 GUI 上的不同位置并保持其他所有内容相同。

到目前为止我的代码:

import tkinter
import tkinter.messagebox

window = tkinter.Tk()

#create default values for buttons
#frame and buttonText are the values passed to the class when making a new
#button
class myButtons:
     def buttonLayout(self, frame, buttonText):
          self.newButton=tkinter.Button(frame, font=("Ariel", 16),
                                        width=10, height=10, fg=#ffffff,
                                        bg=#000000, text=buttonText)

topFrame = tkinter.Frame(window)
topFrame.pack()

#create new button here and place in the frame called topFrame with the text
#"Cake" on it
buttonCake = myButtons.buttonLayout(topFrame, "Cake")
#position the new button in a certain cell using grid in topFrame
buttonCake.grid(row=1, column=0)

window.mainloop()

我尝试运行它时遇到的错误是:

TypeError: buttonLayout() missing 1 required positional argument: 'buttonText'

我很困惑,因为我传入了"Cake",错误提示它丢失了。

感谢您指出 init 我不知道如何使用 init 来解决我的问题,但这和这里给出的答案有所帮助。谢谢。

【问题讨论】:

  • 确切的错误意味着“self”参数没有被传递给buttonLayout函数——当你从一个对象调用一个实例方法时会隐式发生。 buttonLayout 应该是实例方法还是静态方法?它被定义为实例方法,但被称为静态方法。您应该创建一个myButton 类的实例并从该实例调用buttonLayout 函数。

标签: python class user-interface tkinter widget


【解决方案1】:

由于self参数,您会收到错误消息。 还有一个问题是您的代码没有创建MyButtons 类的实例。

这是一个继承自 Button 并自定义 __init__ 以设置一些默认值的示例。

import tkinter
import tkinter.messagebox

window = tkinter.Tk()    

#create default values for buttons
#frame and buttonText are the values passed to the class when making a new button

class MyButton(tkinter.Button):
    def __init__(self, *args, **kwargs):
        if not kwargs:
            kwargs = dict()
        kwargs['font'] = ("Arial", 16)
        kwargs['width'] = 10,
        kwargs['height'] = 10,
        kwargs['fg'] = '#ffffff',
        kwargs['bg'] = '#000000',
        super().__init__(*args, **kwargs)

topFrame = tkinter.Frame(window)
topFrame.pack()

#create new button here and place in the frame called topFrame with the text "Cake" on it
buttonCake = MyButton(topFrame, text="Cake")
#position the new button in a certain cell using grid in topFrame
buttonCake.grid(row=1, column=0)

window.mainloop()

这会将您的默认值强制输入按钮。您可以添加 if 语句来定义它们,前提是您没有通过如下方式在调用中传递它们:

if not 'width' in kwargs:
    kwargs['width'] = 10 

【讨论】:

    【解决方案2】:

    你没有定义你的类并正确使用它。
    这是一个版本,其中包含使其工作所需的更正:

    import tkinter
    
    
    class MyButton:
        """ Create Button with some default values. """
        def __init__(self, frame, buttonText):
            self.newButton = tkinter.Button(frame, font=("Ariel", 16),
                                            width=10, height=10, fg='#ffffff',
                                            bg='#000000', text=buttonText)
    
    window = tkinter.Tk()
    topFrame = tkinter.Frame(window)
    topFrame.pack()
    
    # Create new button here and place in the frame called topFrame with the text
    # "Cake" on it.
    buttonCake = MyButton(topFrame, "Cake")
    
    # Position the new button in a certain cell in topFrame using grid().
    buttonCake.newButton.grid(row=1, column=0)
    
    window.mainloop()
    

    更新

    更多的object-oriented 方法是派生自己的tkinter.Button subclass,由于继承,它的实例可以像基类的实例一样被使用——也就是说,不需要请记住在grid() 调用中引用其newButton 属性而不是按钮本身,这通常是必需的。

    下面显示的实现也非常灵活,您可以在创建一个默认值时轻松覆盖任何默认值,只需通过通常的关联关键字参数为其提供不同的值。

    import tkinter
    
    
    class MyButton(tkinter.Button):
        """ Create Button with some default values. """
    
        # Default Button options (unless overridden).
        defaults = dict(font=("Ariel", 16), width=10, height=10,
                        fg='#ffffff', bg='#000000')
    
        def __init__(self, *args, **kwargs):
            kwargs = dict(self.defaults, **kwargs)  # Allow defaults to be overridden.
            super().__init__(*args, **kwargs)
    
    
    window = tkinter.Tk()
    topFrame = tkinter.Frame(window)
    topFrame.pack()
    
    # Create new button here and place in the frame called topFrame with the text
    # "Cake" on it.
    buttonCake = MyButton(topFrame, text="Cake")
    
    # Position the new button in a certain cell in topFrame using grid().
    buttonCake.grid(row=1, column=0)
    
    window.mainloop()
    

    【讨论】:

      【解决方案3】:

      所以我对代码进行了注释,以便您学习一些东西

      from tkinter import * #in order not to have to writer "tkinter." each time
      
      class app: #we usually put the whole app in a class
      
          def __init__(self,window): # so here you "attach" things to your instance represented by self
              self.window=window
              self.topFrame = Frame(window)
              self.topFrame.pack()
              self.ButtonList=[]  #because you wouldn't want to make 100 button with the same name
      
          def buttonLayout(self, frame, buttonText): # here we create a method wich will be also "attached" to the instance
      
              self.ButtonList.append(Button(frame, font=("Ariel", 16),width=10, height=10, fg="#ffffff", bg="#000000", text=buttonText)) #adding a button to your list of buttons
              self.lastButton=self.ButtonList[(len(self.ButtonList)-1)] #storing the last button to call grid outside the class
      
      window=Tk()
      anInstance=app(window)
      anInstance.buttonLayout(anInstance.topFrame, "Cake")
      anInstance.lastButton.grid(row=1,column=0)
      window.mainloop()
      

      此外,如果您制作按钮,您通常会在 __init__ 中创建它们,但您的应用程序有一个不错的按钮构建器,您甚至可以用它制作一个框架构建器。

      【讨论】:

        【解决方案4】:

        我在我的项目中使用了一个名为 Tools 的通用类,其中包含这样的代码

        def get_button(self, container, text, row=None, col=None):
        
            w = ttk.Button(container, text=text, underline=0)
        
            if row is not None:
                w.grid(row=row, column=col, sticky=tk.W+tk.E, padx=5, pady=5)
            else:
                w.pack(fill =tk.X, padx=5, pady=5)
        

        调用

            self.tools = Tools()
        
            f = ttk.Frame()
            bts = [('Reset', self.on_reset),
                   ('New', self.on_add),
                   ('Edit', self.on_edit),
                   ('Close', self.on_cancel)]
        
            for btn in bts:
                self.tools.get_button(f, btn[0] ).bind("<Button-1>", btn[1])
        

        您可以轻松扩展此添加样式属性。

        【讨论】:

          猜你喜欢
          • 2015-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-11
          相关资源
          最近更新 更多