@PythonMarlem: Achtung: Grundlage von diesem Beitrag ist der Code im vorletzen Beitrag von Dir. Hat ein bisschen länger gedauert…
Mir fehlt da die She-Bang-Zeile.
Boxen aus Zeichen in Kommentaren und Docstrings sind zwar im ersten Moment nett anzusehen, aber nicht sehr wartungsfreundlich. In Docstrings hat man zusätzlich das Problem, dass weder reStructuredText noch Markdown damit etwas anfangen können.
`os` wird importiert, aber nirgends verwendet.
Sternchen-Importe sind Böse™. Das macht Programme unübersichtlich weil man nicht mehr so leicht nachvollziehen kann welcher Name woher kommt. Ausserdem besteht die Gefahr von Namenskollisionen. Das die Module `QtCore` und `QtWidgets` importiert werden und dann aber auch noch mal Objekte *aus* diesen beiden Modulen direkt importiert werden, macht die Sache auch nicht übersichtlicher. Wann geht man denn dann über das Modul und wann wird direkt importiert? Insbesondere bei `QtWidgets` wo ja der Sternchen-Import verwendet wird, frage ich mich was da dann der Grund sein sollte über das Modul zu gehen, wo man doch alle Namen schon direkt zur Verfügung hat?
Der Code-Block am Ende des Moduls gehört auch in eine Funktion, konventionell `main()` genannt, und davor geschützt ausgeführt zu werden wenn man das Modul importiert statt es als Programm auszuführen.
`QApplication` erwartet die Argumente von der Kommandozeile, denn Qt kann davon welche auswerten.
Zu sparrow's Anmerkungen das `barrierefreiheit_setzen()` nicht von aussen aufgerufen werden sollte: Das setzt auch noch ein neues Attribut auf dem Objekt. Auch das sollte nicht sein. Nachdem die `__init__()`-Methode durchgelaufen ist, sollten alle Attribute existieren und das Objekt in einem benutzbaren Zustand sein, denn genau das ist die Aufgabe der `__init__()`-Methode.
`layout_barrierefrei` sollte aber wohl eher auch gar kein Attribut sein, denn das wird nirgends sonst benötigt.
Neben den ganzen unnötigen `show()`-Aufrufen ist auch `showNormal()` Unsinn. Das Fenster wurde vorher ja gar nicht angezeigt, also auch nicht minimiert oder maximiert. Zudem gehört das Anzeigen von sich selbst nicht in die `__init__()` weil man so dem Code der das Widget erstellt, die Möglichkeit nimmt zu entscheiden ob und wann das Widget angezeigt werden soll.
Das Vorgeben der minimalen Fenstergrösse macht nicht wirklich Sinn. Das sieht mir nach dem Versuch aus, dass für die anfängliche Fenstergrösse zu missbrauchen.
Und auch `setDefault()` ist ein ganz klarer Missbrauch. Das ist dafür gedacht *einen* Default-Button in Dialogen festzulegen, nicht dazu um auf *allen* Buttons in einem Fenster gesetzt zu werden, nur damit man die Eingabetaste zum aktivieren verwenden kann. Das hat ja auch noch andere Auswirkungen. Und man kann das dann nicht mehr dazu verwenden wofür es eigentlich gedacht ist: bei mehreren Buttons in einem Dialog einen speziell ausgwählten davon per Tastatur aktivieren zu können, ohne das man ihn auswählen/fokussieren muss.
Das mit den Fokusfarben funktioniert bei mir (Linux) bei den Buttons nicht. Das Gelb blitzt ganz kurz auf und wird dann durch ein Blau ersetzt.
Das Farbe setzen hat den leicht komischen Effekt, dass Buttons die einmal den Fokus hatten, danach eine andere Hintergrundfarbe haben. Würde wohl auch für das Texteingabefeld gelten wenn da die normale Farbe nicht zufällig auch weiss wäre.
Aber noch schlimmer ist, dass die Hintergrundfarbe auch auf den Tooltips gesetzt wird. Die bei mir standardmässig eine dunkle Hintergrundfarbe mit weisser Schrift haben. Beim Texteingabefeld also wenn das den Fokus hat, weisse Schrift auf gelbem Hintergrund. Schlecht bis gar nicht lesbar. Wenn es dann den Fokus verliert, weisse Schrift auf weissem Hintergrund. Garantiert gar nicht mehr lesbar.
Die Fokus-Handler in den beiden Klassen rufen auch die ursprüngliche Implementierung auf der Basisklasse gar nicht auf. Falls die irgend etwas wichtiges macht, dann fällt das einfach unter den Tisch.
Für die beiden supersimplen Button-Aktionen würde ich keine Methoden definieren. Das bekommt man auch in einem ``lambda``-Ausdruck bequem unter.
Was PEP8 angeht ist `Text` in `OnClick()` wie eine Klasse geschrieben. Ich sehe aber auch nicht so wirklich wofür man da überhaupt einen Namen braucht.
Bei den Event-Handlern ist das Argument `QFocusEvent` falsch geschrieben. Zudem noch verwirrend, da das der Typ ist den das Argumnet hat, denn eine `QFocusEvent`-Klasse gibt es in Qt ja tatsächlich. Konvention bei unbenutzten Argumentnamen oder lokalen Namen ist es entweder nur `_` las Namen zu verwenden, oder den einen Unterstrich als Präfix zu verwenden.
In `barrierefreiheit_setzen()` ist die Leerzeichensetzung nach Kommas nicht konsistent.
Fazit: Es wird ganz viel wirklich falsch gemacht, nur um auf biegen und brechen ein Ergebnis zu bekommen, das nur für Leute funktioniert, die bestimmte Screenreader einsetzen. Und das auch nur wenn nur der Reader-Teil von Accessibility-Software benutzt wird. Sollte ein Anwender dann auch Sprachsteuerung verwenden wollen, verhindert der Missbrauch vom AccessibilityName das auch noch. Und das mit der Farbe bei Buttons funktioniert auch noch nicht mal überall. Für sehende Menschen macht das, zumindest bei mir, nur Probleme.
Das mag hart klingen, aber IMHO ist das komplett unbrauchbar.
Trotzdem noch mal den Zwischenstand nach der ganzen Kritik:
Code: Alles auswählen
#!/usr/bin/env python3
"""
==================================================
Mit Python und Qt eine Anwendung entwickeln
die für Blinde und Sehbehinderte bedienbar ist
==================================================
Folgende barrierefreie Kriterien demonstriert diese Anwendung:
1. Screenreadertauglichkeit
Screenreader ist eine Software die den Bildschirminhalt vorliest Blinde und
auch einige Sehbehinderte Menschen können nur Software bedienen die dem
Screenreader Texte übermitteln welche die Bedienelemente beschreiben.
In Java und C# werden Texte für Screenreader in der Eigenschaft
"AccessibleDescription" hinterlegt. Diese Eigenschaft gibt es auch in Python.
Leider wird sie im Betriebssystem Windows von den Screenreadern NVDA und Jaws
nicht ausgelesen. Deswegen werden die Texte für Screenreader in der
Eigenschaft "AccessibleName" hinterlegt.
Die Software wurde erfolgreich mit folgenden Screenreadern getestet:
* NVDA, Betriebssystem Windows
* Jaws, Betriebssystem Windows
* Orca, Betriebssystem Ubuntu
2. Tastaturbedienbarkeit
Alle Bedienelemente sind per Tabulatortaste erreichbar. Die Schalter können
per Entertaste ausgeführt. Die Tastaturbedienbarkeit ist für blinde und
sehbehinderte Menschen wichtig. Zur Tastaturbedienbarkeit gehört auch das
Beschriftung mit Eingabefelder verknüpft sind. Das geht über die Methode
`Qlabel.setBuddy()`.
3. Visuelle und programmgesteuerte Anzeige der Position des Tastaturfokus
Damit Menschen mit einer Sehbehinderung erkennen welches Bedienelement aktiv
ist, muss eine Software dies deutlich sichtbar machen. Meine Lieblingsmethode
ist, dass aktive Bedienelement bekommt die Hintergrundfarbe Gelb.
"""
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QLabel,
QLineEdit,
QPushButton,
QWidget,
)
# 3. Visuelle und programmgesteuerte Anzeige der Position des Tastaturfokus
class QAcccessibilityButton(QPushButton):
def focusInEvent(self, event):
super().focusInEvent(event)
self.setStyleSheet("background-color: yellow")
def focusOutEvent(self, event):
super().focusOutEvent(event)
self.setStyleSheet("background-color: #E1E1E1")
# 3. Visuelle und programmgesteuerte Anzeige der Position des Tastaturfokus
class QAcccessibilityEdit(QLineEdit):
def focusInEvent(self, event):
super().focusInEvent(event)
self.setStyleSheet("background-color: yellow")
def focusOutEvent(self, event):
super().focusOutEvent(event)
self.setStyleSheet("background-color: white")
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Barrierefreiheit mit Python und Qt")
layout = QGridLayout()
self.button_betriebssystem = QAcccessibilityButton(
"Name des &Betriebssystem", self
)
self.button_betriebssystem.setToolTip(
"Es wird ausgegeben wie das Betriebssystem heißt"
)
self.button_betriebssystem.setDefault(True)
layout.addWidget(self.button_betriebssystem, 0, 0)
self.button_anwender = QAcccessibilityButton("Hallo &Anwender", self)
self.button_anwender.setToolTip("Der Anwender wird begrüßt")
layout.addWidget(self.button_anwender, 1, 0)
self.label_vor_nachname = QLabel("&Vor- und Nachname:", self)
layout.addWidget(self.label_vor_nachname, 2, 0)
self.edit_vor_nachname = QAcccessibilityEdit(self)
self.edit_vor_nachname.setToolTip("Geben Sie Vor- und Nachname ein")
self.edit_vor_nachname.setText("Markus Lemcke")
layout.addWidget(self.edit_vor_nachname, 2, 1)
self.programm_beenden_button = QAcccessibilityButton("&Ende", self)
self.programm_beenden_button.setToolTip("Programm Beenden")
layout.addWidget(self.programm_beenden_button, 3, 0)
self.setLayout(layout)
self.label_vor_nachname.setBuddy(self.edit_vor_nachname)
self.button_betriebssystem.clicked.connect(
lambda: print("Betriebssytem:", sys.platform)
)
self.button_anwender.clicked.connect(
lambda: print("Guten Tag", self.edit_vor_nachname.text())
)
self.programm_beenden_button.clicked.connect(self.close)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()