# Fortgeschrittene Bedienung der Benutzeroberfläche

Dieses Kapitel stellt Ihnen tiefergehende Automatisierungsschnittstellen vor, mit denen Sie verschiedene detaillierte Operationen durchführen können. Der Inhalt dieses Kapitels ist umfangreich. Wenn Sie zum ersten Mal damit in Berührung kommen, empfehlen wir Ihnen, jeden Abschnitt geduldig durchzulesen.

```{tip}
Beim Schreiben von Automatisierungscode können Sie den Befehl `lamda` direkt im Terminal auf der rechten Seite des Remote-Desktops eingeben und darin die folgenden Testcodes ausführen oder selbst Tests zur Elementauswahl oder zum Klicken durchführen. Dies kann die Geschwindigkeit Ihrer Entwicklung und Verifizierung beschleunigen.
```

## Elemente abrufen

Sie haben möglicherweise bereits in den Grundlagen oder in den vorherigen Abschnitten einige Kenntnisse darüber erlangt. Sie müssen die relevanten Elemente über Selektoren finden, um Operationen durchführen zu können. Sie haben wahrscheinlich auch gesehen, wo Sie die Selektorparameter erhalten können. Die folgenden Erläuterungen werden sich um dieses Element drehen. Auf der rechten Seite dieses Bildes sehen Sie die relevanten Informationen zum Element „同意“ (Zustimmen).

![Beispielelement](/assets/images/auto-eyeselect.png)

```{attention}
Das Element, auf das Sie direkt auf der linken Benutzeroberfläche klicken, ist möglicherweise nicht das tatsächliche Element, da es sich in Größe und Position mit anderen Elementen überschneiden kann. Normalerweise werden mehrere Elemente, die sich in Position und Größe überschneiden, auch in der Informationsleiste auf der rechten Seite angezeigt. Sie können nach oben und unten scrollen, um zu sehen, welches das wirklich benötigte ist. Sie können auch die TAB-Taste auf der linken Auswahl-Oberfläche drücken, um manuell durch alle Elemente zu navigieren.
```

Für das obige Element verwenden wir im Allgemeinen `text`, um es abzurufen. Die Bedingung für die Verwendung von `text` ist, dass auf der aktuellen Oberfläche kein anderes Element ebenfalls den Text „同意“ (Zustimmen) hat. Dies ist die einfachste Methode. Alternativ können Sie auch `resourceId` verwenden. Beachten Sie jedoch, dass `resourceId` hier nicht für eine eindeutige ID steht, sondern für eine Ressourcen-ID, und eine Benutzeroberfläche kann viele Elemente mit derselben Ressourcen-ID enthalten. Andere Felder wie `packageName`, `checkable` usw. werden seltener verwendet, können aber versucht werden, wenn `text`, `resourceId`, `description` usw. nicht verfügbar sind. Wir können dieses Element auf folgende Weisen abrufen.

```python
element = d(text="同意")
element = d(text="同意", resourceId="com.tencent.news:id/btm_first_agree")
element = d(resourceId="com.tencent.news:id/btm_first_agree")
```

## Klick auf Elemente

Rufen Sie die folgende Schnittstelle auf, um einen normalen Klick auf ein Element auszuführen. Im Kontext wird für Sie der Effekt eines manuellen Klicks auf „Zustimmen“ realisiert.

```python
element.click()
```

Wenn Sie die Position des Klicks auf dem Element angeben müssen, können Sie `corner` angeben. `Corner.COR_CENTER` bedeutet, auf den Mittelpunkt des Elements zu klicken. Sie können auch auf die obere linke oder untere rechte Ecke (`COR_BOTTOMRIGHT`) klicken.

```python
element.click_exists(corner=Corner.COR_TOPLEFT)
```

Führt einen langen Klick auf dem Element aus; löst eine Ausnahme aus, wenn es nicht existiert. Diese Schnittstelle unterstützt auch `corner`, die Dauer des langen Klicks kann nicht angegeben werden.

```python
element.long_click()
```

Klickt, wenn das Element existiert. Wenn das Element nicht existiert, löst der Aufruf dieser Schnittstelle keine Ausnahme aus. Diese Schnittstelle unterstützt ebenfalls `corner`.

```python
element.click_exists()
```

```python
>>> element.click_exists()
True
```

## Existenzprüfung

In vielen Fällen ist es notwendig, die Existenz eines Elements zu überprüfen, bevor weitere Operationen durchgeführt werden, andernfalls kann der nachfolgende Prozess auf einen Fehler stoßen oder falsche Aktionen auf der falschen Oberfläche ausführen. Möglicherweise müssen Sie in bestimmten Situationen die folgende Schnittstelle zur Existenzprüfung verwenden.

```python
element.exists()
```

## Elementinformationen

In einigen Fällen möchten Sie möglicherweise Teile der Informationen eines Elements abrufen, zum Beispiel die Koordinaten, den Bereich oder die im Element enthaltenen Text- oder Beschreibungsinformationen. Sie können die folgende Schnittstelle verwenden, um Elementinformationen zu lesen.

```python
element.info()
```

Für unser obiges Testelement lautet die Ausgabeinformation wie folgt:

```python
>>> info = element.info()
>>> print (info)
bounds { ... }
className: "android.widget.TextView"
clickable: true
enabled: true
focusable: true
packageName: "com.tencent.news"
resourceName: "com.tencent.news:id/btn_first_agree"
text: "\345\220\214\346\204\217"
visibleBounds { ... }
```

```{hint}
Sie stellen vielleicht fest, dass in der obigen Druckausgabe einige Felder fehlen, wie z.B. `description`. Dies bedeutet normalerweise, dass das Feld leer oder `false` ist. Sie können dennoch normal über die Attribute auf die entsprechenden Felder zugreifen, um deren Werte zu erhalten.
```

Wie Sie sehen, sind diese Informationen relativ komplex. Dies ist das Standard-Druckformat von protobuf. Sie können den tatsächlichen Wert direkt ausgeben, indem Sie auf das entsprechende Attribut zugreifen. Wenn Sie beispielsweise den Wert des `text`-Attributs eines Elements lesen möchten, können Sie dies wie folgt tun.

```python
>>> info = element.info()
>>> print (info.text)
同意
```

Natürlich gibt es auch Informationen zu den Bereichskoordinaten des Elements, auf die Sie ebenfalls zugreifen können. Wenn Sie beispielsweise die Bereichsinformationen des Elements abrufen möchten, können Sie dies wie folgt tun, um die Bereichsinformationen auszugeben, oder sie für nachfolgende Operationen in einer Variablen speichern.

```python
>>> info = element.info()
>>> print (info.bounds)
```

Der ausgegebene oder zurückgegebene Wert ist eine Bereichsinformation (`Bound`). Sie werden später feststellen, dass dies ein Parameter ist, der auch von einer Screenshot-Schnittstelle verwendet wird. Ja, Sie können diesen Parameter an die Screenshot-Schnittstelle übergeben, um einen Screenshot nur von diesem Element zu erstellen, aber wir haben dies bereits für Sie gekapselt.

Vielleicht möchten Sie auch die Breite und Höhe des Elements abrufen, um bestimmte Offsets zu berechnen, zum Beispiel den Offset relativ zu anderen Elementen. Das können Sie so tun:
```python
>>> info = element.info()
>>> print (info.bounds.width, info.bounds.height)
484 138
```

Oder rufen Sie den Mittelpunkt oder die Eckpunkte des Elements ab, wie z.B. oben links oder unten rechts. Die folgenden Schnittstellen geben normalerweise `Point`-Informationen zurück. Sie können auch die entsprechenden X- und Y-Koordinaten des Gerätebildschirms aus dem `Point`-Objekt abrufen.
```python
>>> info = element.info()
>>> print (info.bounds.center())
x: 792
y: 1908
>>> print (info.bounds.center().x)
792
```

Der folgende Aufruf wird verwendet, um die Eckpunktkoordinaten des Elements abzurufen. Das Beispiel ruft die Koordinaten der oberen linken Ecke des Elements ab. Darüber hinaus wird das Abrufen der Koordinaten aller vier Eckpunkte wie `bottom-right`, `top-right` und `bottom-left` unterstützt.

```python
>>> info = element.info()
>>> print (info.bounds.corner("top-left"))
x: 550
y: 1839
>>> print (info.bounds.corner("top-left").x)
550
```

## Iteration über Elemente

Sie können auch über alle vom Selektor ausgewählten Elemente iterieren. Normalerweise gibt es im Kontext möglicherweise nur ein solches Element, daher wählen Sie bitte einen anderen Selektor zum Testen. Sie können einfach eine `for`-Schleife oder eine andere Methode direkt auf dem Selektor verwenden, um zu iterieren.

```python
for i in element: print (i)
```

Oder wenn Sie wissen, dass es mehrere übereinstimmende Elemente gibt und Sie das n-te übereinstimmende Element erhalten möchten, können Sie die folgende Schnittstelle verwenden.

```python
element_3rd = element.get(3)
```

## Elementanzahl

Normalerweise werden Sie diese Schnittstelle nicht direkt verwenden. Der folgende Aufruf kann die Anzahl der Elemente abrufen, die mit Ihrem aktuellen Selektor übereinstimmen.

```python
>>> element.count()
1
```

## Screenshot von Elementen

Wir unterstützen Screenshots auf Elementebene, sodass Sie das Bild eines Elements einzeln erfassen können, ohne einen Screenshot des gesamten Bildschirms machen und ihn dann zuschneiden zu müssen.

```python
element.screenshot(quality=60)
```

Nachdem Sie den Screenshot erstellt haben, können Sie `getvalue` verwenden, um die binären Daten des Screenshots direkt abzurufen, oder ihn direkt an ein `PIL.Image`-Objekt übergeben.

```python
>>> element.screenshot(quality=60).getvalue()
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe2\x02(ICC_PROFILE\x00\x01\x01\x00\x00\x02\x18\x00\x00\x00\x00\x02\x10\x00\x00mntrRGB XYZ \x00\x00...
```
Oder wenn Sie keine weitere Verarbeitung benötigen, können Sie den Screenshot auch direkt in einer lokalen Datei speichern.
```python
>>> element.screenshot(quality=60).save("image.png")
```

## Warten auf Elemente

In einigen Situationen müssen Sie möglicherweise feststellen, ob die aktuelle Seite vollständig geladen ist. Normalerweise können Sie dies tun, indem Sie prüfen, ob ein relevantes Element bereits angezeigt wird, um festzustellen, ob die aktuelle Seite geladen ist. Das folgende Beispiel wartet auf das Erscheinen des Elements „同意“ (Zustimmen), mit einer maximalen Wartezeit von 10 Sekunden.

```{hint}
Die Wartezeit hier ist in Millisekunden, daher müssen 10 Sekunden mit 1000 multipliziert werden, 10 Sekunden = 10000 Millisekunden.
```

```python
element.wait_for_exists(10*1000)
```

```python
>>> element.wait_for_exists(10*1000)
True
```

Natürlich unterstützen wir nicht nur das Warten auf das Erscheinen eines Elements, sondern auch das Warten auf sein Verschwinden, das heißt, bis das Element von der Benutzeroberfläche verschwindet.

```python
element.wait_until_gone(10*1000)
```

```python
>>> element.wait_until_gone(10*1000)
False
```

## Texteingabe

Die Texteingabe ist ein Bereich, der besondere Aufmerksamkeit erfordert. Wir können keinen Text in eine „Zustimmen“-Schaltfläche eingeben, da es sich um eine Schaltfläche handelt. Jetzt nehmen wir ein Eingabefeld-Element als Beispiel, dessen grundlegende Informationen unten gezeigt werden.

![Texteingabe](/assets/images/input-text.png)

```{attention}
Beim Abrufen von Eingabefeld-Elementen gibt es einige Dinge zu beachten. Bitte stellen Sie sicher, dass Ihre Eingabemethode **geöffnet** ist, bevor Sie nach dem relevanten Element suchen, und es wird empfohlen, sorgfältig zu suchen, da Sie sonst möglicherweise nicht das tatsächliche Eingabefeld erhalten.
```

```{hint}
Im Ablauf des Automatisierungscodes müssen Sie nur Code schreiben, um zuerst auf das übergeordnete angezeigte Eingabefeld zu klicken, um die Eingabemethode zu öffnen.
```

Für das obige Eingabefeld können wir die folgende Schnittstelle aufrufen, um die Zeichenfolge „你好世界“ (Hallo Welt) einzugeben. Natürlich wird auch die Eingabe von englischen oder anderen Unicode-Zeichenfolgen unterstützt. Sie müssen es nur wie unten gezeigt verwenden, um Text in das Feld einzugeben.

```python
>>> element = d(text="搜索感兴趣的内容")
>>> element.set_text("你好世界")
True
```

Oder wenn Sie plötzlich die Idee haben, den aktuell im Eingabefeld angezeigten Text abzurufen, können Sie dies wie folgt tun.

```{attention}
Sie können sehen, dass wir hier den Selektor geändert haben. Unser ursprünglicher Selektor basierte auf `text`, aber nachdem wir Text eingegeben hatten, änderte sich der Inhalt, sodass das Element nicht mehr existierte, weshalb wir zu einem anderen Selektor wechselten. Die Verwendung eines geeigneten Selektors ist sehr wichtig, aber wir belassen es für dieses Beispiel dabei.
```

```python
>>> element = d(className="android.widget.EditText")
>>> element.get_text()
'你好世界'
```

Oder um den aktuell eingegebenen Inhalt zu löschen. Normalerweise wird beim Eingeben von Text der vorherige Text automatisch gelöscht, aber Sie können ihn auch manuell löschen.

```{hint}
Tatsächlich kann ein ähnlicher Effekt auch erzielt werden, indem die Tastenschnittstelle verwendet wird, um wiederholt die `BACKSPACE`-Taste zu drücken.
```

```python
>>> element = d(className="android.widget.EditText")
>>> element.clear_text_field( )
True
```

```{note}
In extremen Fällen kann diese Schnittstelle an einigen Stellen nicht normal zur Texteingabe verwendet werden. Wir arbeiten an der Unterstützung.
```

## Normales Wischen (Swipe)

Verwenden Sie die folgende Schnittstelle, um Wischoperationen auf der Benutzeroberfläche durchzuführen, zum Beispiel das Scrollen nach oben und unten in einer Liste. Der folgende Aufruf implementiert ein Wischen nach oben. Passen Sie `step` selbst an; je größer der Wert, desto langsamer die Wischgeschwindigkeit, was für Wischvorgänge mit hoher Präzision geeignet ist.

```{attention}
In einfachen Fällen muss für diese Operation kein Selektorparameter angegeben werden. Wenn jedoch ein Wischen nicht möglich ist, setzen Sie bitte die Selektorbedingung auf ein geeignetes Element, zum Beispiel ein Element mit dem Attribut `scrollable` oder den Container der ersten Ebene einer Liste.
```

```python
d().swipe(direction=Direction.DIR_UP, step=32)
```

```python
>>> element = d(resourceId="com.tencent.news:id/important_list_content")
>>> element.swipe(direction=Direction.DIR_UP, step=32)
True
```

| Richtungsanzeiger   | Beschreibung     |
|---------------------|------------------|
| Direction.DIR_UP    | Nach oben wischen|
| Direction.DIR_LEFT  | Nach links wischen|
| Direction.DIR_DOWN  | Nach unten wischen|
| Direction.DIR_RIGHT | Nach rechts wischen|

## Schnelles Wischen (Fling)

Schnelles Wischen (Fling) ähnelt dem Verhalten einer Person, die schnell über den Bildschirm wischt. Diese Operation wischt schnell über den Bildschirm und eignet sich zur Simulation von Aktionen wie schnellem Durchsuchen. Das folgende Beispiel wischt von oben nach unten über den Bildschirm. Im Beispiel ist der Selektor leer, Sie müssen jedoch je nach Situation entscheiden, ob Sie einen Selektor angeben.

```python
d().fling_from_top_to_bottom()
```

Schnelles Wischen von unten nach oben

```python
d().fling_from_bottom_to_top()
```
Schnelles Wischen von links nach rechts
```python
d().fling_from_left_to_right()
```
Schnelles Wischen von rechts nach links

```python
d().fling_from_right_to_left()
```

```{attention}
In einfachen Fällen muss für diese Operation kein Selektorparameter angegeben werden. Wenn jedoch ein Wischen nicht möglich ist, setzen Sie bitte die Selektorbedingung auf ein geeignetes Element, zum Beispiel ein Element mit dem Attribut `scrollable` oder den Container der ersten Ebene einer Liste.
```

```python
>>> element = d(resourceId="com.tencent.news:id/important_list_content")
>>> element.fling_from_bottom_to_top()
True
```

Wird aktualisiert...

## Weitere Operationen

```python
# Diese APP in den Ordner „Einkaufen“ ziehen (je nach tatsächlicher Situation anpassen)
element.drag_to(Selector(text="购物"))

#########
# Gleichgeordnete oder untergeordnete Elemente finden
#########
# Manchmal gibt es doppelte Elemente oder Elemente ohne klare Merkmale, die schwer zu lokalisieren sind
# In diesem Fall können Sie den Suchbereich eingrenzen, indem Sie nach untergeordneten/gleichgeordneten Elementen suchen
# Untergeordnete Elemente, Beispiel: In einem Chat-Anmeldeformular sind die Eingabefelder untergeordnete Elemente des Anmeldeformulars
# Gleichgeordnete Elemente, Beispiel: Das Benutzername- und das Passwortfeld in einem Chat-Eingabefeld sind (normalerweise) gleichgeordnete Elemente
form = d(resourceId="login_form")
form.child(index=1)
# Dies ruft das Element mit dem Index 1 unter login_form ab
form.child(index=1).sibling()
# Sie können auch so nach der Schaltfläche „Passwort vergessen“ suchen, die auf derselben Ebene wie login_form liegt
# (Eigentlich kann dies bereits durch eine Zeichenfolgenprüfung erfolgen, dies ist also nicht notwendig, hier nur zur Demonstration)
form.sibling(textContains="找回密码")
# Sie sind selbst ein Element, Sie können jede Element-Operation darauf anwenden


# Sonstiges, kontinuierlich nach unten/links/rechts/oben wischen, bis das Ende erreicht ist
# Da es nicht immer möglich ist, bis zum Ende zu wischen oder das Erreichen des Endes zu erkennen
# ist der Parameter max_swipes erforderlich
d().fling_from_top_to_bottom_to_end(max_swipes=32)
d().fling_from_bottom_to_top_to_end(max_swipes=32)
d().fling_from_left_to_right_to_end(max_swipes=32)
d().fling_from_right_to_left_to_end(max_swipes=32)

#########
# scroll: Eher mechanisches Wischen
#########
step = 60
max_swipes = 32
# Wischt step Schritte von oben nach unten
d().scroll_from_top_to_bottom(step)
# Wischt step Schritte von unten nach oben
d().scroll_from_bottom_to_top(step)
# Wischt step Schritte von links nach rechts
d().scroll_from_left_to_right(step)
# Wischt step Schritte von rechts nach links
d().scroll_from_right_to_left(step)

# Sonstiges, kontinuierlich nach unten/links/rechts/oben wischen, bis das Ende erreicht ist
# Wie oben bei fling beschrieben
d().scroll_from_top_to_bottom_to_end(max_swipes, step)
d().scroll_from_bottom_to_top_to_end(max_swipes, step)
d().scroll_from_left_to_right_to_end(max_swipes, step)
d().scroll_from_right_to_left_to_end(max_swipes, step)
```