Search code examples
pythonkivykivy-languagekivymd

Python TypeError: takes 4 positional arguments but 5 were given


I'm trying to design a user interface in Python / Kivy MD. Starting from an example, I developed an interface with a simple drop down widget, such as a combobox. When the app runs, the widget should display its elements. Here is the code:

from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import StringProperty
from kivymd.uix.list import OneLineIconListItem
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu

KV = '''
#:import toast kivymd.toast.toast

MDScreen

    MDDropDownItem:
        id: drop_item
        pos_hint: {'center_x': .5, 'center_y': .5}
        text: 'FREQUENCY'
        on_release: app.menu.open()
        select: toast(self.current_item)
'''


class MainApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.screen = Builder.load_string(KV)
        
        myItems = ['300 Hz', '200 Hz', '100 Hz']
        
        
        menu_items = self.create_combobox_items(self.screen.ids.drop_item, myItems)
        
        # WAY 1: WORKS --- COMMENT THIS BLOCK
        ########################################
        self.menu = MDDropdownMenu(
            caller = self.screen.ids.drop_item,
            items = menu_items,
            position = "bottom", #top, bottom, center, auto
            width_mult = 2,
        )
        ########################################
        
        # WAY 2: DOESN'T WORK --- UNCOMMENT ONLY THE FOLLOWING LINE
        ########################################
        self.menu = self.create_dropdown_object(self.screen.ids.drop_item, menu_items, 'auto', 2)
        ########################################
        self.menu.bind()        

        
    def create_dropdown_object(dropDownItem, menuItems, pos, width):
        ddMenu = MDDropdownMenu(
            caller = dropDownItem,
            items = menuItems,
            position = pos, #top, bottom, center, auto
            width_mult = width,
        )
        return ddMenu        
    
        
    def create_combobox_items(self, dropDownItem, itemList):
        comboBoxItems = [
            {
                "viewclass": "OneLineListItem",
                "text": itemList[i],
                "height": dp(56),
                "on_release": lambda x = itemList[i]: self.set_item(dropDownItem, self.menu, x),
            } for i in range(len(itemList))
        ]
        return comboBoxItems

    
    def set_item(self, dropDownItem, dropDownMenu, textItem):
        dropDownItem.set_item(textItem)
        dropDownMenu.dismiss()  


    def build(self):
        return self.screen


if __name__ == '__main__':
    MainApp().run()

This code (WAY 1) works fine. I'm trying to develop a method for the MDDropDownItem widget creation, namely create_dropdown_object. When I comment the way 1 code block, and use the method defined below (WAY 2), I get the TypeError: create_dropdown_object() takes 4 positional arguments but 5 were given. How it can be possible considering that I passed 4 arguments to the function?


Solution

  • Inside the class function self keyword need to be in parameter.

    You Forgot to mention self inside the class function. Add self will fix the issue

    def create_dropdown_object(self, dropDownItem, menuItems, pos, width):
        ddMenu = MDDropdownMenu(
            caller = dropDownItem,
            items = menuItems,
            position = pos, #top, bottom, center, auto
            width_mult = width,
        )
        return ddMenu
    

    Above change will fix your issue