Kivy AttributeError: 'NoneType' object has no attribute 'ids'

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Hat leider nicht geklappt
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Hallo
Ich mache die Benachrichtigung jezt einfach mit plyer, ich kann ja das mit pyjnius später noch ergänzen.

Ich habe aber gerade ein ganz anderes Problem: wenn man die app aktualisieren will gibt es einen ladebalken. Aber wenn man auf Start drückt dann aktualiesiert er sich nicht sondern wartet bis der Download fertig ist und steht dann auf 100%.

Hier nur ein kleines Beispiel Programm:

Code: Alles auswählen

from kivy.app import App
from kivy.lang import Builder
import urllib.request

g=Builder.load_string("""
BoxLayout:
	Button:
		on_press: app.dw()
	Label:
		id: lb
		text:"...%"
	ProgressBar:
		id: pb
		max: 100
		
		
		

""")



class myApp(App):
	def __init__(self):
		super().__init__()
	def build(self):
		return g
	def dw(self):
		urllib.request.urlretrieve("https://www.python.org/ftp/python/3.7.3/python-3.7.3-embed-amd64.zip","py.zip", self)
	def __call__(self, bn,bs,cl):
		percent=int((bn*bs)/cl*100)
		self.root.ids.lb.text=str(percent)+"%"
		self.root.ids.pb.value=percent
		
myApp().run()


Weder der ladebalken noch das Label aktualiesiert sich.

Was kann ich Dagegen tun?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Als erstes könntest Du ordentliche Variablennamen vergeben. Auch zweibuchstabige Namen sind nicht aussagekräftig. Ich habe große Probleme den Code zu verstehen, was wie sich den nun bm von bs oder lb von pb unterscheidet. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht Tabs, denn sonst kann es je Editoreinstellung zu unleserlichem Code kommen. Ein __init__ das nichts macht, als das super-__init__ aufzurufen, kann ganz weg.

Ich denke, wie bei jeder GUI muß man die Ausführung an die Hauptschleife zurückgeben, um eine Aktualisierung zu haben. Das tut aber urlretrieve nicht.
Was Du brauchst ist einen Hintergrundthread für den Download, eine Queue, die den Zustand an die GUI weitergibt, und einen Timer innerhalb der GUI, der die Aktualisierung vornimmt.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MupfSpace: Das darf halt nicht blockieren. Rückruffunktionen bei GUIs dürfen immer nur ganz kurz etwas machen, denn solange sie laufen ist die GUI blockiert. Du könntest das in einen Thread auslagern. Dann wirst Du aber sehr wahrscheinlich nicht einfach einen Callback verwenden können um die Werte in der GUI zu ändern, denn das darf man nur aus dem Thread heraus machen in dem die GUI läuft. Da musst Du dann schauen wie man so etwas in Kivy löst.

Anmerkungen zum Code: Die Namenskonventionen haben sich immer noch nicht geändert – `myApp` sollte mindestens `MyApp` heissen. Auch was Einrückung und Leerzeichensetzung hat sich nichts geändert.

Eine Methode die einfach nur die gleiche Methode auf der Basisklasse mit den gleichen Argumenten aufruft ist überflüssig. Weg mit `__init__()`.

Warum ein Objekt das eine Anwendung repräsentiert aufrufbar sein sollte, und dieser Aufruf dann ausgerechnet einen Ladebalken aktualisiert, ist so gar nicht offensichtlich. Da würde man wirklich besser eine Methode mit einem aussagekräftigen Namen für verwenden. Apropos aussagekräftige Namen: `bn`, `bs`, `cl`, `lb`, `pb` sind das sicher nicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Also warum bringt im __init__: super().__init__() nichts allein durch diese Teile wurde der ids Fehler behoben.

Ich habe den Code jezt noch mal besser gemacht:

Code: Alles auswählen


from kivy.app import App
from kivy.lang import Builder
import urllib.request

g=Builder.load_string("""
BoxLayout:
    Button:
        on_press: app.start_download()
    Label:
        id: info_label
        text:"...%"
    ProgressBar:
        id: progress_bar
        max: 100
        
        
        

""")



class MyApp(App):
    def download(self, block_num, block_size, content_length):
        percent=int((block_num*block_size)/content_length*100)
        self.root.ids.info_label.text=str(percent)+"%"
        self.root.ids.progress_bar.value=percent
    def build(self):
        return g
    def start_download(self):
        urllib.request.urlretrieve("https://www.python.org/ftp/python/3.7.3/python-3.7.3-embed-amd64.zip","py.zip", self.download)


        
MyApp().run()
Okay. Wie genau behebe ich jezt den Fehler mit dem lade Balken.

Ich habe schon verschiedenes versucht und es hat nicht funktioniert. Im Internet habe ich auch nichts gefunden.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du suchst den `kivy.clock.mainthread`-Dekorator mit dem man die Ausführung der Rückruffunktion in den Hauptthread verlegen kann.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

so passiert genau das gleiche wie vorher trotz kivy.clock.mainthread:

Code: Alles auswählen

from kivy.app import App
from kivy.lang import Builder
from kivy.clock import mainthread
import urllib.request

g=Builder.load_string("""
BoxLayout:
    orientation:"vertical"
    BoxLayout:
        Label:
            text:"..%"
            id: info_label
        ProgressBar:
            id: progress_bar
            max: 100
    Button:
        on_press: app.start()



""")

class MyApp(App):
    def build(self):
        return g
    def start(self):
        urllib.request.urlretrieve("https://www.python.org/ftp/python/3.7.3/python-3.7.3.exe","download.iregndwas", self.download)
    @mainthread
    def download(self, block_num,block_size,content_length):
        percent=int((block_num*block_size)/content_length*100)
        self.root.ids.info_label.text=str(percent)
        self.root.ids.progress_bar.value=percent
        print(percent)

MyApp().run()
        

in der Dokumentation habe ich gelesen das ich mit UrlRequest arbeiten soll, aber da steht nur was von on_succes aber der Ladebanken soll ja nicht wenn es geklappt hat aktualisiert werden sondern während des Downloads.

welcher Fehler befindet sich in meinem Code?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MupfSpace: Der Fehler ist immer noch das `urlretrieve()` alles blockiert bis der Download komplett ist. Der Callback ist jetzt thread-sicher, nun müsstest Du halt noch einen Thread für das herunterladen starten.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Mit threading?
Ich dachte man soll keinen Thread in gui Anwendungen erstellen?
Oder doch?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Jein. Du darfst aus dem Thread keine GUI Objekte manipulieren. Aber ein Thread kann seine Ergebnisse (wie zb den Fortschritt) eben an den mainthread kommunizieren. Kivy kennt dafür wohl diesen decorator, so das du die Methode auch aus einem anderen Thread aufrufen kannst.
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

So passiert überhaupt gar nichts und ich bekomme noch nicht mal den print...

Code: Alles auswählen

from kivy.app import App
from kivy.lang import Builder
from kivy.clock import mainthread
import urllib.request
import threading

g=Builder.load_string("""
BoxLayout:
    orientation:"vertical"
    BoxLayout:
        Label:
            text:"..%"
            id: info_label
        ProgressBar:
            id: progress_bar
            max: 100
    Button:
        on_press: app.start()



""")

class MyApp(App):
    def build(self):
        return g
    def start(self):
        threading.Thread(target=urllib.request.urlretrieve,args=("https://www.python.org/ftp/python/3.7.3/python-3.7.3.exe","download.iregndwas", self.download))
    @mainthread
    def download(self, block_num,block_size,content_length):
        percent=int((block_num*block_size)/content_length*100)
        self.root.ids.info_label.text=str(percent)
        self.root.ids.progress_bar.value=percent
        print(percent)

MyApp().run()
        
Warum ist das so und wie kann ich das beheben?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Threads sollte man auch starten.
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Ups stimmt :oops:
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

So jezt klappt es.

Aber mich würde immer noch interessieren warum das mit dem super().__init__() weg.

Das hat doch den ids Fehler behoben.
Oder nicht?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MupfSpace: Einfach nur in einer Methode die Methode der Basisklasse aufzurufen, mit den gleichen Argumenten, hat keinen Mehrwert. Da passiert vom Effekt her genau das gleiche als wenn es die Methode nicht gäbe, denn dann wird ja beim Aufruf der Methode die aus der Basisklasse genommen. Man hat mit der Methode halt bloss einen Aufruf mehr in der Aufrufhierarchie der aber nichts zusätzliches macht. Also kann man das auch weg lassen. Und sollte man halt auch, denn sonst fragt sich der Leser warum das da steht und ob das Programm an der Stelle fertig ist und nicht noch irgend etwas fehlt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Ich wollte gerade versuchen eine Test-App mit buildozer zu einer apk zu machen.
nach dem ich

Code: Alles auswählen

buildozer android debug deploy run
eingegebn habe

hat es eine weile gedauert und ich bekam diesen fehler

Code: Alles auswählen


adrian@adrian-desktop:~$ cd TestApp
adrian@adrian-desktop:~/TestApp$ buildozer android debug deploy run
# Check configuration tokens
# Ensure build layout
# Create directory /home/adrian/.buildozer
# Create directory /home/adrian/.buildozer/cache
# Create directory /home/adrian/TestApp/.buildozer
# Create directory /home/adrian/TestApp/bin
# Create directory /home/adrian/TestApp/.buildozer/applibs
# Create directory /home/adrian/.buildozer/android/platform/android/platform
# Create directory /home/adrian/TestApp/.buildozer/android/platform
# Create directory /home/adrian/TestApp/.buildozer/android/app
# Check configuration tokens
# Read available permissions from api-versions.xml
# Preparing build
# Check requirements for android
# Run 'dpkg --version'
# Cwd None
Debian »dpkg« Paketmanagement-Programm Version 1.19.0.5 (armhf).
Dies ist freie Software; lesen Sie die GNU General Public License in der
Version 2 oder höher für Kopierbedingungen. Es wird KEINE Haftung übernommen.
# Search for Git (git)
#  -> found at /usr/bin/git
# Search for Cython (cython)
#  -> found at /home/adrian/.local/bin/cython
# Search for Java compiler (javac)
#  -> found at /usr/lib/jvm/java-11-openjdk-armhf/bin/javac
# Search for Java keytool (keytool)
#  -> found at /usr/lib/jvm/java-11-openjdk-armhf/bin/keytool
# Install platform
# Run 'git clone -b master --single-branch https://github.com/kivy/python-for-android.git python-for-android'
# Cwd /home/adrian/TestApp/.buildozer/android/platform
Cloning into 'python-for-android'...
# Run '/usr/bin/python -m pip install -q --user \'appdirs\' \'colorama>=0.3.3\' \'jinja2\' \'six\' \'enum34; python_version<"3.4"\' \'sh>=1.10; sys_platform!="nt"\' \'pep517\' \'pytoml\' \'virtualenv\''
# Cwd None
# Android ANT is missing, downloading
# Downloading http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.4-bin.tar.gz
# Run 'tar xzf apache-ant-1.9.4-bin.tar.gz'
# Cwd /home/adrian/.buildozer/android/platform/apache-ant-1.9.4
# Apache ANT installation done.
# Android SDK is missing, downloading
# Downloading http://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
# Unpacking Android SDK
# Run 'unzip -q /home/adrian/.buildozer/android/platform/android-sdk/sdk-tools-linux-4333796.zip'
# Cwd /home/adrian/.buildozer/android/platform/android-sdk
# Android SDK tools base installation done.
# Android NDK is missing, downloading
# Downloading https://dl.google.com/android/repository/android-ndk-r17c-linux-x86.zip
# Unpacking Android NDK
# Run 'unzip -q /home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip'
# Cwd /home/adrian/.buildozer/android/platform
[/home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip]
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip or
        /home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip.zip, and cannot find /home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip.ZIP, period.
# Command failed: unzip -q /home/adrian/.buildozer/android/platform/android-ndk-r17c-linux-x86.zip
# ENVIRONMENT:
#     MATE_DESKTOP_SESSION_ID = 'this-is-deprecated'
#     XDG_GREETER_DATA_DIR = '/var/lib/lightdm-data/adrian'
#     XDG_CURRENT_DESKTOP = 'MATE'
#     XDG_SESSION_TYPE = 'x11'
#     LOGNAME = 'adrian'
#     USER = 'adrian'
#     PATH = '/home/adrian/.buildozer/android/platform/apache-ant-1.9.4/bin:/home/adrian/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'
#     XDG_VTNR = '7'
#     HOME = '/home/adrian'
#     DISPLAY = ':0'
#     SSH_AGENT_PID = '1614'
#     LANG = 'de_DE.UTF-8'
#     MANAGERPID = '1166'
#     SHELL = '/bin/bash'
#     XDG_SESSION_PATH = '/org/freedesktop/DisplayManager/Session0'
#     XAUTHORITY = '/home/adrian/.Xauthority'
#     JOURNAL_STREAM = '9:33972'
#     SESSION_MANAGER = 'local/adrian-desktop:@/tmp/.ICE-unix/1188,unix/adrian-desktop:/tmp/.ICE-unix/1188'
#     XDG_DATA_DIRS = '/usr/share/mate:/usr/local/share:/usr/share:/var/lib/snapd/desktop'
#     QT_QPA_PLATFORMTHEME = 'gtk2'
#     QT_ACCESSIBILITY = '1'
#     WINDOWID = '52428806'
#     GTK_OVERLAY_SCROLLING = '0'
#     IM_CONFIG_PHASE = '1'
#     GPG_AGENT_INFO = '/run/user/1000/gnupg/S.gpg-agent:0:1'
#     QT_AUTO_SCREEN_SCALE_FACTOR = '0'
#     INVOCATION_ID = '4975065039d84d9f84f6efe8716def4f'
#     XDG_SESSION_DESKTOP = 'mate'
#     XDG_RUNTIME_DIR = '/run/user/1000'
#     QT_SCALE_FACTOR = '1'
#     SSH_AUTH_SOCK = '/run/user/1000/keyring/ssh'
#     TERM = 'xterm'
#     VTE_VERSION = '5202'
#     GDMSESSION = 'mate'
#     XDG_SEAT_PATH = '/org/freedesktop/DisplayManager/Seat0'
#     DBUS_STARTER_BUS_TYPE = 'session'
#     LESSOPEN = '| /usr/bin/lesspipe %s'
#     XDG_SESSION_ID = 'c2'
#     DBUS_SESSION_BUS_ADDRESS = 'unix:path=/run/user/1000/bus,guid=1de859e84ac47caa38b0d51c5cf179cd'
#     _ = '/usr/local/bin/buildozer'
#     DESKTOP_SESSION = 'mate'
#     LESSCLOSE = '/usr/bin/lesspipe %s %s'
#     GTK_MODULES = 'appmenu-gtk-module:gail:atk-bridge:canberra-gtk-module'
#     UBUNTU_MENUPROXY = '1'
#     OLDPWD = '/home/adrian'
#     DBUS_STARTER_ADDRESS = 'unix:path=/run/user/1000/bus,guid=1de859e84ac47caa38b0d51c5cf179cd'
#     GDM_LANG = 'de_DE'
#     LANGUAGE = 'de_DE'
#     SHLVL = '1'
#     PWD = '/home/adrian/TestApp'
#     COLORTERM = 'truecolor'
#     XDG_CONFIG_DIRS = '/etc/xdg/xdg-mate:/etc/xdg'
#     LS_COLORS = 'rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:'
#     XDG_SEAT = 'seat0'
# 
# Buildozer failed to execute the last command
# The error might be hidden in the log above this error
# Please read the full log, and search for it before
# raising an issue with buildozer itself.
# In case of a bug report, please add a full log with log_level = 2
adrian@adrian-desktop:~/TestApp$ 


was kann ich dagegen tun?
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Wie kann ich diesen Fehler beheben?
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

@MupfSpace: was hat das mit dem eigentlichen Thema zu tun?

unzip meldet den Fehler im Logfile.
When we say computer, we mean the electronic computer.
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Ja das hab ich bemerkt.
Die datei gibt's nicht.
Wie kann ich die richtige runterladen?
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Hast du schon einmal versucht danach zu googeln?
Es gibt nur 2 Treffer, wenn man nach dem Dateinamen such. Diesen Beitrag im Forum und eine Diskussion in eine Google-Gruppe. Dort stellt sich heraus: Die gesucht Datei existiert nicht, weil buildozer nicht auf 32-bit Systemen bauen kann.
Falls du also ein 32-bit Linux installiert hast, geht es nicht.
Antworten