Kivy - Methoden unbekannt, Installation fehlerhaft?

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Emanuel
User
Beiträge: 7
Registriert: Donnerstag 22. August 2019, 22:35
Wohnort: Herzogenrath
Kontaktdaten:

Liebe Community,

eben bin ich neu zu euch gestoßen und bin gespannt dieses Forum kennenzulernen.

Kurz zu mir: Ich möchte mit Python und Kivy meinen Horizont erweitern und eine einfache grafische Anwendung schreiben. Beides kenne ich bisher noch nicht und versuche es seit einem guten Monat mit Tutorials zu erlernen. Generell kann ich aber programmieren, hauptsächlich (weil beruflich) in C. Objektorientierte Programmierung verstehe ich zumindest grundlegend und habe es bereits mit Java angewendet.

Meine ersten Versuche mit Python und Kivy machen Spaß und die Oberflächen mit Wechselscreens usw. funktionieren (ScreenManager, …). Ich bin motiviert, schnell weiterzukommen.

Nun bemerke ich aber, dass Kivy einige Methoden der Objekte aus den Bibliotheken nicht zu kennen scheint und frage mich, ob die Installation irgendwie fehlerhaft ist. Im Internet verfügbare Beispiele kann ich bei mir darum nicht nachvollziehen.

Hier ein ausgedünntes Minimalbeispiel von mir:

main.py

Code: Alles auswählen

import kivy
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
kivy.require('1.11.1')  # replace with your current kivy version !


class ScreenManagerMain(ScreenManager):
	pass


class ScreenMenu(Screen):
	pass


class ScreenIntro(Screen):
	pass
'''
	def __init__(self, **kwargs):
		super(ScreenIntro, self).__init__(**kwargs)

	def on_enter(self, *args):
		print("on Enter")
		Clock.schedule_once(self.change_screen_to_menu(), 3)

	def change_screen_to_menu(self, *args):
		print('to menu')
		self.manager.current = 'screen_menu'
'''

class TestApp(App):
	title = 'Test'

	def build(self):
		screen_mgr_main = ScreenManagerMain()
		return screen_mgr_main


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

test.kv

Code: Alles auswählen

#:kivy 1.11.1
#:import RiseInTransition kivy.uix.screenmanager.RiseInTransition

<ScreenManagerMain>:
    name: 'screen_manager_main'
    transition: RiseInTransition()
    ScreenIntro:
    ScreenMenu:

<ScreenIntro>:
    name: 'screen_intro'

    Button:
        text: 'B1'
        size_hint: None,None
        size: 100,100
        pos: 0,0
        on_press: root.manager.current = 'screen_menu'

<ScreenMenu>:
    name: 'screen_menu'

    Button:
        text: 'B2'
        size_hint: None,None
        size: 100,100
        pos: 300,0
        on_press: root.manager.current = 'screen_intro'
Lässt man zunächst den in main.py auskommentierten Code weg, erscheint folgende Ausgabe in der Konsole, während die Anwendung mit dem Fenster funktioniert:

Code: Alles auswählen

/home/ned/.virtualenvs/kivyinstall/bin/python /home/ned/Projekte/Carrera-Controller/Software/Entwicklung/main.py
[INFO   ] [Logger      ] Record log in /home/ned/.kivy/logs/kivy_19-08-23_2.txt
[INFO   ] [Kivy        ] v1.11.1
[INFO   ] [Kivy        ] Installed at "/home/ned/.virtualenvs/kivyinstall/lib/python3.7/site-packages/kivy/__init__.py"
[INFO   ] [Python      ] v3.7.3 (default, Nov 10 2011, 15:00:00) 
[GCC 8.3.0]
[INFO   ] [Python      ] Interpreter at "/home/ned/.virtualenvs/kivyinstall/bin/python"
[INFO   ] [Factory     ] 184 symbols loaded
[INFO   ] [ImageLoaderFFPy] Using ffpyplayer 4.2.0
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2, img_ffpyplayer, img_gif (img_pil ignored)
[ERROR  ] [Input       ] MTDev is not supported by your version of linux
Traceback (most recent call last):
  File "/home/ned/.virtualenvs/kivyinstall/lib/python3.7/site-packages/kivy/input/providers/__init__.py", line 41, in <module>
    import kivy.input.providers.mtdev
  File "/home/ned/.virtualenvs/kivyinstall/lib/python3.7/site-packages/kivy/input/providers/mtdev.py", line 84, in <module>
    from kivy.lib.mtdev import Device, \
  File "/home/ned/.virtualenvs/kivyinstall/lib/python3.7/site-packages/kivy/lib/mtdev.py", line 28, in <module>
    libmtdev = cdll.LoadLibrary('libmtdev.so.1')
  File "/usr/lib/python3.7/ctypes/__init__.py", line 434, in LoadLibrary
    return self._dlltype(name)
  File "/usr/lib/python3.7/ctypes/__init__.py", line 356, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: libmtdev.so.1: cannot open shared object file: No such file or directory
[INFO   ] [Window      ] Provider: sdl2(['window_egl_rpi'] ignored)
[INFO   ] [Window      ] Provider: x11(['window_egl_rpi', 'window_sdl2'] ignored)
FBConfig selected:
Doublebuffer: Yes
Red Bits: 8, Green Bits: 8, Blue Bits: 8, Alpha Bits: 8, Depth Bits: 24
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] Backend used <gl>
[INFO   ] [GL          ] OpenGL version <b'3.1 Mesa 19.1.2'>
[INFO   ] [GL          ] OpenGL vendor <b'X.Org'>
[INFO   ] [GL          ] OpenGL renderer <b'AMD TURKS (DRM 2.50.0 / 4.15.0-58-generic, LLVM 7.0.1)'>
[INFO   ] [GL          ] OpenGL parsed version: 3, 1
[INFO   ] [GL          ] Shading version <b'1.40'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <16>
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [Base        ] Leaving application in progress...

Process finished with exit code 0
Hier hapert es wohl an MTDev, dabei will ich MultiTouch gar nicht verwenden. In der entsprechenden Bibliotheksdatei (kivy/input/providers/__init__) sehe ich jedoch, dass die Ausgabe mit der Betriebssystemunterstützung eine pauschale Fehlermeldung auf jegliche import-Probleme ist:

Code: Alles auswählen

    try:
        import kivy.input.providers.mtdev
    except:
        err = 'Input: MTDev is not supported by your version of linux'
        Logger.exception(err)
Von meinem Linux-System wird MTDev prinzipiell unterstützt und es ist bereits installiert.

Wenn ich den auskommentierten Code aus main.py einfüge (dafür 'pass' oberhalb entferne), sehe ich, dass die Methode schedule_once des Objekts Clock (Zeile 26) nicht existiert. Ebenso das Attribut current von self.manager.current (Zeile 30). Clock wird jedoch per Autovervollständigung angeboten, sowie auch self.manager. Die Anwendung läuft so natürlich nicht. Wie kann das sein, dass die Clock-Bibliothek eingebunden ist, die Klasse von Clock scheinbar bekannt ist, aber die Methoden fehlen?

Und noch meine Umgebung:
Linux Mint 18.3 64-bit, Linux Kernel 4.15.0-58-generic
PyCharm Community 2019.2
Python 3.7
Kivy 1.11.1
Im Screenshot noch die installierten Module.
Bild

Für jegliche Ideen dazu bin ich sehr dankbar!
Lieben Gruß,
Emanuel
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich kann das Problem nicht nachvollziehen, beziehungsweise bekomme ich eine andere Fehlermeldung, nämlich das es keinen Screen mit dem Namen "screen_menu" gibt. Den gibt es zu dem Zeitpunkt wo Du darauf versuchst zuzugreifen auch tatsächlich noch nicht. Der Fehler im Programm ist, dass Du `self.change_screen_to_menu` *aufrufst* und das *Ergebnis* an `Clock.schedule_once()` übergibst, statt die Methode zu übergeben und das `Clock` *später* aufrufen zu lassen. Wenn ich die Klammern für den Aufruf entferne, dann funktioniert das bei mir.

Eingerückt wird Python übrigens vier Leerzeichen pro Ebene und *nicht* mit Tabs. Wenn das mit PyCharm geschrieben ist, müsstest Du da ja selbst in den Einstellungen den Standard auf Tabs umgestellt haben‽

Und literale Zeichenketten sind nicht dazu gedacht Code auszukommentieren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

In der Fehlermeldung wird eine dynamische Bibliothek erwähnt, die nicht gefunden wird. Hast du überprüft ob die auf deinem System vorhanden ist?
Emanuel
User
Beiträge: 7
Registriert: Donnerstag 22. August 2019, 22:35
Wohnort: Herzogenrath
Kontaktdaten:

__blackjack__ hat geschrieben: Samstag 24. August 2019, 13:15 nämlich das es keinen Screen mit dem Namen "screen_menu" gibt. Den gibt es zu dem Zeitpunkt wo Du darauf versuchst zuzugreifen auch tatsächlich noch nicht.
Warum gibt es den nicht? TestApp() erzeugt doch nach meinem Verständnis zuerst den ScreenManager, der wiederum die Screens und die on_enter()-Methode des einen Screens wird doch erst später aufgerufen. Oder liege ich falsch?
__blackjack__ hat geschrieben: Samstag 24. August 2019, 13:15 Wenn ich die Klammern für den Aufruf entferne, dann funktioniert das bei mir.
Da hast du natürlich Recht. Ich habe gepennt.
__deets__ hat geschrieben: Samstag 24. August 2019, 13:25 In der Fehlermeldung wird eine dynamische Bibliothek erwähnt, die nicht gefunden wird. Hast du überprüft ob die auf deinem System vorhanden ist?
Ja, laut ubuntu.pkgs.org/… ist sie Bestandteil des Pakets libmtdev1. Das ist bei mir installiert. Die Datei "/usr/lib/x86_64-linux-gnu/libmtdev.so.1" ist auch vorhanden, bzw. es ist ein Link auf "/usr/lib/x86_64-linux-gnu/libmtdev.so.1.0.0" und diese Datei existiert ebenfalls.
Bild

Grundsätzlich bleibt das Problem, dass z.B. das Clock-Objekt scheinbar ein leeres Standardobjekt ist, aber nicht von der Klasse aus der entsprechenden Bibliothek erzeugt wird. Hier die verfügbaren Attribute und Methoden. Da fehlt alles spezifische von Clock.
Bild

Zusammenfassung: Kivy findet wohl MTDev nicht, als auch die Clock-Bibliothek, obwohl beides da ist. Daraufhin fragte ich mich, ob die Installation irgendwie unvollständig ist oder ich einen Konfigurationsschritt unterschlagen habe. Andererseits funktionieren ja ScreenManager und Co, zumindest ein bisschen. Im Programm kann ich allerdings nicht das current-Attribut des ScreenManagers abfragen, wie im ersten Post erwähnt.


Nebensächlichkeiten:
__blackjack__ hat geschrieben: Samstag 24. August 2019, 13:15 Eingerückt wird Python übrigens vier Leerzeichen pro Ebene und *nicht* mit Tabs.
Aus welcher Quelle hast du das? Ich habe nach dem Tutorial bei techbeamers.com/… gelernt und das sagte in der ersten Lektion:
In Python, indentation replaces brackets to group a block of instructions. And you can use either tabs or spaces to indent the code.

However, Python enforces some rules (PEP 8) such as to use four spaces per indentation level.
Weiterhin steht in python.org/…:
Spaces are the preferred indentation method.

Tabs should be used solely to remain consistent with code that is already indented with tabs.

Python 3 disallows mixing the use of tabs and spaces for indentation.
Wenn die gemischte Verwendung von Tabs und Spaces verboten ist, entnehme ich, dass Tabs nicht verboten sind. Spaces sind allerdings bevorzugt.
Ich bin ein Freund von Tabs (der Länge 4 Spaces) und hatte die deshalb verwendet. Vielleicht sollte ich mich umgewöhnen?!?
__blackjack__ hat geschrieben: Samstag 24. August 2019, 13:15 Und literale Zeichenketten sind nicht dazu gedacht Code auszukommentieren.
Oh, das hatte ich irgendwo gesehen und als Blockkommentar missinterpretiert. Gibt es entsprechende Zeichen dafür oder muss ich je Zeile ein '#' voranstellen?
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Emanuel: Keine Ahnung warum der Screen noch nicht existiert, ich vermute mal weil er zu dem Zeitpunkt an dem Du die Methode aufgerufen hast, noch nicht erstellt wurde. Das macht ja aber in der `on_enter()`-Methode sowieso nicht so viel Sinn und Du willst das zu dem Zeitpunkt ja auch gar nicht machen.

Terminalausgaben muss man nicht wirklich als Bild posten, da kann man doch einfach den Text kopieren.

Gibt es `Clock.schedule_one()` tatsächlich nicht wenn Du das Programm laufen lässt, oder fehlt Dir das bloss in der Autovervollständigung in der IDE? Letzeres heisst ja nicht das es das *nicht* gibt, nur das die IDE das bei iherer *statischen* Analyse nicht finden konnte. Das gilt selbst wenn die IDE Namen als nicht vorhanden anmeckert – das kann auch einfach nur bedeuten, dass sie die Namen nicht gefunden hat. Die können zur *Laufzeit* dann trotzdem existieren. Dynamische Programmiersprache halt.

Im Tutorial steht „Python enforces some rules“, auch wenn das natürlich nicht wirklich hart durchgesetzt wird, und auf Python.org der Satz „Tabs should be used solely to remain consistent with code that is already indented with tabs.“ schliesst für mich Tabs aus, denn Du fängst da ja *neuen* Code an und entwickelst keinen weiter der bereits Tabs verwendet.

Für einen Blockkommentar musst Du je Zeile ein ``#`` davorstellen, allerdings musst Du das ja nicht wirklich selbst in jeder Zeile machen – wenn der Editor/die IDE da kein Tastenkürzel bietet um markierte Zeilen aus- oder einzukommentieren, sollte man Editor oder IDE wechseln.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Emanuel
User
Beiträge: 7
Registriert: Donnerstag 22. August 2019, 22:35
Wohnort: Herzogenrath
Kontaktdaten:

__blackjack__ hat geschrieben: Samstag 24. August 2019, 14:43 Gibt es `Clock.schedule_one()` tatsächlich nicht wenn Du das Programm laufen lässt, oder fehlt Dir das bloss in der Autovervollständigung in der IDE?
Oh, du hast recht. Nachdem ich das Testprogramm ein bisschen umgebaut habe, funktioniert Clock.schedule_once(), sowie auch die anderen "unbekannten". Die IDE kennt sie weiterhin nicht. Schade, wenn man nicht alles im Scope angezeigt bekommt (zumindest für mich als Anfänger). Im Fall von schedule_once() handelt es sich um eine C-Funktion, die mit cpdef erstellt ist. Sollte doch für eine IDE kein Ding der Unmöglichkeit sein, wenigstens den Funktionsprototyp zu verstehen, oder? Die Funktionen selbst sind bereits kompiliert, da kommt die IDE also nicht mehr dran, aber die Prototypen liegen als Sourcen vor. Gibt es andere IDEs, die das können?


Somit bleibt noch das MTDev-Problem übrig. Vielleicht muss ich das aber gar nicht lösen, da meine Anwendung ja funktioniert und mein Entwicklungssystem ohnehin nicht das Zielsystem ist. Das soll später auf einem Raspberry Pi ablaufen.


Btw, da habe ich auch gefunden, woher ich das mit den Blockkommentaren in '''-Zeichen hatte. Das wird in den kivy-Bibliotheken so gemacht. Kleiner Auszug aus kivy/clock.py:

Code: Alles auswählen

    def tick_draw(self):
        '''Tick the drawing counter.
        '''
        self._process_events_before_frame()
        self._rfps_counter += 1
        self._frames_displayed += 1

    def get_fps(self):
        '''Get the current average FPS calculated by the clock.
        '''
        return self._fps

    def get_rfps(self):
        '''Get the current "real" FPS calculated by the clock.
        This counter reflects the real framerate displayed on the screen.

        In contrast to get_fps(), this function returns a counter of the
        number of frames, not the average of frames per second.
        '''
        return self._rfps

    def get_time(self):
        '''Get the last tick made by the clock.'''
        return self._last_tick
Vielen Dank, insbesondere an __blackjack__.
Emanuel
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sind aber keine Blockkommentare. Sondern doc-strings zur Dokumentation. Etwas sehr anderes.
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Emanuel: ``cpdef`` ist ja kein Python, das ist Cython. Klar, könnte die IDE vielleicht auch statisch analysieren, aber bei dynamisch typisierten Sprachen muss man sich einfach damit abfinden, dass statische Analyse da nicht 100%ig geht und sogar falsche Ergebnisse liefern kann.

Das gezeigte sind keine Blockkommentare sondern Docstrings und das gehört zur Python-Syntax. Das sind keine Kommentare die weggeworfen werden, sondern diese Informationen werden an die jeweiligen Objekte (Modul, Funktion, Klasse, Methode) gebunden und stehen zur Laufzeit zur Verfügung:

Code: Alles auswählen

In [229]: print(kivy.clock.ClockBaseBehavior.get_rfps.__doc__)                  
Get the current "real" FPS calculated by the clock.
        This counter reflects the real framerate displayed on the screen.

        In contrast to get_fps(), this function returns a counter of the
        number of frames, not the average of frames per second.
Und wenn Du mal in die Dokumentation schaust, siehst Du, dass dort exakt die gleichen Texte stehen, weil Dokumentationswerkzeuge die Informationen dort auch heraus ziehen: https://kivy.org/doc/stable/api-kivy.cl ... or.get_fps
Der Docstring direkt vom Modul ist wesentlich umfangreicher, da sieht man dann auch reStructuredText als Auszeichnungssprache ganz gut. Und das PDF, welches man oben auf der Seite über den PDF-Button erreicht, ist auch aus diesen Quellen entstanden.

Das Werkzeug was dafür verwendet wird ist http://www.sphinx-doc.org und damit wird auch die Python-Dokumentation erstellt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Emanuel
User
Beiträge: 7
Registriert: Donnerstag 22. August 2019, 22:35
Wohnort: Herzogenrath
Kontaktdaten:

Danke euch für die Informationen. Ich sauge alles auf ;)

Ich habe noch nicht annähernd die ganze Python-Syntax erschlossen und bei weitem nicht die Möglichkeiten damit. Aber ich muss wohl erstmal praktisch anfangen, denn wenn ich Tutorials einfach lese, erfasse ich vieles nicht mit dem Langzeitgedächtnis. So kommt es, dass ich hier wie ein Idiot über solche Dinge stolpere, weil ich schon ausprobiere, ohne vorher alles kennengelernt zu haben.

In C verwende ich Doxygen. Vermutlich sind die Docstrings etwas entsprechendes. Muss ich alles noch erschließen.

Danke für eure Geduld!
Antworten