Kivy:如何在Python代码的子小部件中正确绑定画布矩阵操作?

问题描述 投票:0回答:2

我正在使用calculator tutorial from RealPython,并且每当父窗口小部件的宽度小于我的Label小窗口中的texture_size时,我都希望缩放Label子窗口小部件的画布。在我的代码中,我的Lable位于布局中,因此其位置和大小取决于其父项。

[我正在KvLang that scales a child widget well中获取一些代码,并在Python中实现它,以便更好地理解Kivy的编码。

[每当父窗口小部件位置发生变化时,我都会调用我孩子的check_canvas()方法来运行其画布指令,在那里我调用Scale,但它似乎对我的Label中的文本没有任何作用。

如何使用Python代码中的Scale调整myTextInput画布的大小? (我有意避免使用KvLang)

这是我的代码中涉及我要完成的部分

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.graphics import PushMatrix,PopMatrix,Scale

class myTextInput(Label):

    def __init__(self, **kwargs):
        super(myTextInput,self).__init__(**kwargs)

    def check_canvas(self):   
        if self.texture_size[0] < self.width:
            self._scale = 1
        else:
            self._scale = float(self.width) / self.texture_size[0]

        self.text = 'my scale text here (%d, %.2f)' % (self.width, self._scale)

        with self.canvas.before:

            PushMatrix()
            Scale(
                origin = self.center,
                x = self._scale or 1,
                y = self._scale or 1
                )
        with self.canvas.after:
            PopMatrix()

class MainApp(App):
    def build(self):
        self.operators = ["/", "*", "+", "-"]
        self.last_was_operator = None
        self.last_button = None
        main_layout = BoxLayout(orientation="vertical")

        self.solution = myTextInput(font_size= main_layout.height * 0.5)

        def callback_size(instance, value):
            print('The widget', instance, 'sized to', value)
            print('The widget', instance, 'texture_size[0] is', instance.texture_size[0])

            #What I have noted here is that the texture_size[0] and size
            #are responsive but not _scale and canvas operations.
            #I made check_canvas() to 'enforce' a check on _scale and canvas operation but
            #although now I see _scale changing, canvas operations are not showing any result

            instance.check_canvas() 

            print('The widget', instance, '_scale is', instance._scale)           

        self.solution.bind(size = callback_size)                
        main_layout.add_widget(self.solution)
python canvas widget kivy scaling
2个回答
0
投票
在您的代码中,该行:

self.solution = myTextInput(font_size= main_layout.height * 0.5)

在执行该行时将font_sizemyTextInput设置为main_layout高度的一半。由于该行以build()方法执行,因此在实际显示main_layout之前,其height是默认的100,因此font_size设置为50。不管font_size的大小如何,myTextInput都不会改变。 Scale指令仅更改myTextInput的大小,而不更改font_size。如果您在kv中设置:

font_size: main_layout.height * 0.5

((假设main_layout中定义了kv),则每当font_sizeheight更改时,都会调整main_layout。那是对kv语言的补充。如果您使用Python进行此操作,则必须自己进行处理。您可以通过在font_size方法中添加代码来调整check_canvas()来做到这一点:

def check_canvas(self, main_layout): if self.texture_size[0] < self.width: self._scale = 1 else: self._scale = float(self.width) / self.texture_size[0] self.text = 'my scale text here (%d, %.2f)' % (self.width, self._scale) # adjust the font_size self.font_size = main_layout.height * 0.1 with self.canvas.before: PushMatrix() Scale( origin = self.center, x = self._scale or 1, y = self._scale or 1 ) with self.canvas.after: PopMatrix()

请注意,修改后的check_canvas()main_layout作为参数,因此对该方法的调用必须在callback_size()中更改为:

instance.check_canvas(main_layout)

我已经将font_size的系数从0.1更改为0.5,因为这看起来很大。

0
投票
[这是另一种仍然像代码一样使用Matrix的方法,但是计算字体大小以适合myTextInput的宽度:

from kivy.core.text import Label as CoreLabel . . . def check_canvas(self): if self.texture_size[0] < self.width: self._scale = 1 else: self._scale = float(self.width) / self.texture_size[0] self.text = 'my scale text here (%d, %.2f)' % (self.width, self._scale) # adjust the font_size self.font_size = self.calculate_font_to_fit(self.text, self.width) # need to clear the canvas instructions, or they just keep accumulating self.canvas.before.clear() self.canvas.after.clear() with self.canvas.before: PushMatrix() Scale( origin = self.center, x = self._scale or 1, y = self._scale or 1 ) with self.canvas.after: PopMatrix() def calculate_font_to_fit(self, text, width): # use core.text.Label to calculate size of a Label with given font and text self.core_label = CoreLabel(text=text, font_name=self.font_name, font_size = self.font_size) self.core_label.refresh() curr_width = self.core_label.texture.width new_font_size = int(self.font_size) if curr_width > width: # reduce font size while curr_width > width: new_font_size -= 1 self.core_label = CoreLabel(text=text, font_name=self.font_name, font_size = new_font_size) self.core_label.refresh() curr_width = self.core_label.texture.width elif curr_width < width: # increase font size while curr_width < width: old_font_size = new_font_size new_font_size += 1 self.core_label = CoreLabel(text=text, font_name=self.font_name, font_size = new_font_size) self.core_label.refresh() curr_width = self.core_label.texture.width new_font_size = old_font_size return new_font_size

© www.soinside.com 2019 - 2024. All rights reserved.