@Bueroklammer_xy: Das ist aber keine wirklich empfehlenswerte Lösung die Tk-Hauptschleife nicht zu verwenden. Wenn man periodisch etwas machen möchte, gibt es dafür die `after()`-Methode auf Widgets.
Der Sternchen-Import holt ca. 190 Namen in das Modul von denen nur ganz wenige verwendet werden. Es ist schwieriger nachzuvollziehen wo Namen definiert wurden und es besteht die Gefahr von Namenskollisionen.
Funktionen (und Methoden) sollten alles was sie ausser Konstanten benötigen als Argument übergeben bekommen und nicht auf magische Weise aus der Umgebung nehmen. Globale Variablen und ``global`` sollte man nicht verwenden. Das macht Programme unnötig schwer nachvollziehbar, weil man plötzlich das gesamte Programm auf einmal kennen muss, um zu verstehen wann welche globale Variable unter welchen Umständen von wo aus verändert wird.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Das hier ist ein Programm bei dem man ohne objektorientierte Programmierung nicht mehr wirklich auskommt.
Es werden sehr sehr viele `CD`-Objekte erstellt, die alle das selbe CD-Laufwerk repräsentieren. Man braucht eigentlich nur ein einziges dieser Objekte im ganzen Programm.
Der Test auf das Track-Ende ist unzuverlässig, denn wenn man Pech hat, bekommt man den Track-Wechsel nicht mit. Man darf nicht nur auf die Zeit prüfen, sondern muss auch den Track-Index berücksichtigen.
Zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist mehr BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode.
Es wird bei der Erstellung der Trackliste kein Test gemacht ob es sich überhaupt um einen Audio-Track handelt.
Statt dort alle Tracks einzeln abzufragen, würde sich die `CD.get_all()`-Methode anbieten.
Explizite Vergleiche mit `True` und `False` sind unnötig umständlich. Da kommt ja nur wieder ein Wahrheitswert heraus, entweder den, den man sowieso schon hatte, oder das Gegenteil. Also kann man auch gleich den Wert oder seine Negation mit `not` verwenden.
Ungetesteter Zwischenstand:
Code: Alles auswählen
from functools import partial
import tkinter as tk
from tkinter import ttk
from pygame import cdrom
def cd_tracks_holen(drive):
"""Tracks von CD auslesen."""
return [
'Track{} - {}'.format(number, int(length))
for number, (is_audio, _, _, length) in enumerate(drive.get_all(), 1)
#
# TODO Check if track is audio track and filter those out.
# Needs changes in the GUI code because then the index into
# this list isn't neccessarily the index of the `Listbox`.
#
]
class App(tk.Tk):
def __init__(self, drive):
tk.Tk.__init__(self)
self.drive = drive
self.is_playing = False
self.current_selection_index = 0
self.selected_track_indices = []
main_frame = ttk.Frame(self, padding=5)
main_frame.grid()
ttk.Button(
main_frame, text='Play', command=self.abspielen
).grid(column=0, row=0, sticky=tk.N)
tracks = tk.StringVar(value=cd_tracks_holen(drive))
self.tracks_listbox = tk.Listbox(
main_frame, height=12, selectmode=tk.EXTENDED, listvariable=tracks
)
self.tracks_listbox.grid(column=1, row=0, sticky=tk.N)
self.check_state()
def check_state(self):
if self.is_playing:
track_index = self.selected_track_indices[
self.current_selection_index
]
playing_index, length = self.drive.get_current()
if not self.drive.get_busy():
self.drive.play(track_index)
print(
'Track{} {}'.format(
track_index, self.drive.get_track_length(track_index)
)
)
elif (
track_index != playing_index or
int(length) >= int(self.drive.get_track_length(track_index))
):
self.drive.stop()
self.current_selection_index += 1
if self.current_selection_index >= len(self.selected_track_indices):
self.is_playing = False
self.after(100, self.check_state)
def abspielen(self):
"""Abspielen vorbereiten."""
self.selected_track_indices = self.tracks_listbox.curselection()
if self.selected_track_indices:
if self.drive.get_busy():
self.drive.stop()
self.is_playing = True
self.current_selection_index = 0
def main():
cdrom.init()
drive = cdrom.CD(0)
drive.init()
app = App(drive)
app.mainloop()
if __name__ == '__main__':
main()