Kivy开发电梯GUI时bind()函数参数异常的解决方法求助
Hey there! Let's break down why that TypeError is popping up and get your elevator request system working smoothly.
The Root Cause of the Error
When you wrote:
self.floor1.up_button.bind(on_press=self.up_pressed(1))
You’re immediately calling the up_pressed(1) function instead of passing the function itself to bind(). This returns None (since your function has no return statement), and bind() gets confused because it expects a callable function, not None. On top of that, Kivy’s on_press callback automatically passes the pressed button instance as the first argument to your function—your current up_pressed doesn’t account for this extra parameter.
Solution 1: Use functools.partial (Recommended)
This is the cleanest way to pass extra arguments to your callback function. Here’s how to adjust your code:
- First, import
partialfromfunctoolsat the top of your.pyfile:
from functools import partial
- Update the
up_pressedfunction to accept the button instance (even if you don’t use it):
def up_pressed(self, floor_index, instance): # 'instance' is the button that was pressed; we don't need it here but must accept it a_request = Request( floor_index, FloorRequestStatus.up, self.generate_destination(floor_index, FloorRequestStatus.up), 0 ) self.request_queue.append(a_request) print(f"Up request added from floor {floor_index}") # Optional: Verify the request works
- Fix the binding in your
__init__method:
def __init__(self, **kwargs): super(FloorSystem, self).__init__(**kwargs) # Fix the floors list to use instance attributes (not class attributes) self.floors = [self.floor1, self.floor2, self.floor3, self.floor4] # Use partial to bind the floor index to up_pressed self.floor1.up_button.bind(on_press=partial(self.up_pressed, 1)) # Bonus: Loop to bind all floors at once (avoids repetitive code) # for floor_num, floor in enumerate(self.floors, start=1): # floor.up_button.bind(on_press=partial(self.up_pressed, floor_num))
Solution 2: Use a Lambda Function
If you don’t want to import functools, a lambda can wrap your function call for simple cases:
def __init__(self, **kwargs): super(FloorSystem, self).__init__(**kwargs) self.floors = [self.floor1, self.floor2, self.floor3, self.floor4] # Lambda captures the button instance and calls up_pressed with the floor index self.floor1.up_button.bind(on_press=lambda btn: self.up_pressed(1))
Then adjust up_pressed to skip the instance parameter:
def up_pressed(self, floor_index): a_request = Request( floor_index, FloorRequestStatus.up, self.generate_destination(floor_index, FloorRequestStatus.up), 0 ) self.request_queue.append(a_request)
Quick Additional Fixes
- In your
Floorclass, setup_button = ObjectProperty(None)instead ofObjectProperty(Button)—Kivy will automatically assign the button withid: up_buttonfrom your.kvfile to this property. - The
floorslist inFloorSystemwas defined as a class attribute, which won’t work correctly with instance-specificfloor1/floor2etc. Move it inside__init__as shown above to use instance attributes.
Testing the Fix
Run your app again, press the floor 1 up button, and check the request_queue—it should now add a new Request object each time the button is pressed.
内容的提问来源于stack exchange,提问作者Gary Yuan

