Киви: Как сделать размер этикетки и размер холста равными? - PullRequest
0 голосов
/ 10 апреля 2020

Я сделал квадратную сетку этикеток, используя Gridlayout. Теперь я хочу добавить цвет фона метки (каждый из которых имеет разные прямоугольники). Я попытался сделать это с помощью следующего кода.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Rectangle, Color
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label


class MyGrid(FloatLayout):
    def __init__(self,**kwargs):
        super(MyGrid,self).__init__(**kwargs)
        self.grid=GridLayout()
        self.grid_size=4
        self.grid.cols=self.grid_size
        for k in range(self.grid_size):
            for i in range(self.grid_size):
                with self.grid.canvas:
                    Rectangle(size=(100,100),pos=(k*160+100,i*160+100),source="52852.JPG")
        for h in range(self.grid_size):
            for j in range(self.grid_size):
                self.grid.add_widget(Label(text="labwl"+str(h)+str(j),size=(100,100),pos=(h*160+100,j*160+100)))
        self.add_widget(self.grid)

class GameApp(App):
    def build(self):
        return MyGrid()

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

В этом коде, если я не указываю "self.grid.cols", он генерирует предупреждение в консоли python, а также когда окно в полноэкранном режиме прямоугольники с холста сохраняют исходный размер и положение, а метки - нет. Я хочу разместить надписи перед прямоугольниками холста, и они также должны сохранять размер экрана, как указано. Более того, если я изменю «self.grid.size» на любое другое число, оно должно составить сетку из меток той же длины и соответствующего количества холста. Я попытался использовать поплавок для этой цели, но это не помогло. Прямоугольники и метки холста должны вписываться в окно независимо от размера окна. Было бы лучше, если бы я мог получить решение вышеупомянутой проблемы, записанное в файле python (не в файле .kv). Если вы знаете другое решение этой проблемы или любой другой виджет, пожалуйста, дайте мне знать. Как и для виджета кнопки, мы можем указать цвет фона и текста, а также добавить любой виджет, который будет выполнять вышеуказанную задачу. Вы должны заменить «источник» в прямоугольном холсте на любой известный файл изображения. Я надеюсь, вы понимаете. Если вы не хотите, пожалуйста, дайте мне знать. :)

1 Ответ

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

Установка Widgets без изменений size или pos - самое простое решение. В основном просто используйте size_hint=(None, None) и не используйте GridLayout:

from kivy.app import App
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label


class MyGrid(FloatLayout):
    def __init__(self,**kwargs):
        super(MyGrid,self).__init__(**kwargs)
        self.grid_size=4
        for k in range(self.grid_size):
            for i in range(self.grid_size):
                with self.canvas:
                    Rectangle(size=(100,100),pos=(k*160+100,i*160+100),source="52852.JPG")
        for h in range(self.grid_size):
            for j in range(self.grid_size):
                self.add_widget(Label(text="labwl"+str(h)+str(j),size=(100,100),pos=(h*160+100,j*160+100), size_hint=(None, None)))

class GameApp(App):
    def build(self):
        return MyGrid()

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

Чтобы сделать Rectangles и Labels изменения pos и size немного сложнее. В измененной версии вашего кода ниже я храню списки Labels и Rectangles, а также bind adjust_common_size() метода, который будет запускаться при изменении size из MyGrid. Затем этот метод настраивает size и pos Labels и Rectangles для соответствия:

from kivy.app import App
from kivy.properties import ListProperty
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label


class MyGrid(FloatLayout):
    common_size = ListProperty((100, 100))
    def __init__(self,**kwargs):
        super(MyGrid,self).__init__(**kwargs)
        self.grid_size=4
        self.rects = []
        self.labels = []
        for k in range(self.grid_size):
            one_row = []
            self.rects.append(one_row)
            for i in range(self.grid_size):
                with self.canvas:
                    one_row.append(Rectangle(size=self.common_size,pos=(k*160+100,i*160+100),source="52852.JPG"))
        for h in range(self.grid_size):
            one_row = []
            self.labels.append(one_row)
            for j in range(self.grid_size):
                label = Label(text="labwl"+str(h)+str(j),size=self.common_size,pos=(h*160+100,j*160+100), size_hint=(None, None))
                one_row.append(label)
                self.add_widget(label)

        self.bind(size=self.adjust_common_size)

    def adjust_common_size(self, instance, new_size):
        self.common_size = (new_size[0] * 0.9 / self.grid_size, new_size[1] * 0.9 / self.grid_size)
        for k in range(self.grid_size):
            for i in range(self.grid_size):
                adjusted_pos = (k * new_size[0] / self.grid_size, i * new_size[1] / self.grid_size)
                rect = self.rects[k][i]
                label = self.labels[k][i]
                label.size = self.common_size
                label.pos = adjusted_pos
                rect.size = self.common_size
                rect.pos = adjusted_pos

class GameApp(App):
    def build(self):
        return MyGrid()

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

Использование ListProperty для common_size не является необходимым, но будет удобно, если вы решите использовать kv.

Это интересный вопрос. Вот лучший способ сделать совпадение Rectangle и Label. Приведенный ниже код использует GridLayout, но определяет MyLabel для включения его Rectangle и сохранения его Rectangle в pos и size:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label

class MyLabel(Label):
    def __init__(self, **kwargs):
        super(MyLabel, self).__init__(**kwargs)
        with self.canvas.before:
            self.rect = Rectangle(size=self.size,pos=self.pos,source="52852.JPG")
        self.bind(size=self.adjust_size)
        self.bind(pos=self.adjust_pos)

    def adjust_pos(self, instance, new_pos):
        self.rect.pos = new_pos

    def adjust_size(self, instance, new_size):
        self.rect.size = new_size


class MyGrid(FloatLayout):
    def __init__(self,**kwargs):
        super(MyGrid,self).__init__(**kwargs)
        self.grid=GridLayout()
        self.grid_size=4
        self.grid.cols=self.grid_size
        for h in range(self.grid_size):
            for j in range(self.grid_size):
                self.grid.add_widget(MyLabel(text="labwl"+str(h)+str(j),size=(100,100),pos=(h*160+100,j*160+100)))
        self.add_widget(self.grid)

class GameApp(App):
    def build(self):
        return MyGrid()

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

При таком подходе вам вообще не нужно создавать Rectangles в MyGrid, поскольку каждый Label создает свой собственный.

...