2016-12-27 6 views
0

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

Что я заметил, так это то, что когда я добавлю виджет в другой виджет, если я сделаю это через код Python, он будет немного в другом положении, чем если бы я сделал это через Kivy. Я вставлю свой код ниже (сейчас он довольно короткий), и вы можете просто попробовать его сами, и вы поймете, что я имею в виду.

client.py:

import kivy 
kivy.require('1.9.1') # current kivy version 

from kivy.config import Config 
Config.set('graphics', 'width', '360') 
Config.set('graphics', 'height', '640') 

from kivy.app import App 
from kivy.uix.widget import Widget 
from kivy.properties import ObjectProperty, NumericProperty, ReferenceListProperty 
from kivy.graphics import Color, Rectangle 
from kivy.clock import Clock 
from kivy.vector import Vector 
from random import randint 

class Bird(Widget): 
    ''' 
     Bird Widget defines each sprite./Test version: blue and red cards 
     Defined attributes: 
      SIZE 
      POSITION 
      (COLOR) 
     Upade the position of this widget individually every 0.7 seconds with 60 fps 
    ''' 

    # set attributes 
    border_color = (1,1,1) 
    r = NumericProperty(0) 
    g = NumericProperty(0) 
    b = NumericProperty(0) 
    color = ReferenceListProperty(r, g, b) # initial color = red // maybe make it random 

    velocity_x = NumericProperty(0) 
    velocity_y = NumericProperty(-3) 
    velocity = ReferenceListProperty(velocity_x, velocity_y) 

    def __init__(self, **kwargs): 
     super(Bird, self).__init__(**kwargs) 
     self.pick_color() 

    # Randomly generate 0 or 1, and pick a color based on that 
    def pick_color(self): 
     color_num = randint(0,1) 

     if color_num == 0: # blue 
      self.color = (0,0,1) 
     elif color_num == 1: # red 
      self.color = (1,0,0) 

    # Move the widget by -3y increment at 60 fps 
    def increment(self, dt): 
     self.pos = Vector(*self.velocity) + self.pos 

    def move(self): 

     # While the sprite moves at 60 fps, the movement is "cancelled" after 0.3 seconds 
     # This event sequence is refreshed every 0.7 seoncds in MainApp class 
     move = Clock.schedule_interval(self.increment, 1.0/60.0) 
     stop = Clock.schedule_once(lambda dt: move.cancel(), 0.3) 


class GameMain(Widget): 
    ''' 
     Contains two functions: ADD_NEW_BIRD() and UPDATE(). 
     All controls happen in this widget 
     Not using kivy.screen because there is only one screen used 

     ADD_NEW_BIRD() adds a new bird to list_of_birds AND add it as a child widget to the GameMain Widget. UPDATE() calls MOVE() (Bird Widget) and receives events 

     Create global variable limit = 0; if limit == 4, game over; variable accessed in update function, which checks whether the limit has been reached. If the player makes the right decision, then limit -= 1 
    ''' 

    limit = 0 

    def add_new_bird(self): 
     self.new_bird = Bird(center_x=self.center_x, center_y=self.height/1.5) 
     print (self.center_x, self.height) 
     self.new_bird.pick_color() 
     self.add_widget(self.new_bird) 

    def update(self, dt): 
     for bird in self.children: 
      bird.move() 

     self.add_new_bird() 

class MainApp(App): 

    def build(self):  
     game = GameMain() 
     Clock.schedule_interval(game.update, 0.7) 
     return game 


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

main.kv:

#:kivy 1.9 

<Bird>: 
    size: 70, 80 
    canvas: 
     Color: 
      rgb: self.border_color 
     Rectangle: 
      size: self.size 
      pos: self.pos 
     Color: 
      rgb: self.color 
     Rectangle: 
      size: root.width - 10, root.height - 10 
      pos: root.x + 5, root.y + 5 

<GameMain> 
    Bird: 
     center_x: root.center_x 
     center_y: root.height/1.5 

код делает именно то, что я хочу, чтобы это сделать (я собираюсь остановиться на Z-значениях позже) за исключением того, что самая первая карта слегка отведена влево. Я просто очень смущен, потому что center_x: root.center_x в main.kv не должен отличаться от Bird(center_x=self.center_x в client.py насколько я понимаю. Я пытался инициализировать первый экземпляр Bird() внутри функцию инициализации, как так:

def __init__(self, **kwargs): 
    super(GameMain, self).__init__(**kwargs) 
    self.bird = Bird(center_x=self.center_x, center_y=self.height/1.5) 
    self.bird.pick_color() 
    self.add_widget(self.bird) 

И проблема была все еще там! Если бы кто-нибудь мог объяснить, что происходит/что я делаю неправильно, и, возможно, даже предложить лучший способ приблизиться к этому, я был бы признателен.

На всякий случай вам любопытно, мне нужно добавить виджеты непосредственно из кода Python, потому что мне нужно приложение для постоянного создания новой карты с постоянным временным интервалом. Однако первая карта инициализируется в файле Kivy для простоты. Чтобы быть справедливым, это работает очень хорошо, за исключением смещения. И, наконец, я не использую макет, потому что не был уверен, какой из них использовать ... Я немного положил руки на FloatLayout, но, похоже, это не решило проблему.

ответ

1

При построении виджет имеет начальный размер (100, 100). Если изменить размер от этого:

<Bird>: 
    size: 70, 80 

к этому:

<Bird>: 
    size: 100, 80 

прямоугольники будут выровнены правильно. Исходный прямоугольник, созданный в файле kv, центрируется в родительском окне, другие, созданные в коде Python, смещены влево.

Если изменить Птичий конструктор в коде Python из этого:

def __init__(self, **kwargs): 
    super(Bird, self).__init__(**kwargs) 
    self.pick_color() 

этого (фактически перекрывая размер виджета по умолчанию из (100, 100), чтобы быть (50,50)):

def __init__(self, **kwargs): 
    self.size = (50, 50) 
    super(Bird, self).__init__(**kwargs) 
    self.pick_color() 

вы заметите, что прямоугольники, созданные в коде Python, сдвинутся вправо. Изменение киловольт файла из:

<Bird>: 
    size: 70, 80 

к:

<Bird>: 
    size: 50, 80 

, который соответствует (новый) начальный размер виджета (50,50) в ширину, все прямоугольники будут выровнены снова.

Решение вашей проблемы было бы оставить все как есть, за исключением того, чтобы установить size для новых птиц в Python, чтобы быть равным, что в кв файла:

def __init__(self, **kwargs): 
    self.size = (70, 80) 
    super(Bird, self).__init__(**kwargs) 
    self.pick_color() 

и все будет работать, как задумано.

Это означает, что свойство size из файла kv не применяется к вашим созданным на основе Питона птицам, только к тому, которое создано декларацией kv. Является ли это ошибкой Kivy или, возможно, вам не хватает еще одного шага в коде Python, чтобы Builder применил size от файла kv к созданным Python птицам, я понятия не имею прямо сейчас.

По моему опыту, в этот момент развития Kivy, слишком много смешивания kv и кода Python приведут к таким странным проблемам, которые у вас здесь есть. Лучше либо обрабатывать все связанные с просмотром вещи в kv, либо полностью вырезать kv и строить все в Python.

Некоторые вещи вообще не работают в kv, то есть устанавливают cols свойство GridLayout (v1.9.1).

Лично, на данный момент я придерживаюсь хорошо организованного кода Python для создания пользовательского интерфейса и практически не использую файлы kv.

Надеюсь, это немного помогает ...

+0

Спасибо. Я закончил использовать обходной путь, но зная, что это спасло бы меня от головной боли. Кроме того, эта часть о том, чтобы не смешивать слишком много киви и питона - я вижу эту проблему прямо сейчас, с Popups. Я бы хотел, чтобы это идеальное «разделение» (kivy обрабатывает все элементы интерфейса UI, питон управляет логикой), но поскольку я добавляю виджеты динамически довольно часто, я в конечном итоге использую python больше. Может быть, я должен полностью удалить киви файл. – spicypumpkin