mal eben ein UI ... blutiger anfäger rennt vor eine Wand

Fragen zu Tkinter.
Antworten
S3R43o3
User
Beiträge: 4
Registriert: Donnerstag 15. Juli 2021, 18:22

Nun zu erst ich bin blutiger Anfänger sowohl in Sachen programmieren als auch in Sachen Python.
Nun habe ich mit einen Screen recorder gebaut der auch funktioniert nur gefällt mir die CMD nicht und wollte daher ein nettes GUI haben. Dachte kann ja nich so schwer sein 2 Buttons 1 text vielleicht ein Hilfe Button.
Joah hab ich wohl die Rechnung nich mit python gemacht.
Ich spreche schon gut englisch jedoch sind fachspezifische texte unglaublich schwer zu verstehen wenn nicht in der Muttersprache geschrieben.
Gestartet habe ich hiermit:
das funktioniert auch alles wie es soll.

Code: Alles auswählen

import cv2, numpy, pyautogui, keyboard
import PySimpleGUI as UI



filename = 'Bildschirmaufnahme' 
SCREEN_SIZE = (1920, 1080)
vid = cv2.VideoWriter(filename + ".mp4", cv2.VideoWriter_fourcc(*'mp4v'),20.0,(SCREEN_SIZE))
print("Starte Aufnahme.\nDrücke 'X' auf deiner Tastatur um die Aufnahme zu beenden...")
while True:
    img = pyautogui.screenshot()
    numpy_frame = numpy.array(img)
    frame = cv2.cvtColor(numpy_frame, cv2.COLOR_BGR2RGB)
    vid.write(frame)
    if keyboard.is_pressed('x'):
        print("Stoppe Aufnahme.")
        break
cv2.destroyAllWindows()
vid.release()
und hier nun der Klägliche Versuch den Code umzubauen *ich schäm mcih schon ein wenig ...

Code: Alles auswählen

import tkinter as tk 
import cv2, numpy, pyautogui, keyboard, time




# --------------- Funktionen ------------------
def start():
    global running

    if running is not None:
        print('Ich laufe bereits')
    else:
        frame = cv2.cvtColor(numpy_frame, cv2.COLOR_BGR2RGB)
        running = vid.write(frame)
        running.start_recording()

def stop():
    global running

    if running is not None:
        running.stop_recording()
        vid.release()
        cv2.destroyAllWindows()
        running = None
    else:
        print('Ich laufe nicht mehr')


# ---------------------- Main ------------------------------
filename = "Bildschirmaufnahme"
SCREEN_SIZE = (1920, 1080)
vid = cv2.VideoWriter(filename + ".mp4", cv2.VideoWriter_fourcc(*'mp4v'), 20.0,(SCREEN_SIZE))
img = pyautogui.screenshot()
numpy_frame = numpy.array(img)
running = None

root = tk.Tk()

button_rec = tk.Button(root, text="Start", command=start)
button_rec.pack()

button_stop = tk.Button(root, text="Stop", command=stop)
button_stop.pack()

root.mainloop()

Der selbstverständlich nich das tut was er soll.. Ich bekomme zwar die Ausgabe einer mp4. Datei aber es ist wohl so das er nur solang aufnimmt solange der button im gedrückt zustand ist...
Ich forsche nun schon seit 2 Tagen im Netz habe Mir Qt, Tkinter, SimpleGUI angeschaut aber iwie komme ich nich zu einer Lösung. Ich glaube nicht das ich dafür threadding brauche oder ?
Ich bin über jegliche Hilfe unglaublich dankbar und vielen Dank im allgemeinen für eurer geteiltest Knowhow und eure Zeit!
Liebe Grüße

Bitte seid gnädig
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@S3R43o3: Doch dafür brauchst Du Threads wenn die Aufnahme mit Code entstehen soll, der neben der GUI laufen muss. Und damit ist das definitiv nichts mehr als erstes Anfängerprojekt, denn sowohl Threads als auch GUIs sind für sich genommen schon komplex. Alternativ kannst Du schauen welchen Mechanismus das verwendete GUI-Rahmenwerk bietet um nach einer bestimmten Zeitspanne eine Funktion/Methode aufzurufen, in der dann eine einzelne Aufnahme gemacht und kodiert werden kann. Bei `tkinter` wäre das die `after()`-Methode auf Widgets.

Für GUIs braucht man objektorientierte Programmierung (OOP), und dafür die Grundlage wäre es das man auch saubere Programme mit Funktionen schreiben kann. Das ist beiden Programmen von Dir nicht ersichtlich. ``global`` vergisst Du beispielsweise am besten sofort wieder. Funktionen (und Methoden) bekommen alles was sie ausser Konstanten benötigen, als Argument(e) übergeben, und Ergebnisse werden an den Aufrufer mit ``return`` zurückgegeben. Und um Zustand über Aufrufe hinweg zu speichern, braucht man dann OOP, also eigene Klassen.

Mehrere GUI-Rahmenwerke sollte man in der Regel nicht mischen. Den `VideoWriter` von OpenCV kannst Du verwenden, aber Du solltest keine GUI oder Benutzerinteraktion aus dem Paket zusammen mit einem GUI-Rahmenwerk benutzen. Das kann funktionieren, muss es aber nicht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@S3R43o3: Anmerkungen zum ersten Quelltext:

Importe von mehreren Modulen werden üblicherweise nicht zu einer ``import``-Anweisung zusammengefasst. Siehe Style Guide for Python Code.

`PySimpleGUI` wird importiert, aber nicht verwendet.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

`filename` ist eine Konstante und sollte deshalb KOMPLETT_GROSS geschrieben werden.

Die Klammern bei der Verwendung von `SCREEN_SIZE` sind überflüssig.

Namen sollte man nicht kryptisch Abkürzungen. Und man muss auch nicht jedes Zwischenergebnis an einen eigenen Namen binden.

Den `release()`-Aufruf sollte man mit einem ``try``/``finally`` auch sicherstellen wenn die Aufnahme durch eine Ausnahme beendet wird.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import cv2
import keyboard
import numpy
from pyautogui import screenshot

BASE_FILENAME = "Bildschirmaufnahme"
SCREEN_SIZE = (1920, 1080)  # TODO Dynamisch ermitteln.


def main():
    video_writer = cv2.VideoWriter(
        BASE_FILENAME + ".mp4",
        cv2.VideoWriter_fourcc(*"mp4v"),
        20,
        SCREEN_SIZE,
    )
    try:
        print(
            "Starte Aufnahme.\n"
            "Drücke 'X' auf deiner Tastatur um die Aufnahme zu beenden..."
        )
        while True:
            video_writer.write(
                cv2.cvtColor(numpy.array(screenshot()), cv2.COLOR_BGR2RGB)
            )
            if keyboard.is_pressed("x"):
                print("Stoppe Aufnahme.")
                break

        cv2.destroyAllWindows()
    finally:
        video_writer.release()


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
S3R43o3
User
Beiträge: 4
Registriert: Donnerstag 15. Juli 2021, 18:22

Okay dann ersteinmal vielen Dank ich dachte mir Schon das die Problematik dahin führt... Nun ich bin mit JS vertraut dort kann ich einfach ein process laufen lassen.
Herzlichen dank nocheinmal dann lege ich das mal auf Seite =D
Was die sache mit dem import angeht das war nur ein vergessenes rest stück beim Copy/paste
Zuletzt geändert von S3R43o3 am Freitag 16. Juli 2021, 14:34, insgesamt 1-mal geändert.
S3R43o3
User
Beiträge: 4
Registriert: Donnerstag 15. Juli 2021, 18:22

was anderes ... das script einfach so aufrufen über ein anderes funktioniert da nicht ? per import oder so ?
S3R43o3
User
Beiträge: 4
Registriert: Donnerstag 15. Juli 2021, 18:22

nun nach Etwas tüffeln habe ich ein Workaround gefunden.
Leider habe ich dein Snippet nicht zum laufen bekommen.
Aber der hier tut in etwa das was ich wollte.
Die automatische größe funktioniert auch =)

Code: Alles auswählen

import cv2
import numpy
import keyboard
import pyautogui as ui

SCREEN_SIZE = width, height = ui.size()
info2 = "\n\bNach dem drücken des 'Ok'-Buttons wird die Aufnahme automatisch gestartet."
info1 = "Bitte schreibe den Titel deiner Aufnahme in die Eingabe unten."
wichtig1 = "\n\bUm die Aufnahme zu beenden drücke 'X' auf deiner Tastatur."


filename = ui.prompt(text=info1 + info2 + wichtig1, title="Name der Aufnahme", default="")    
vid = cv2.VideoWriter(filename + ".mp4", cv2.VideoWriter_fourcc(*'mp4v'), 30.0, (SCREEN_SIZE))

while True:
    img = ui.screenshot()
    numpy_frame = numpy.array(img)
    frame = cv2.cvtColor(numpy_frame, cv2.COLOR_BGR2RGB)
    vid.write(frame)
    if keyboard.is_pressed('x'):
        print("Stoppe Aufnahme.")
        ui.alert("Deine Aufnahme wurde erstellt.", 'Achtung!', button='OK')
        break
cv2.destroyAllWindows()
vid.release()
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@S3R43o3: Mein ”Snippet” ist vollständig und ich habe es gerade ausprobiert — das läuft bei mir. Nervigerweise nur als Admin, weil das `keyboard`-Modul diese Rechte braucht. Aber das wäre bei Deinem letzten Quelltext ja auch der Fall.

Dein Programm kommt nicht damit klar wenn der Benutzer den Dialog mit der Frage nach dem Dateinamen per Button oder Fenster schliessen abbricht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten