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

Kivy月度费用追踪APP:ScrollView内GridLayout的FloatLayout对齐问题

Fixing Your Kivy Monthly Expense Tracker Layout Issues

Hey there! Let's work through your Kivy layout problems step by step, and replace those wonky pos_hint hacks with clean, maintainable layouts.


1. Why those weird y values "worked" (and why they're a bad idea)

The odd y values (0 for the image, 1.15 for the category label, 1.35 for the date) are a symptom of misconfigured layout sizes:

  • When you set FL1 = FloatLayout(size=self.size), self refers to MyGrid—which hasn't finished laying out yet, so its size is Kivy's default (not the final 260x480 you set in Config).
  • Later, FL1 gets placed into a GridLayout cell with a fixed row_default_height=40, but its internal size is still stuck on the initial MyGrid size.
  • FloatLayout's pos_hint uses the parent's coordinate system: y=0 sticks to the bottom, y=1 sticks to the top. When your parent's size is wrong, setting y=1.15 shoves the label above the parent's actual top—just enough to visually align with the image, but this is a fragile hack that'll break if you change any layout dimensions.

2. Why size_hint messes up positioning, and better GridLayout alternatives

size_hint defines a widget's size as a percentage of its parent's size, so changing it directly alters how much space the widget takes up—and throws off any manual pos_hint values you set.

Your current nested FloatLayout mess is totally unnecessary! Kivy's built-in layouts (GridLayout, BoxLayout, AnchorLayout) are designed to handle this kind of structured layout automatically. Here's a better approach:

  • For each expense row, use a 2-column GridLayout (left for icon/info, right for amount).
  • On the left, use a horizontal BoxLayout to hold the image and a vertical BoxLayout for the category/date labels.
  • On the right, use an AnchorLayout to pin the amount label to the top-right.

This way, Kivy handles all sizing and positioning—no more manual pos_hint guesswork.


3. Why "BOOOOOOOOOOOKS" wraps when there's space

You set text_size=self.size on the category label, where self is MyGrid (full 260px width). But the label is actually inside a GridLayout cell that's only half the ScrollView width (since GL has cols=2). The label thinks it has 260px of space, but in reality it's confined to a narrower cell—so the text wraps once it hits the cell's edge, even though there's empty space in the full window.

The fix? Set text_size to match the label's actual available width, or let Kivy handle it with text_size=(None, None) and size_hint_x=1.


Optimized Code Example

Here's your refactored code that fixes all three issues, with clean, maintainable layouts:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.config import Config

Config.set('graphics', 'width', '260')
Config.set('graphics', 'height', '480')

class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.cols = 1
        
        # ScrollView and inner GridLayout for expenses
        SV = ScrollView()
        # Main expense grid: 2 columns, dynamic height
        expense_grid = GridLayout(
            cols=2,
            size_hint_y=None,
            height=self.minimum_height,
            spacing=(20, 20),
            row_default_height=40,
            row_force_default=True
        )
        expense_grid.bind(minimum_height=expense_grid.setter('height'))
        
        name = ['PET', 'GROCERIES', 'CLOTHES', 'BOOOOOOOOOOOKS', 'COSMETICS', 'TOILETRIES', 'GAMES']
        numa = ['$ 526.00', '$ 33.00', '$ 1008.28', '$ 10.85', '$ 25.20', '$ 100.00', '$ 66.85']
        
        for category, amount in zip(name[:6], numa[:6]):
            # Left side: Icon + category/date
            left_layout = BoxLayout(orientation='horizontal', spacing=10)
            # Icon (fixed size to avoid stretching)
            left_layout.add_widget(Image(source="pet.png", size_hint=(None, 1), width=30))
            # Category and date stacked vertically
            text_layout = BoxLayout(orientation='vertical', spacing=2)
            text_layout.add_widget(Label(
                text=category,
                size_hint_y=0.7,
                halign='left',
                valign='middle',
                text_size=(None, None)
            ))
            text_layout.add_widget(Label(
                text='Jan 20',
                size_hint_y=0.3,
                halign='left',
                font_size=10,
                text_size=(None, None)
            ))
            left_layout.add_widget(text_layout)
            
            # Right side: Amount aligned to top-right
            right_layout = BoxLayout()
            right_layout.add_widget(Label(
                text=amount,
                halign='right',
                valign='top',
                size_hint=(1, 1),
                text_size=(None, None)
            ))
            
            # Add to main expense grid
            expense_grid.add_widget(left_layout)
            expense_grid.add_widget(right_layout)
        
        SV.add_widget(expense_grid)
        self.add_widget(Button(text='Arbitrary Button 1', background_color=(.7, .5, .9, 1)))
        self.add_widget(SV)
        self.add_widget(Button(text='Arbitrary Button 2', background_color=(.7, .5, .9, 1)))

class MainApp(App):
    def build(self):
        return MyGrid()

MainApp().run()

Key improvements:

  • No more FloatLayout hacks—uses BoxLayout and GridLayout to handle automatic positioning
  • Fixed text wrapping by removing the incorrect text_size=self.size
  • Icon uses fixed width (size_hint=(None,1)) to maintain aspect ratio
  • All sizing is relative to parent containers, so layout stays consistent if you adjust window size

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:42:53