基于Kivy实现多水箱圆形容器的分层水位填充效果
Circular Water Tank Fill Effect with Multiple Tanks (Kivy Implementation)
Got it, let's build this multi-tank water fill effect properly using Kivy! I'll expand on your existing code snippet to create a reusable WaterFill widget that supports dynamic sizing, custom colors, and automatic level animation—plus we'll add support for multiple tanks in a layout.
Complete Working Code
from kivy.app import App from kivy.clock import Clock from kivy.uix.widget import Widget from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import NumericProperty, ListProperty Builder.load_string(""" <WaterFill>: id: tank level: 0.0 color: 0, 0, 1 # Default blue size_hint: None, 1 width: self.height # Keep it a perfect circle canvas: # Stencil setup: define the circular tank shape as the mask StencilPush Ellipse: size: root.size pos: root.pos StencilUse # Draw the water fill, clipped to the stencil Color: rgb: root.color Rectangle: # Position starts at the bottom, moves up as level increases pos: root.pos[0], root.pos[1] + (1 - root.level) * root.height # Height scales with the level, width matches the tank size: root.width, root.level * root.height # Draw the tank outline (optional but makes it clearer) Color: rgb: 0, 0, 0 # Black outline Line: ellipse: root.pos[0], root.pos[1], root.width, root.height, 0, 360 width: 2 # Clean up the stencil StencilPop <TankLayout>: orientation: 'horizontal' spacing: 40 padding: 40 size_hint: 1, 1 """) class WaterFill(Widget): # Property to track water level (0.0 = empty, 1.0 = full) level = NumericProperty(0.0) # Property to customize water color color = ListProperty([0, 0, 1]) def __init__(self, **kwargs): super().__init__(**kwargs) # Start the fill animation Clock.schedule_interval(self.update_level, 0.02) self.fill_direction = 1 # 1 = filling up, -1 = draining down def update_level(self, dt): # Update the level based on direction self.level += self.fill_direction * 0.005 # Reverse direction when full or empty if self.level >= 1.0 or self.level <= 0.0: self.fill_direction *= -1 class TankLayout(BoxLayout): pass class TankApp(App): def build(self): layout = TankLayout() # Add multiple tanks with different colors layout.add_widget(WaterFill(color=[0.2, 0.6, 0.8])) # Light blue layout.add_widget(WaterFill(color=[0.1, 0.8, 0.3])) # Green layout.add_widget(WaterFill(color=[0.9, 0.3, 0.2])) # Red return layout if __name__ == '__main__': TankApp().run()
Key Features Explained
- Dynamic Circular Mask: Instead of fixed positions/sizes, we use
root.sizeandroot.posfor the ellipse stencil, so the tank scales with the widget's bounds. - Reusable
WaterFillWidget: Uses Kivy properties (NumericProperty,ListProperty) to make level and color easy to customize for each tank. - Smooth Animation: The
update_levelmethod usesClock.schedule_intervalto increment/decrement the level, creating a smooth fill/drain cycle. - Multiple Tanks: The
TankLayout(a horizontalBoxLayout) lets you add as many tanks as you want, each with its own color and independent animation. - Tank Outline: Added a simple black outline to make the tank shape more visible—you can remove this by deleting the
Linesection if you don't need it.
How It Works
- Stencil Clipping: We use
StencilPushto start the mask, draw the ellipse (the tank shape), thenStencilUseto ensure all subsequent drawing is clipped to that ellipse. Finally,StencilPopcleans up the mask so other widgets aren't affected. - Water Positioning: The fill rectangle's
posis calculated to start at the bottom of the tank—root.pos[1] + (1 - root.level) * root.heightmeans aslevelincreases, the rectangle moves up and fills more of the tank. - Animation Cycle: The
fill_directionvariable flips between 1 and -1 when the tank is full or empty, creating a continuous fill/drain loop.
内容的提问来源于stack exchange,提问作者Bhu_24
相关产品推荐
相关产品推荐

