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

Kivy中窗口大小变化时如何让FloatLayout尺寸与内部图片保持一致

Kivy FloatLayout与内部图片尺寸同步解决方案

问题根因

当前逻辑为FloatLayout先按窗口比例确定自身尺寸,再让开启keep_ratio=True的棋盘图片适配布局大小,图片为了保持原始宽高比不会完全填满布局,因此会出现布局绿色背景露出的问题。需要将逻辑反转:先根据棋盘比例和窗口可用空间计算出图片的实际显示尺寸,再让FloatLayout尺寸与图片完全对齐。


具体修改点

  1. 移除FloatLayout的百分比尺寸配置size_hint,改为手动控制布局尺寸
  2. 提前获取棋盘图片的原始宽高比,监听窗口尺寸变化事件,动态计算适配窗口的棋盘显示尺寸
  3. 同步FloatLayout的尺寸与棋盘尺寸,保证布局不会超出图片边界

修改后完整代码

from kivy.config import Config

Config.set('graphics', 'resizable', True)
Config.set('graphics', 'window_state', 'maximized')
Config.write()

import kivy
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window # 新增导入用于监听窗口大小变化

kivy.require('2.0.0')

class DraggableArea(FloatLayout):
    def __init__(self, **kwargs):
        super(DraggableArea, self).__init__(**kwargs)
        # 移除固定百分比size_hint,改为手动控制尺寸
        self.size_hint = (None, None)
        self.pos = (40, 40) # 固定边距与原逻辑一致
        # 提前获取棋盘原始宽高比
        self.board_img_path = "./data/images/chess-pieces/DarkerGreenGreyChessBoard.png"
        self.board_ratio = Image(source=self.board_img_path).texture_ratio

        with self.canvas.before:
            Color(0, 1, 0, 1) 
            self.rect = Rectangle(size=self.size, pos=self.pos)

        # 监听布局位置、尺寸变化更新背景
        def update_rect(instance, value):
            instance.rect.pos = instance.pos
            instance.rect.size = instance.size
        self.bind(pos=update_rect, size=update_rect)

        # 首次初始化添加棋盘和棋子
        self.add_widget(
            Image(source=self.board_img_path, pos=self.pos,
                  size_hint=(1, 1), keep_ratio=True, allow_stretch=True)
        )
        self.add_widget(
            MoveableImage(source="./data/images/chess-pieces/WhiteQueen57.png",
                          pos=self.pos)
        )

        # 监听窗口大小变化,动态调整布局尺寸
        def update_layout_size(*args):
            # 可用空间为窗口尺寸减去左右、上下各40的边距(和原pos设置对齐)
            max_available_w = Window.width - 80
            max_available_h = Window.height - 80
            # 按棋盘比例计算最大不超出可用空间的尺寸
            if max_available_w / max_available_h > self.board_ratio:
                layout_h = max_available_h
                layout_w = layout_h * self.board_ratio
            else:
                layout_w = max_available_w
                layout_h = layout_w / self.board_ratio
            # 更新布局尺寸,内部图片会自动适配布局大小
            self.size = (layout_w, layout_h)
        
        # 绑定窗口变化事件,首次启动触发一次计算
        Window.bind(size=update_layout_size)
        update_layout_size()


class MoveableImage(DragBehavior, Image):
    def __init__(self, **kwargs):
        super(MoveableImage, self).__init__(**kwargs)
        self.drag_timeout = 10000000
        self.drag_distance = 0
        self.drag_rectangle = [self.x, self.y, self.width, self.height]
        self.size_hint = (.1, .1) 
        self.keep_ratio = True
        self.allow_stretch = True  

    def on_pos(self, *args):
        self.drag_rectangle = [self.parent.x, self.parent.y, self.parent.width, self.parent.height]

    def on_size(self, *args):
        self.drag_rectangle = [self.parent.x, self.parent.y, self.parent.width, self.parent.height]


class egGameApp(App):
    def build(self):
        return DraggableArea()


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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:57:02