Kivy中窗口大小变化时如何让FloatLayout尺寸与内部图片保持一致
Kivy FloatLayout与内部图片尺寸同步解决方案
问题根因
当前逻辑为FloatLayout先按窗口比例确定自身尺寸,再让开启keep_ratio=True的棋盘图片适配布局大小,图片为了保持原始宽高比不会完全填满布局,因此会出现布局绿色背景露出的问题。需要将逻辑反转:先根据棋盘比例和窗口可用空间计算出图片的实际显示尺寸,再让FloatLayout尺寸与图片完全对齐。
具体修改点
- 移除FloatLayout的百分比尺寸配置
size_hint,改为手动控制布局尺寸 - 提前获取棋盘图片的原始宽高比,监听窗口尺寸变化事件,动态计算适配窗口的棋盘显示尺寸
- 同步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
相关产品推荐
相关产品推荐

