You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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.size and root.pos for the ellipse stencil, so the tank scales with the widget's bounds.
  • Reusable WaterFill Widget: Uses Kivy properties (NumericProperty, ListProperty) to make level and color easy to customize for each tank.
  • Smooth Animation: The update_level method uses Clock.schedule_interval to increment/decrement the level, creating a smooth fill/drain cycle.
  • Multiple Tanks: The TankLayout (a horizontal BoxLayout) 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 Line section if you don't need it.

How It Works

  1. Stencil Clipping: We use StencilPush to start the mask, draw the ellipse (the tank shape), then StencilUse to ensure all subsequent drawing is clipped to that ellipse. Finally, StencilPop cleans up the mask so other widgets aren't affected.
  2. Water Positioning: The fill rectangle's pos is calculated to start at the bottom of the tank—root.pos[1] + (1 - root.level) * root.height means as level increases, the rectangle moves up and fills more of the tank.
  3. Animation Cycle: The fill_direction variable flips between 1 and -1 when the tank is full or empty, creating a continuous fill/drain loop.

内容的提问来源于stack exchange,提问作者Bhu_24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:13:44