Kivy: Как правильно связать матрицу холста в дочернем виджете в коде Python? - PullRequest
0 голосов
/ 27 апреля 2020

Я работаю с учебником калькулятора от Real Python и хочу масштабировать холст моего дочернего виджета Label всякий раз, когда ширина родительского виджета меньше, чем texture_size в моем виджете Label. В моем коде мой Lable находится в макете, и поэтому его положение и размер основаны на его родителе.

Я беру некоторый код в KvLang, который хорошо масштабирует дочерний виджет , и реализую его в Python, чтобы лучше понять кодирование с помощью Kivy.

Всякий раз, когда изменяется положение родительского виджета, я вызываю метод check_canvas () моего ребенка для запуска его инструкций canvas, и там я вызываю Scale, но, похоже, ничего не делать с текстом в моем ярлыке.

Как изменить размер холста myTextInput с помощью Scale в Python коде? (Я намеренно избегаю KvLang)

Вот часть моего кода, которая включает в себя то, что я пытаюсь выполнить sh

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)

Ответы [ 2 ]

0 голосов
/ 27 апреля 2020

Вот еще один подход, который все еще использует 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
0 голосов
/ 27 апреля 2020

В вашем коде строка:

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

Устанавливает font_size из myTextInput равной половине высоты 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

(при условии, что в вашем kv определено main_layout), тогда font_size будет корректироваться при каждом изменении height из 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 только потому, что он кажется довольно большим.

...