Bild bei aktivem GTK ändern.

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Antworten
steffenrohwer
User
Beiträge: 8
Registriert: Montag 4. Februar 2019, 19:00

Sonntag 13. Oktober 2019, 10:35

Hallo Leute!

In diesem Forum wurde mir schonmal bei einem Problem mit Python und GTK geholfen... das betreffende Programm ist nun auch fast fertig :D Auch der Teamstand, in den das Programm integriert wird nimmt langsam Form an aber jetzt sitze ich an dem letzten Problem... :?:

Zuerst wollte ich in meinem Programm immer eine Interface schließen und ein anderes öffnen... die Performance lässt aber zu wünschen übrig und deshalb habe ich mir nun überlegt zu beginn ein Interface zu öffnen und ein GTK.image auszutauschen. Dafür habe ich mich an diesem Thread bei Stackoverflow orientiert: https://stackoverflow.com/questions/442 ... ython3-gtk

Nun habe ich folgendes Programm, aber es bleibt nur das bild geladen das ich in glade auswähle ...: :?

Code: Alles auswählen

from datetime import datetime
import time
import binascii
import socket
import signal
import sys
import argparse

import Adafruit_PN532 as PN532
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
from neopixel import *

# Pins NFC Modul
CS   = 18
MOSI = 23
MISO = 24
SCLK = 25

# Karten fuer NFC definieren
karten = {
    "hauptmenue": "hauptmenue",
    "112": "finalrs",
    "111": "v1"
}

...

GLADEFILE = "/home/pi/Desktop/InterfacesRS/hauptmenue.glade"

# Karten Typ (Mifare)
CARD_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]

class MainWindow(Gtk.Window):
    letzter_tag = ""

    def __init__(self, sensor, led):
        global letzter_tag
        self.pn532 = sensor
        self.statusLED = led
        self.window = None
        letzter_tag = "hauptmenue"
        self.builder = Gtk.Builder()
        self.builder.add_from_file(GLADEFILE)
        self.window = self.builder.get_object("window1")
        self.interfaceImg = self.builder.get_object("image1")
        self.interfaceImg.set_from_file = "/home/pi/Desktop/InterfacesRS/menu.png"
        self.window.show_all()
        print("window intialized")

    def changewindow(self, part):
        # change picture
        print("anderung")
        self.interfaceImg.set_from_file = "/home/pi/Desktop/InterfacesRS/v1"
        print("rendered")
        #self.interfaceImg.show()

    ...

        def sensorabfrage(self):
        uid = self.pn532.read_passive_target()
        if uid is None:
            if self.letzter_tag is not "hauptmenue":
                self.letzter_tag = "hauptmenue"
                print("Kein Tag in Reichweite!")
                self.changecolor(Color(84, 0, 173))
                self.changewindow(part="hauptmenue")
        else:
            if not self.pn532.mifare_classic_authenticate_block(uid, 4, PN532.MIFARE_CMD_AUTH_B,
                                                   CARD_KEY):
                print('Kartenfehler')
                self.fehler()
            data = self.pn532.mifare_classic_read_block(4)
            if data is not  None:
                action = str(int(data[2:8].decode("utf-8"), 16))
                objekt = karten.get(action)
                if objekt != self.letzter_tag:
                    self.letzter_tag = objekt
                    print(objekt)
                    self.changecolor(Color(255, 0, 0)) # LED gruen
                    self.changewindow(part=objekt)
        return True

    def startsensortimer(self):
        GObject.timeout_add(300, self.sensorabfrage)

def main():
    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO)
    pn532.begin()
    pn532.SAM_configuration()
    
    strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
    strip.begin()
    
    win = MainWindow(sensor=pn532, led=strip)
    win.startsensortimer()
    Gtk.main()

if __name__ == "__main__":
    main()
LG
Steffen :geek:
Benutzeravatar
__blackjack__
User
Beiträge: 4467
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 13. Oktober 2019, 10:41

@steffenrohwer: Auf StackOverflow ist es ja noch richtig. Musst Du halt auch so machen. Tipp: ``print = "Hallo"`` wird nichts ausgeben, weil das nicht das gleiche ist wie ``print("Hallo")``.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
Benutzeravatar
__blackjack__
User
Beiträge: 4467
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 13. Oktober 2019, 11:13

@steffenrohwer: Vergiss bitte ``global`` sofort wieder. Und auf der Klasse hat `letzter_tag` auch nichts zu suchen.

Zeichenketten mit ``is``/``is not`` vergleichen ist ein Fehler! Das kann funktionieren, muss es aber nicht. Du willst nicht wissen ob es sich um das *selbe* Objekt handelt, sondern nur ob die beiden Objekte (un)gleich sind.

Anstelle eines speziellen Zeichenkettenwertes würde sich hier eventuell auch einfach `None` für das Hauptmenü anbieten. Und warum Du die Zahlen von den Karten in Zeichenketten umwandelst ist mir nicht wirklich klar.

Namen schreibt man in Python klein_mit_unterstrichen. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Also `status_led` anstelle von `statusLED`, `interface_img` anstelle von `interfaceImg` und so weiter. Ausserdem sollte man kryptische Abkürzungen vermeiden. `interface_img` sollte also `interface_image` heissen. Zwischen Worte gehören Unterstriche — `startsensortimer` istschwererlesbaralsesseinmüsste.

`self.window` an `None` zu binden ist überflüssig wenn man es gleich ein paar Zeilen später an einen anderen Wert bindet, ohne dass das `None` jemals für irgendetwas benutzt wurde.

Wenn der `Builder` nicht ausserhalb der `__init__()` verwendet wird, sollte er auch nicht an das Objekt gebunden werden. Dann ist das einfach ein lokaler Wert.

Auch in externen Daten wie der Glade-Datei sollte man aussagekräftige Namen für Daten/Objekte verwenden und nicht irgendwelche generischen, durchnummerierten.

Man sollte keine Daten im Quelltext wiederholen. Den Basispfad zu den Daten sollte man beispielsweise nur einmal im Quelltext stehen haben, als Konstante.

Bei einem Kartenfehler wird danach trotzdem die Karte ausgelesen/ausgewertet? Das sieht falsch aus.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import argparse
import binascii
from datetime import datetime
from pathlib import Path
import signal
import socket
import sys
import time

import Adafruit_PN532 as PN532
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject
from neopixel import *

# Pins NFC Modul
CS = 18
MOSI = 23
MISO = 24
SCLK = 25

# Karten fuer NFC definieren
KARTEN = {None: "hauptmenue", 112: "finalrs", 111: "v1"}

...

BASE_PATH = Path("/home/pi/Desktop/InterfacesRS")
GLADEFILE_PATH = BASE_PATH / "hauptmenue.glade"

# Karten Typ (Mifare)
CARD_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]


class MainWindow(Gtk.Window):
    def __init__(self, sensor, led):
        self.pn532 = sensor
        self.status_led = led
        self.letzter_tag = None
        builder = Gtk.Builder()
        builder.add_from_file(str(GLADEFILE_PATH))
        #
        # TODO Sinnvolle Namen in der Glade-Datei verwenden.
        #
        self.window = builder.get_object("window1")
        self.interface_image = builder.get_object("image1")
        self.interface_image.set_from_file(str(BASE_PATH / "menu.png"))
        self.window.show_all()
        print("window intialized")

    def change_window(self, part):
        print("anderung")
        self.interface_image.set_from_file(str(BASE_PATH / "v1"))
        print("rendered")

    ...

    def sensorabfrage(self):
        uid = self.pn532.read_passive_target()
        if uid is None:
            if self.letzter_tag is not None:
                self.letzter_tag = None
                print("Kein Tag in Reichweite!")
                self.change_color(Color(84, 0, 173))
                self.change_window(None)
        else:
            if not self.pn532.mifare_classic_authenticate_block(
                uid, 4, PN532.MIFARE_CMD_AUTH_B, CARD_KEY
            ):
                print('Kartenfehler')
                self.fehler()
            #
            # TODO Das hier wirklich machen, auch nach einem Kartenfehler?
            #
            data = self.pn532.mifare_classic_read_block(4)
            if data:
                action = int(data[2:8].decode("ascii"), 16)
                tag = KARTEN.get(action)
                if tag != self.letzter_tag:
                    self.letzter_tag = tag
                    print(tag)
                    self.change_color(Color(255, 0, 0))
                    self.change_window(tag)
        return True

    def start_sensor_timer(self):
        GObject.timeout_add(300, self.sensorabfrage)


def main():
    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO)
    pn532.begin()
    pn532.SAM_configuration()

    strip = Adafruit_NeoPixel(
        LED_COUNT,
        LED_PIN,
        LED_FREQ_HZ,
        LED_DMA,
        LED_INVERT,
        LED_BRIGHTNESS,
        LED_CHANNEL,
    )
    strip.begin()

    win = MainWindow(sensor=pn532, led=strip)
    win.start_sensor_timer()
    Gtk.main()


if __name__ == "__main__":
    main()
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
steffenrohwer
User
Beiträge: 8
Registriert: Montag 4. Februar 2019, 19:00

Dienstag 15. Oktober 2019, 18:18

Hallo!

Heute hatte ich endlich mal wieder Zeit mich der Softwareseite des Projekts zu widmen. Vielen dank für deine unglaublich ausführlichen Ausführungen und sogar dem überarbeiteten Code...
Nachdem ich die LED Steuerung wieder implementiert und das pathlib nachinstalliert habe, funktioniert das Programm auch fast perfekt. Einzig das automatische wechseln zurück zu dem Hauptmenü will auch nach mehreren Anläufen einfach nicht funktionieren.

Code: Alles auswählen

#!/usr/bin/env python3
import argparse
import binascii
from datetime import datetime
from pathlib import Path
import signal
import socket
import sys
import time

import Adafruit_PN532 as PN532
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject
from neopixel import *

# Pins NFC Modul
CS = 18
MOSI = 23
MISO = 24
SCLK = 25

# Karten fuer NFC definieren
KARTEN = {None: "menu", 112: "menu", 111: "v1"}

# LED strip configuration:
LED_COUNT      = 24      # Number of LED pixels.
LED_PIN        = 19      # GPIO pin connected to the pixels (18 uses PWM!).
#LED_PIN        = 10      # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ    = 800000  # LED signal frequency in hertz (usually 800khz)
LED_DMA        = 10      # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255     # Set to 0 for darkest and 255 for brightest
LED_INVERT     = False   # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL    = 1       # set to '1' for GPIOs 13, 19, 41, 45 or 53

BASE_PATH = Path("/home/pi/Desktop/InterfacesRS")
GLADEFILE_PATH = BASE_PATH / "hauptmenue.glade"

# Karten Typ (Mifare)
CARD_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]


class MainWindow(Gtk.Window):
    def __init__(self, sensor, led):
        self.pn532 = sensor
        self.status_led = led
        self.letzter_tag = None
        builder = Gtk.Builder()
        builder.add_from_file(str(GLADEFILE_PATH))
        #
        # TODO Sinnvolle Namen in der Glade-Datei verwenden.
        #
        self.window = builder.get_object("window1")
        self.interface_image = builder.get_object("image1")
        self.interface_image.set_from_file(str(BASE_PATH / "menu"))
        self.window.show_all()
        print("window intialized")

    def change_window(self, part):
        print(part)
        self.interface_image.set_from_file(str(BASE_PATH / part))
        print("rendered")

    def change_color(self, color):
        for i in range(self.status_led.numPixels()):
            self.status_led.setPixelColor(i, color)
            self.status_led.show()

    def fehler(self):
        self.change_color(color = Color(0, 0, 0))
        time.sleep(0.2)
        self.change_color(color = Color(0, 255, 0))
        time.sleep(0.2)
        self.change_color(color = Color(0, 0, 0))
        time.sleep(0.2)
        self.change_color(color = Color(0, 255, 0))
        time.sleep(0.2)
        self.change_color(color = Color(84, 0, 173))

    def sensorabfrage(self):
        uid = self.pn532.read_passive_target()
        if uid is None:
            if self.letzter_tag is not None:
                self.letzter_tag = None
                print("Kein Tag in Reichweite!")
                self.change_color(Color(84, 0, 173))
                ########################################################
                tag = KARTEN.get(112)
                print(tag)
                self.interface_image.set_from_file(str(BASE_PATH / tag))
                print("Startscreen")
                ########################################################
        else:
            if not self.pn532.mifare_classic_authenticate_block(
                uid, 4, PN532.MIFARE_CMD_AUTH_B, CARD_KEY
            ):
                print('Kartenfehler')
                self.fehler()
            data = self.pn532.mifare_classic_read_block(4)
            if data:
                action = int(data[2:8].decode("ascii"), 16)
                tag = KARTEN.get(action)
                if tag != self.letzter_tag:
                    self.letzter_tag = tag
                    print(tag)
                    self.change_color(Color(255, 0, 0))
                    #self.change_window(tag)
                    self.interface_image.set_from_file(str(BASE_PATH / tag))
        return True

    def start_sensor_timer(self):
        GObject.timeout_add(300, self.sensorabfrage)


def main():
    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO)
    pn532.begin()
    pn532.SAM_configuration()

    strip = Adafruit_NeoPixel(
        LED_COUNT,
        LED_PIN,
        LED_FREQ_HZ,
        LED_DMA,
        LED_INVERT,
        LED_BRIGHTNESS,
        LED_CHANNEL,
    )
    strip.begin()

    win = MainWindow(sensor=pn532, led=strip)
    win.start_sensor_timer()
    Gtk.main()


if __name__ == "__main__":
    main()


Hier liegt das Problem in dem mit Hashtag markierten Bereich, denn der erste Printbefehl gibt zwar
menu
aus und auch der zweite print Befehle funktioniert einwandfrei... nur das interface ändert sich einfach nicht. :( :?

LG
steffenrohwer
User
Beiträge: 8
Registriert: Montag 4. Februar 2019, 19:00

Donnerstag 24. Oktober 2019, 20:09

Moin Moin!

Hat wirklich niemand von euch eine Idee, wie man das Problem lösen könnte? Auch nach Zahlteichen versuchen will es Raubfisch nicht klappen...

Es macht dich auch keinen Sinn, dass der selbe Code 10 Zeilen später klappt und dort nicht...
Sirius3
User
Beiträge: 10764
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 25. Oktober 2019, 07:23

Die Bild-Datei hat keine Endung? Ist das so richtig? Und das set_from_file in __init__ funktioniert?

Du könntest die beiden Fälle zusammenfassen, spart Code:

Code: Alles auswählen

    def sensorabfrage(self):
        uid = self.pn532.read_passive_target()
        if uid is None:
            print("Kein Tag in Reichweite!")
            tag = None
        elif not self.pn532.mifare_classic_authenticate_block(
                uid, 4, PN532.MIFARE_CMD_AUTH_B, CARD_KEY
            ):
            print('Kartenfehler')
            self.fehler()
            tag = None
        else:
            data = self.pn532.mifare_classic_read_block(4)
            if data:
                tag = int(data[2:8].decode("ascii"), 16)
            else:
                tag = None
        if tag != self.letzter_tag:
            self.letzter_tag = tag
            if tag is None:
                self.change_color(Color(84, 0, 173))
            else:
                self.change_color(Color(255, 0, 0))
            #self.change_window(tag)
            self.interface_image.set_from_file(str(BASE_PATH / KARTEN.get(tag)))
        return True
steffenrohwer
User
Beiträge: 8
Registriert: Montag 4. Februar 2019, 19:00

Montag 28. Oktober 2019, 18:02

Sirius3 hat geschrieben:
Freitag 25. Oktober 2019, 07:23
Die Bild-Datei hat keine Endung? Ist das so richtig? Und das set_from_file in __init__ funktioniert?

Du könntest die beiden Fälle zusammenfassen, spart Code:

Code: Alles auswählen

    def sensorabfrage(self):
        uid = self.pn532.read_passive_target()
        if uid is None:
            print("Kein Tag in Reichweite!")
            tag = None
        elif not self.pn532.mifare_classic_authenticate_block(
                uid, 4, PN532.MIFARE_CMD_AUTH_B, CARD_KEY
            ):
            print('Kartenfehler')
            self.fehler()
            tag = None
        else:
            data = self.pn532.mifare_classic_read_block(4)
            if data:
                tag = int(data[2:8].decode("ascii"), 16)
            else:
                tag = None
        if tag != self.letzter_tag:
            self.letzter_tag = tag
            if tag is None:
                self.change_color(Color(84, 0, 173))
            else:
                self.change_color(Color(255, 0, 0))
            #self.change_window(tag)
            self.interface_image.set_from_file(str(BASE_PATH / KARTEN.get(tag)))
        return True
Ich habe das nun endlich mal ausprobiert... leider immer noch das gleiche Problem...
Antworten