簡體   English   中英

在 Kivy 中,如何制作一個 bitmap,點擊並(按比例)調整大小?

[英]In Kivy, how to make a bitmap, point-clickable and (proportionally) resizable?

我試圖在 Kivy 中顯示一個 bitmap,並賦予它幾個屬性,其中一些屬性似乎是相互排斥的。 它應該是:

  • 點點擊(能夠找到點坐標,而不僅僅是點擊按鈕)
  • 可調整大小
  • 調整大小時保持比例

這是最后一項似乎有問題。 我可以制作一個 bitmap,它基本上是一個按鈕類型的 object,並且可以點擊 - 但它是固定大小的。 或者我可以制作一個“有彈性的”bitmap,它會在 Window 調整大小時調整大小。 但是 - 要么是比例變化,要么是 Widget 的“位圖”部分以正確的比例顯示,但是 Widget 有一個不成比例的組件,可以單擊。

第一套是“按鈕”模式,第二套是“拉伸”模式。

按鈕模式小部件

拉伸模式小部件

在拉伸模式下,實際顯示bitmap會調整大小並保持比例大小。 但是,顯示它的圖像小部件正在不按比例調整大小。 (因此keep_ratio選項適用於顯示的 bitmap,但不適用於實際的 Widget object。)這很好,但整個 Widget 都是可點擊的,我還沒有找到確定點擊點位置的方法,相對於 bitmap。

我可以想到半解決方案,例如強制 Window 調整大小成比例,根據需要更改寬度/高度以匹配,但這相當混亂。 似乎應該有某種方法可以使用 Kivy 對象/屬性,但我還沒有找到。

實際代碼示例。 要以“按鈕”模式運行,

  KIVY_NO_ARGS=1 python show_bitmap.py -b
import sys
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window
from kivy.uix.relativelayout import RelativeLayout
hex_bmp = 'basic_hexes.png'
hex_bmp_size = (456, 292)

stretch_params = {'source': hex_bmp,  # Bitmap is stretchable, but click-region is wrong
                  'allow_stretch': True,
                  'keep_ratio': True,
                  'pos': (110, 110),
                  'size': hex_bmp_size,
                  'size_hint': (0.5, 0.5),
                  }
button_params = {'source': hex_bmp,  # Behaves like a Button, with regard to click-region
                 'allow_stretch': True,
                 'keep_ratio': True,
                 'pos': (110, 110),
                 'size': hex_bmp_size,
                 'size_hint': (None, None),
                 }
new_params = stretch_params

class VariableImage(Image):
    def __init__(self, **kwargs):
        super().__init__(**new_params, **kwargs)
        Window.bind(on_resize=self.on_window_resize)
        with self.canvas.before:
            Color(0.9, 0.2, 0.2, 0.5)
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)

    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            print(f"*** Clicked VariableImage, pos: {touch.pos}")

    def on_window_resize(self, window, width, height):
        self.bg_rect.size = self.size

class TopBoxLayout(RelativeLayout):
    def __init__(self, initial_window_size, **kwargs):
        super().__init__(**kwargs)
        self.orientation = 'vertical'
        self.bg_rect = None
        self.size = initial_window_size
        self.label_2 = Label(text='WTF?', pos_hint={'top': 1}, size_hint=(1.0, 0.1))
        self.add_widget(self.label_2)
        self.back_picture = VariableImage()
        self.add_widget(self.back_picture)
        self.setup_background()
        Window.bind(on_resize=self.on_window_resize)

    def setup_background(self):
        with self.canvas.before:
            Color(0.6, 0.6, 0.6, 0.9)
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
        with self.canvas.after:
            Color(0.9, 0.9, 0.9, 0.9)
            self.target_rect = Rectangle(pos=(100, 100), size=(10, 10))

    def on_window_resize(self, window, width, height):
        self.bg_rect.pos = self.pos
        self.bg_rect.size = self.size

class canvasMain(App):
    def build(self):
        Window.size = (700, 450)
        self.root = TopBoxLayout(Window.size)
        return self.root

if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == '-b':
        new_params = button_params
    canvasMain().run()

我認為關鍵是要確保VariableImage實例保持其比率與 bitmap 的比率相匹配。這是執行此操作的代碼的修改版本:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.uix.relativelayout import RelativeLayout

kv = '''
<TopBoxLayout>:
    canvas.before:
        Color:
            rgba: (0.6, 0.6, 0.6, 0.9)
        Rectangle:
            pos: self.pos
            size: self.size
        Color:
            rgba: (0.9, 0.9, 0.9, 0.9)
        Rectangle:
            pos: 100, 100
            size: 10, 10
    Label:
        text: 'WTF?'
        pos_hint: {'top': 1}
        size_hint: (1.0, 0.1)
    VariableImage:
        id: vi
        size_hint: None, None
        # size: 0.5 * root.width, 0.5 * root.width / self.image_ratio  # does the same as the `on_size()` method
<VariableImage>:
    source: 'basic_hexes.png'
    allow_stretch: True
    keep_ratio: True
    pos: (110, 110)
    canvas.before:
        Color:
            rgba: (0.9, 0.2, 0.2, 0.5)
        Rectangle:
            pos: self.pos
            size: self.size
'''

class VariableImage(Image):

    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            print(f"*** Clicked VariableImage, pos: {touch.pos}")

class TopBoxLayout(RelativeLayout):
    def on_size(self, instance, new_size):
        vi = self.ids.vi
        # adjust size of VariableImage based on layout width
        # a more complicated logic can be used, like keeping size with layout size
        vi.size = 0.5 * self.width, 0.5 * self.width / vi.image_ratio

class canvasMain(App):
    def build(self):
        Window.size = (700, 450)
        Builder.load_string(kv)
        return TopBoxLayout()

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

這使用kivy語言做了一些簡化。 kv中的行:

size: 0.5 * root.width, 0.5 * root.width / self.image_ratio

保持VariableImage的比率與 bitmap 比率相同(如果未注釋)。 TopBoxLayout 的TopBoxLayout on_size()方法將做完全相同的事情,但更容易用於更復雜的邏輯。

您不需要這兩種方法。 可以刪除一個或另一個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM