2016-12-27 6 views
0

Ich habe gerade Kivy abgeholt und bin auf dieses Problem gestoßen. Wenn es einen besseren Weg gibt, das zu erreichen, was ich generell versuche, würde ich gerne davon hören.Kivy platziert Widgets über Python und Kivy leicht anders. Fehle ich etwas?

Was ich bemerkt habe, ist, dass, wenn ich ein Widget zu einem anderen Widget hinzufügen, wenn ich dies durch Python-Code tun wird es leicht an einer anderen Position als ich es durch Kivy getan habe. Ich füge meinen Code unten ein (im Moment ist es ziemlich kurz) und du kannst es einfach selbst ausprobieren und du wirst sehen, was ich meine.

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 

Der Code macht genau das, was ich will es tun (ich auf die z-Werte später berühren werde) außer dass die allererste Karte leicht nach links abweicht. Ich bin nur wirklich verwirrt, weil center_x: root.center_x in main.kv nicht anders sein sollte als Bird(center_x=self.center_x in client.py, soweit ich verstehe. Ich habe versucht, innerhalb einer init-Funktion die ersten Instanz von Bird() Initialisierung wie folgt:

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) 

Und das Problem war immer noch da! Wenn jemand erklären könnte, was vor sich geht/was ich falsch mache, und vielleicht sogar einen besseren Weg vorschlage, würde ich es begrüßen.

Nur für den Fall, dass Sie neugierig sind, muss ich Widgets direkt aus Python-Code hinzufügen, weil ich die App ständig eine neue Karte in einem konstanten Zeitintervall produzieren muss. Die erste Karte wird jedoch der Einfachheit halber in der Kivy-Datei initialisiert. Um fair zu sein, funktioniert es bis auf den Offset ziemlich gut. Und schließlich benutze ich kein Layout, weil ich nicht sicher war, welches ich verwenden soll ... Ich habe FloatLayout ein wenig in die Hand genommen, aber es schien nicht so, als würde es mein Problem irgendwie lösen.

Antwort

1

Bei der Erstellung hat Widget eine anfängliche Größe von (100, 100). Wenn Sie eine Größe aus dieser Änderung:

<Bird>: 
    size: 70, 80 

dazu:

<Bird>: 
    size: 100, 80 

Rechtecke korrekt auszurichten. Das anfängliche Rechteck, das in der kv-Datei erstellt wurde, ist im übergeordneten Fenster zentriert, andere, die in Python-Code erstellt wurden, sind nach links versetzt.

Wenn Sie Vogel Konstruktor in Python-Code ändern hieraus:

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

dazu (effektiv das Überschreiben der Standard-Widget Größe von (100, 100) sein (50,50)):

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

Sie werden feststellen, dass in Python-Code erstellte Rechtecke nach rechts verschoben werden. Ändern kv-Datei aus:

<Bird>: 
    size: 70, 80 

zu:

<Bird>: 
    size: 50, 80 

die Spiele (neu) Anfangs-Widget Größe (50,50) in der Breite, werden alle Rechtecke wieder ausgerichtet werden.

Lösung für Ihr Problem wäre alles wie es ist zu verlassen, außer size für neue Vögel in Python zu setzen in kv-Datei, dass gleich sein:

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

und alles wird wie vorgesehen.

Das alles bedeutet, dass size Eigenschaft aus kv-Datei nicht auf Ihre Python-Seite erstellt Vögel angewendet wird, nur auf die von kv-Deklaration erstellt. Ist das ein Kivy-Bug oder vielleicht fehlt noch ein Schritt im Python-Code, damit der Builder size von der kv-Datei auf Python-erzeugte Birds anwendet, habe ich momentan keine Ahnung.

Nach meiner Erfahrung, zu diesem Zeitpunkt der Kivy-Entwicklung, zu viel kv und Python-Code mischen wird in dieser Art von seltsamen Probleme, die Sie hier haben. Es ist am besten, entweder alle View-bezogenen Sachen in kv zu behandeln oder kv komplett zu verwerfen und alles in Python zu bauen.

Einige Dinge funktionieren überhaupt nicht in kv, d. H. Einstellung cols Eigenschaft von GridLayout (v1.9.1).

Persönlich, für den Moment, ich halte mich an gut organisiert Python-Code zum Erstellen von UI und verwenden Sie keine KV-Dateien fast überhaupt.

Hoffe, das hilft ein bisschen ...

+0

Vielen Dank. Ich benutzte einen Workaround, aber wenn ich das wüsste, hätte ich mir eine Menge Kopfschmerzen ersparen können. Auch dieser Teil über nicht zu viel Kivy und Python mischen - ich sehe das Problem gerade mit Popups. Ich hätte gerne diese ideale "Trennung" (kivy behandelt alle UI-Sachen, Python behandelt Logik), aber da ich Widgets dynamisch ziemlich oft hinzufüge, benutze ich am Ende mehr Python. Vielleicht sollte ich die Kivy-Datei komplett löschen. – spicypumpkin