1. Speichere dein Projekt (Projekt > Speichern unter).
  2. Den erzeugten Projektordner kannst du zu einer ZIP komprimieren. Entweder mit einem extra Programm (wie 7zip oder WinRAR) oder den Funktionen deines Betriebssystems (Windows, MacOS).
  3. Die erzeugte ZIP-Datei schickst du an deinen Lehrer. Er kann den Ordner entpacken und bei sich in BlueJ öffnen (Projekt > Fremdprojekt öffnen).
...zur Antwort

Dem Issue Tracker zufolge wurde das Problem mit Version 2021.2 behoben.

...zur Antwort

Das lässt sich mit CSS und einem Gradient-Effekt (für das background-Property) bewerkstelligen.

<!doctype html>
<head>
  <title>Rainbow</title>
  <style>
    body {
      background: linear-gradient(
        90deg,
        rgba(255, 0, 0, 1) 0%,
        rgba(255, 155, 0, 1) 10%,
        rgba(210, 220, 30, 1) 20%,
        rgba(80, 220, 75, 1) 30%,
        rgba(65, 220, 220, 1) 40%,
        rgba(50, 200, 230, 1) 50%,
        rgba(30, 130, 240, 1) 60%,
        rgba(90, 20, 240, 1) 70%,
        rgba(185, 10, 250, 1) 80%,
        rgba(250, 7, 220, 1) 90%,
        rgba(255, 0, 0, 1) 100%
      );
    }
  </style>
</head>
<body>
  <!-- your content ... -->
</body>
...zur Antwort

Wie erstelle ich einen Confirmation Dialog mit JavaFX?

Guten Abend zusammen,

seit ziemlich langer Zeit sitze ich an einer Aufgabe und komme nicht weiter.

Wer kann mich unterstützen? Ich möchte nur den Dialog anzeigen lassen und auswerten. Das war es. Es schien leicht, ist es aber für mich aktuell nicht. :/

Folgende Aufgabenstellung:

Erstellen Sie einen universellen Dialog für JavaFX, in dem der Anwender eine beliebige Frage mit Ja oder Nein beantworten kann. Leiten Sie dazu eine eigene Klasse von der Klasse Alert ab. Die Texte im Dialog sollen über Argumente festgelegt werden.

Stellen Sie sicher, dass Sie die Antwort des Anwenders in Ihrem Code auswerten können. Der Dialog muss also einen Rückgabewert zur Verfügung stellen. Wie Sie dabei vorgehen, ist Ihnen freigestellt.

Ob Sie für die Lösung den neuen Dialog in den Editor aus diesem Studienheft einbauen oder eine eigene Anwendung erstellen, die nur den Dialog anzeigt und die Rückgabe auswertet, ist Ihnen freigestellt.

Einige Hinweise zur Lösung:

Einen Standarddialog für eine Bestätigung erhalten Sie mit dem Typ AlertType.CONFIRMATION.

Den Text in der Titelleiste des Dialogs können Sie über die Methode setTitle() festlegen.

Die Schaltflächen im Dialog können Sie über den Konstruktor festlegen. Dazu übergeben Sie Argumente vom Typ ButtonType. Der Wert ButtonType.YES steht zum Beispiel für eine Schaltfläche mit dem Text „Ja“ und der Wert ButtonType.NO für eine Schaltfläche mit dem Text „Nein“.

Die angeklickte Schaltfläche erhalten Sie über die Methode getResult(). Sie liefert einen Wert vom Typ ButtonType zurück.

Bei mir sieht es bisher so aus:

package universellerDialogJavaFX;

import javafx.event.ActionEvent;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;

public class UniversellerDialog extends Alert {
  public UniversellerDialog(AlertType alertType, String DialogText, String titel, ButtonType buttonType1, ButtonType buttonType2) {
    super(alertType);
    super.setTitle(titel);
    super.setContentText(DialogText);
    super.getButtonTypes().setAll();
    super.showAndWait();
  }

  public void buttonReaktion(ActionEvent event) {
    if (super.getResult() == ButtonType.YES)
      super.setContentText("Dann hast du alles richtig gemacht - weiter so");
    else
      super.setContentText("Dann solltest du heute bewussst etwas tun, was dich glücklich macht!");
  }
}

Und die main, an welche ich die Argumente dann übergebe:

package universellerDialogJavaFX;

import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;

public class DialogMain {
  public static void main(String[] args) {
    new UniversellerDialog(AlertType.CONFIRMATION,"Eine kurze Frage: Bist du heute glücklich?", "Wichtige Frage", ButtonType.YES, ButtonType.NO);
  }
}
...zur Frage

Deine Alert-Klasse beinhaltet derzeit mehr, als sie benötigt. Folgender Code reicht vollkommen aus (ich nutze hierbei englische Bezeichner, wie du es halten möchtest, sei dir überlassen):

public class UniversalAlert extends Alert {
  public UniversalAlert(String message, String title) {
    super(AlertType.CONFIRMATION, message, new ButtonType("Ja", ButtonType.YES.getButtonData()), new ButtonType("Nein", ButtonType.NO.getButtonData()));
    setTitle(title);
  }
}

Da die beiden Buttons im Dialog mit Ja/Nein beschriftet werden sollen, müssen neue ButtonType-Objekte angelegt werden. Diese nutzen die selben Button-IDs (jeder Button kann anhand seines ButtonData-Werts im Typ identifiziert werden) wie ihre englischen Ableger YES und NO.

Die Auswertung der Nutzereingabe erfolgt überlicherweise außerhalb:

var alert = new UniversalAlert(/* ... */);
var result = alert.showAndWait();

if (result.orElse(ButtonType.NO).getButtonData().equals(ButtonType.YES.getButtonData())) {
  // yes ...
}
else {
  // no ...
}

Die Variable result ist hierbei vom Typ Optional<Button>. Das heißt, es handelt sich um ein Wrapperobjekt, welches einen Button enthalten könnte. In der Prüfung mit if wird das Buttonobjekt aus diesem Wrapper herausgeholt oder, falls kein Buttonobjekt existiert (dies wäre ein Fehlerfall), ein NO-Button herangezogen. Dessen ButtonData wird mit dem eines YES-Buttons verglichen. Wenn der Vergleich nicht passt, hat der Nutzer entweder auf Nein gedrückt, es kam wie geschrieben zu einem Ausnahmefall oder der Dialog wurde über den Close-Button geschlossen.

Diesen Auswertungsprozess könnte man noch in eine eigene Methode verlagern. Als Rückgabetyp reicht ein boolscher Typ oder du legst dir eine extra Enumeration dazu an.

public boolean showAndGetResult() {
  // ...
}

Und noch kompakter wäre es, wenn der Aufrufer keine explizite Instanz des Dialogs erstellen, sondern nur die Methode aufrufen müsste.

public class UniversalAlert extends Alert {
  protected UniversalAlert(String message, String title) {
    // ...
  }
  
  public static boolean showAndGetResult(String message, String title) {
    var alert = new UniversalAlert(message, title);
    // ...
  }
}

// call:
if (UniversalAlert.showAndGetResult(/* ... */)) {
  // ...
}
else {
  // ...
}
...zur Antwort

Vergib in deinem Formular je Feld den richtigen input-Typ und setze das required-Attribut.

<form name="form">
  <input required>
  <input type="email" required>
  <button id="send" type="button">Send</button>
</form>

Der Button bekommt einen Event Listener für das Klickereignis angehängt. Er durchläuft alle Felder und prüft auf ihre Validität. Wenn alle Felder valid sind, kann eine Ausgabe erfolgen.

document.getElementById("send").addEventListener("click", e => {
  const fields = document.forms["form"].elements;

  for (const field of fields) {
    if (!field.checkValidity()) {
      return;
    }
  }

  alert("Correct");
})
...zur Antwort

Richtig sieht es m.E. nicht aus.

  1. Die Variable sollte doch eher umrunden heißen. Wieso wird sie eigentlich für huegelVorhanden benötigt?
  2. Die huegelVorhanden-Methode verspricht vom Namen her, dass sie nur die Information liefert, ob ein Hügel (vor dem Rover?) vorhanden ist. So lange das der Fall ist, kannst du den Rover doch nicht geradeaus weiterfahren lassen.
  3. Die Variable gesteinVorhanden wird nirgendwo gesetzt. Wäre es stattdessen eine Funktion, die da aufgerufen wird, wäre es eher verständlich.
  4. Sind denn alle deiner genutzten Elemente (Variablen/Funktionen) irgendwo definiert? Das würde ich an deiner Stelle noch einmal prüfen.
...zur Antwort

Wenn du ein Bild um einen negativen Faktor skalierst, kannst du es spiegeln.

scale(-1, 1);
image(yourImage, -widthOfYourImage, 0);
...zur Antwort

So wie es aussieht, wird ein Spieler in deinem Spiel durch verschiedene Eigenschaften definiert (Farbe, Gesamtpunktezahl, ...). Dementsprechend würde ich wohl auch einen eigenen Typ anlegen.

Class Player
  Public Property Points As Integer
  Public Property TextBox As TextBox
  ' etc. ...

Für das Spiel könnte man sich ein Array anlegen, welches alle Spieler bündelt.

Private currentPlayer As Integer = 0

Private players(3) As Player

Public Sub New()
  For index As Integer = 0 To players.Length - 1
    players(index) = New Player
  Next

  players(0).TextBox = Player1TextBox
  players(1).TextBox = Player2TextBox
  players(2).TextBox = Player3TextBox
  players(3).TextBox = Player4TextBox
End Sub

Der Vorteil dieser beiden Maßnahmen wäre, dass du nicht mehr mit mehreren nummerierten Variablen (Punkte1, Punkte2, u.ä.) arbeitest, sondern nur noch Array und Index bräuchtest, um Eigenschaften für einen Spieler zu definieren.

Beispiel:

players(2).TextBox.BackColor = Color.Salmon

Hier würde vom dritten Spieler die Farbe seiner Textbox gesetzt werden.

Die Tatsache, dass der Index dynamisch berechnet werden kann, hilft beim Spielerwechsel. Das oben definierte Feld currentPlayer dient folgend dazu, bei jedem Zug den aktuellen Spieler zu erhalten.

Dim player As Player = players(currentPlayer)

Am Ende eines jeden Zugs wird dessen Wert um 1 erhöht, sodass bei der nächsten Spielerabfrage das nächste Element aus dem Array gewählt wird. Sollte der Wert über die Arraylänge hinauskommen, muss er wieder auf 0 gesetzt werden.

currentPlayer += 1

If currentPlayer = players.Length Then
  currentPlayer = 0
End If
...zur Antwort

Ich denke, dass du dein Problem noch immer mit CSS lösen kannst. Schachtel deine HTML-Struktur an der Stelle.

<div id="c">
  <div>
    <!-- your content ... -->
  </div>
</div>

Die äußere Box nimmt die Verschiebeanimation vor und die innere die Rotation.

#c {
  /* ... */
  animation: hei 5s 1 0s linear forwards;
}

#c > div {
  animation: rotate 5s 1 5s;
}

Bei JavaScript-Animationen würde ich an deiner Stelle erst überlegen, ob es sich um eine Aktion im DOM handeln soll oder ob es nicht sinnvoller wäre, sie auf einem canvas-Element (siehe Canvas API) zu produzieren.

Bei einer Aktion im DOM kann man die setInterval-Funktion nutzen.

setInterval(function() {
  /* one animation step ... */
}, 1000);

Das zweite Argument definiert die Dauer eines Intervalls. Die Einheit beträgt hierbei Milisekunden, wobei 1000ms genau eine Sekunde ergeben.

Ein Dokument mit rotierender Box könnte so aussehen:

<!doctype html>
<head>
  <title>Example</title>
  <style>
  #box {
    background: red;
    height: 50px;
    width: 50px;
  }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    function rotate() {
      const box = document.getElementById("box");
      let rotation = 0;
      setInterval(function() {
        box.style.transform = `rotate(${rotation}deg)`;
        rotation = ++rotation > 360 ? 0 : rotation;
      }, 10);
    }
    rotate();
  </script>
</body>

Doch auch hier würde ich eine Verschachtelung im HTML vornehmen, damit sich CSS-Animation und Skript nicht beim Definieren des transform-Property überschneiden.

...zur Antwort

An deinem Selektor und dem Tag liegt es offensichtlich nicht (das height-Property kannst du übrigens weglassen, denn auto ist bereits der Standardwert).

Öffne zunächst die Webentwicklungstools deines Browsers, selektiere das img-Element im Selektor und schau nach, ob dein Selektor unter den Styles mit gelistet wird. Wenn ja, siehst du auch, ob deine Properties zum Einsatz kommen oder (wenn sie bspw. durchgestrichen sind) von anderen Properties überschrieben werden. In dem Fall benötigt dein Selektor eine höhere Spezifität.

Wenn du deinen Selektor nicht aufgelistet bekommst, wäre es an der Zeit, zu prüfen, ob dein CSS überhaupt in das Dokument geladen wird. Solltest du also eine externe CSS-Datei verwenden, ist sie entweder nicht im head-Bereich (über einen link-Tag) eingebunden oder konnte gar nicht erst gefunden werden. Die Browserkonsole informiert über gescheiterte Requests, du kannst aber auch im Network-Tab der Webentwicklungstools nachschauen, auf welche Requests dein Browser welche Antwort empfangen hat (Network-Tab öffnen, Seite neuladen).

Überprüfe in der Hinsicht die von dir angegebene URL. Achte auf eine korrekte Groß- und Kleinschreibung. Die CSS-Datei muss auf .css enden. Aktiviere in Windows also erst noch die Anzeige der Dateinamenserweiterung, falls nicht bereits getan.

Weitere mögliche Fehlerursachen:

  • Du hast deinen aktuellen Stand der CSS-Datei oder der HTML-Datei noch nicht gespeichert.
  • Du lässt dir die falsche Webseite im Browser anzeigen.
  • Dein Browser liefert dir einen gecacheten Zustand. Lade die Seite mit Ctrl + F5 neu oder leere explizit den Seitencache vor einem Neuladen.
...zur Antwort

a) Verwende einen anderen Datentyp für den Zähler. Mit long kannst du einen positiven Zahlenbereich bis 9 223 372 036 854 775 807 abbilden, mit ulong noch einmal ungefähr das Doppelte.

b) Ab einer bestimmten Zahlengröße macht es Sinn, nicht mehr die unteren Stellen (Zehner, Hunderter, Tausender) explizit anzuzeigen. Das heißt, du kannst deinen Zähler auf die noch relevanten Stellen verkürzen und den Wert, den du jeweils addierst, runden. Der Spieler dürfte davon eh nicht mehr viel mitbekommen.

...zur Antwort

Entweder du verarbeitest den Wert als String, der zeichenweise aufgetrennt wird oder du gehst mathematisch vor. Mit einer ganzzahligen Division mit Rest lässt sich eine Zahl so aufspalten:

1234 % 10 = 4
1234 % 100 = 34
1234 % 1000 = 234

Das dürfte als Tipp genügen.

Über den Aufbau eines Programmablaufplans kannst du dich hier informieren. Der PapDesigner ist dabei ein hilfreiches Tool.

...zur Antwort

Du wirst eine Funktion haben, die dir deine Tabellenreihen ausgibt. Zum Beispiel:

renderTableRows(data) {
  return someData.map((person, index) => {
    return (
      <tr>
        <td>{person.name}</td>
        <td>{person.age}</td>
        <td><button data-id={person.id} onClick={this.removeEntry}>Remove</button></td>
      </tr>
    );
  });
}

In der gibst du einfach nur deinen Button mit aus und fügst ein onClick-Attribut auf ihm hinzu. Dazu brauchst du noch die Funktion, die dort gebunden wird:

removeEntry = () => {
  const personId = e.target.getAttribute("data-id");
  /* do something ... */
}

In dieser könntest du vom Button (dieser ist das angeklickte Element: target) den Wert des data-Attributs einholen. Ob du da nun eine ID hineingibst oder irgendeinen anderen Wert, ist dir überlassen. Hauptsache es ist ein Wert, an dem du die Datenzeile in deiner Datenliste (im obigen Snippet someData) eindeutig identifizieren kannst. Dann kannst du in ihr nämlich nach den Eintrag suchen und ihn herauslöschen.

...zur Antwort

Python: Kleinsten Wert mit dem größten Wert innerhalb einer Liste tauschen?

Ich habe folgende Methode:

def tausche_wertung(bester_Termin):
       bester_Termin[min], bester_Termin[max] = bester_Termin[max], bester_Termin[min]
       return bester_Termin

Dabei ist "bester_Termin" ein Ergebnis aus einem folgendem Code, der also immer unterschiedlich ausfällt (gearbeitet wurde mit datetime):

print("Bitte geben Sie die Namen oder Bezeichnungen der Mitglieder ein, die zum Treffen kommen sollen (Anmerkung: mit Komma getrennt)")
mitglieder = [name.strip() for name in input().split(",")]

print("Bitte geben Sie die mögliche Termine ein (Anmerkung: mit Komma getrennt und im Format TT.MM.JJJJ)")
termine = [[datetime.strptime(datum.strip(),"%d.%m.%Y"),0] for datum in input().split(",")]


for mitglied in mitglieder:
   for termin in termine:
       termin[1] += int(input(f"Wie gut passt {termin[0]:%A, der %d.%m.%Y} für {mitglied}? (0 = passt gut, 1= passt mäßig, 2 = passt schlecht oder beispielsweise in Noten): "))
   print()

# Den Durchschnitt aller Termine auflisten.
print("Durchschnitt pro Termin:")
for termin in termine:
   print(f"{termin[0]:%A, der %d.%m.%Y}: {termin[1]/len(mitglieder):.2f}")

# Den best-passendsten Termin raussuchen. Anmerkung: Wenn es mehrmals den gleichen Durchschnitt gibt, wird der früheste Termin ausgeben.
bester_Termin = min(termine, key=lambda termin:termin[1])

Als beispiel-print kommt folgendesheraus:

[datetime.datetime(3, 1, 1, 0, 0), 3]

In diesem Fall, war der dritte Termin der beste und die 1 war die kleinste Eingabe der 1. Person für irgendeinen Termin, die zweite 1 war die kleinste Eingabe der 4. Person, wieder für irgendeinen Termin und die beiden 0en waren von Person 2. und 3. schon für den dritten Termin eingeben und automatisch der kleinste Wert.

Die Liste wird also von Groß zu Klein aufgelisten sehe ich das richtig? Denn die vorliegende Liste wäre hier quasi [Person1., Person 4., Person 2., Person 3.] und nicht von 1-4 aufwärts?

Ausgabe:

Mein Ziel ist es erstmal die Werte für den besten Termin nur mit einer anderen Eingabe zu tauschen, wenn nicht bereits die kleinste Wertung für den Termin vorliegt. Das ist hier ja bereits gegeben, wenn ich es richtig sehe, denn die beiden 0en bleiben gleich.

Anschließend will ich, dass das Programm ausgibt wie oft ein Wechsel der Bewertung möglich ist, d.h. wenn es bereits die kleinste bzw. beste Wertung ist (0 ist hier die beste) wird nicht getauscht, ebenso wenn es nicht möglich ist, da alle Wertungen gleich waren o.ä.

Und dann soll das Programm, wenn möglich, noch ausgeben bei welchem Mitglied getauscht wurde, in diesem Fall bei Person 1.

Erläuterung Anhand Beispiel:

Mittwoch, der 01.01.0003 Termin ist der passendste, und Person 1 hat da eine 2, welche man mit der 1 der Wertung des ersten Termins tauschen kann.

Wunschprint: Es ist ein Wechsel der Bewertung möglich, und das bei Person 1

oder noch besser aber kein Zwang, wenn es zu kompliziert ist:

Es ist der Wechsel der Wertung des 3. mit der des 1. Termins bei Person 1 möglich.

...zur Frage
Die Liste wird also von Groß zu Klein aufgelisten sehe ich das richtig?

Die Elemente der Liste werden in der Reihenfolge ausgegeben, wie du sie eingetragen hast. Sofern du keine explizite Sortierung vornimmst, erfolgt auch keine.

Ich habe den Eindruck, dass du die Ausgabe falsch wertest. Die ausgegebene Liste besteht bei dir aus einem Datumsobjekt: datetime.datetime(3, 1, 1, 0, 0) und einer Zahl (der Summe aller Bewertungen): 3.

Mein Ziel ist es erstmal die Werte für den besten Termin nur mit einer anderen Eingabe zu tauschen, wenn nicht bereits die kleinste Wertung für den Termin vorliegt.

Da du dir nur die Summe aller Bewertungen je Datum merkst, ist aktuell keine Trennung nach Nutzereingabe möglich.

Es wäre wohl besser, wenn du dir alle Eingaben sicherst und erst später auf ihrer Grundlage herumrechnest. Man könnte sich für eine Bewertung einen Typ anlegen:

class Bewertung:
  def __init__(self, mitglied, wert = -1):
    self.mitglied = mitglied
    self.wert = wert

# example usage
bewertung1 = Bewertung("Max")
bewertung1.wert = 0
bewertung2 = Bewertung("Moritz")
bewertung2.wert = 1

und für die Terminbewertungen ein Dictionary.

termin_bewertungen = {}

Als Keys können die Daten eingetragen werden, als Wert speicherst du eine Liste an Bewertungsobjekten. Eine andere Option (statt einem Dictionary) wäre ein weiterer Typ:

class Terminbewertung:
  def __init__(self, datum):
    self.datum = datum
    self.bewertungen = []

Der könnte später passenderweise auch mit den Methoden erweitert werden, die die Berechnungen vornehmen (z.B. Berechnung des Durchschnitts).

Der Einfachheit halber würde ich zudem die Werteskala umdrehen: Hohe Werte stehen für mehr Zustimmung als niedrige. Werte mt -1 (Standardwert) sollten nicht in die Rechnung mit einbezogen werden.

Nach Eingabe aller Werte könntest du jedenfalls leicht über alle getätigten Bewertungen eines bestimmten Datums laufen und schauen, inwiefern noch ein Tausch möglich ist. Ebenso kannst du dir mit Schleifen neue Konstellationen zusammenstellen. Zum Beispiel alle Bewertungen einer Person heraussuchen:

bewertungen_mitglied1 = {}

for terminbewertung in terminbewertungen:
  for bewertung in terminbewertung.bewertungen:
    bewertungen_mitglied1[terminbewertung.datum] = bewertung.wert
...zur Antwort

Can't import image?

Hallo,

ich erstelle gerade einen kleinen Algorithmus, bei dem man ein Bild einfügt, welches dann anhand der Stärke der Pixel in Graustufen eingeteilt wird und dann das Bild in einer anderen Art ausgibt.

Ich nutze zum Lesen der Bilder das PIL-Modul.

Ich bin eigentlich schon fast fertig, aber da kommt die Fehlermeldung, dass das Modul etwas nicht importieren kann.

Schaut es euch selbst an:

Microsoft Windows [Version 10.0.19043.1237]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\User\AppData\Local\Programs\Algoritmika\vscode\data\extensions\algoritmika.algopython-20211015.95910.0\temp>C:/Users/User/AppData/Local/Programs/Algoritmika/algovenv/Scripts/activate.bat
(algovenv) C:\Users\User\AppData\Local\Programs\Algoritmika\vscode\data\extensions\algoritmika.algopython-20211015.95910.0\temp>cd c:/Users/User/OneDrive/Dokumente/Soundaufnahmen
(algovenv) c:\Users\User\OneDrive\Dokumente\Soundaufnahmen>C:/Users/User/AppData/Local/Programs/Algoritmika/algovenv/Scripts/python.exe c:/Users/User/OneDrive/Dokumente/Soundaufnahmen/test.py
Traceback (most recent call last):
 File "c:/Users/User/OneDrive/Dokumente/Soundaufnahmen/test.py", line 1, in <module>
  from PIL import image
ImportError: cannot import name 'image' from 'PIL' (C:\Users\User\AppData\Local\Programs\Algoritmika\algovenv\lib\site-packages\PIL\__init__.py)
(algovenv) c:\Users\User\OneDrive\Dokumente\Soundaufnahmen>

Falls ihr auch Fehler beim Code seht, könnt ihr es mir auch gern mitteilen, da ich noch ziemlich neu bin.

...zur Frage

Der Import für Image lautet:

from PIL import Image

Stelle des Weiteren sicher, dass du das Pillow-Modul installiert hast und nicht PIL. Es handelt sich dabei um einen Fork des PIL-Projekts, welches schon seit langer Zeit nicht mehr weiterentwickelt wird.

Solltest du PIL installiert haben, deinstalliere es zunächst und installiere stattdessen Pillow.

pip uninstall PIL
pip install Pillow
...zur Antwort

Eine Möglichkeit:

soup = BeautifulSoup(html)
value = soup.find("input", { "name": "random_id" }).get("value")
...zur Antwort
Wie lange wird Java Swing GUI nicht mehr weiterentwickelt?

Beziehst du dich auf das Toolkit oder das Designertool von IntelliJ?

Zu Ersterem: Swing wird in der Entwicklung von Java noch immer berücksichtigt. In der letzten Client Roadmap von Oracle (Mai 2020) heißt es:

Oracle will continue developing Swing and AWT across all supported releases as a core Java SE technology.

Quelle (siehe Seite 6, letzter Satz)

Allerdings darfst du wohl kaum noch bahnbrechende Features erwarten. Es bezieht sich mehr auf den grundsätzlichen Support / Wartung (Beheben von Bugfixes, u.ä.). Mir wäre bspw. bekannt, dass seit Version 9 auf Linux GTK 3 für Swing unterstützt wird und mit der nächsten Version (17) dürfte die JApplet-Klasse endgültig aus dem SE verschwinden.

Hinsichtlich des Designertools würde ich dir empfehlen, die ausgegebenen Roadmaps von IntelliJ im Auge zu behalten. Grundsätzlich wirst du auch hier den normalen Support (Bugfixes, u.ä.) erwarten dürfen.

Oder ist Java Swing GUI gar nicht diese Funktion (Java Swing UI Designer) bei IntelliJ?

Das Designertool hilft dir, Oberflächen mit Swing-Komponenten zu kreieren.

Wird nicht auch gesagt, dass Swing GUI ein  Zombie ist?

Ja, solche Aussagen kannst du von einigen Entwicklern lesen/hören und da ist auch etwas dran. Java Swing selbst bekommt von Oracle nicht mehr die Aufmerksamkeit geschenkt, als dass es wieder zu einem modernen Toolkit avancieren würde. Es dümpelt insofern nur noch vor sich hin.

Eine Entwicklung findet wenn nur noch auf interner Ebene, als Teil proprietärer Software statt.

Das heißt, im produktiven Bereich kannst du durchaus noch auf Swing treffen. Ich hatte bereits vor einem halben Jahr etwas dazu geschrieben: Lohnt es sich noch, JavaFX oder Java Swing zu lernen?

Warum ist es soviel besser heutzutage  JavaFX zu verwenden?
  • JavaFX wird noch aktiv weiterentwickelt, auch in Richtung mobiler App-Programmierung.
  • Layouts anzulegen und sie passend zu stylen, ist einfacher. Modern wirkende GUIs bauen, ist einfacher.
  • JavaFX unterstützt sowohl eine konsistente MVC-Entwicklung, als auch eine MVVM-Architektur. Mit FXML und CSS kannst du die Anwendungslogik klarer von der Oberflächenimplementation trennen.
...zur Antwort

Es wäre angebracht, eine Schleife zur Lösung dieser Aufgabe heranzuziehen. Zum Beispiel for-do. Sie wiederholt ihren Rumpf so oft, wie es der Schleifenkopf vorgibt.

var
  attempt: integer;
  input: String;
  inputWasValid: Boolean = False;
begin
  for attempt := 1 to 3 do
    begin
      { ask for password ... }
      { check ... }
    end;
end;

Innerhalb des Rumpfs liest du die Eingabe des Nutzers und prüfst sie. Wenn das Passwort korrekt war, kannst du eine boolsche Variable auf True setzen und mit dem break-Befehl die Schleife sofort verlassen.

break;

Im Anschluss kannst du anhand des Zustandes der boolschen Variable herausfinden, ob sich der Nutzer innerhalb der vorgegebenen Anzahl an Versuchen anmelden konnte oder nicht.

...zur Antwort

Wenn du ein JSON-Array erwartest, musst du ein Array schicken:

$weekdays = array('Monday', 'Tuesday', /* ... */);
print json_encode($weekdays);

Ein JSON-Array kapselt seine Werte stets in eckige Klammern.

[ wert1, wert2, wert3, /* ... */ ]

Wenn du stattdessen ein JSON-Objekt schicken möchtest, solltest du stattdessen die getAsJSONObject-Methode zum Empfangen der Antwort verwenden.

/* make request ... */
  .getAsJSONObject(new JSONObjectRequestListener() {
    @Override
    public void onResponse(JSONObject response) {
      // ...
    }

    @Override
    public void onError(ANError error) {
      // ...
    }
  });

Eine dritte Option könnte es sein, das erhaltene Objekt / die erhaltenen Objekte direkt auf einen Java-Typ zu mappen.

Bei einem gelieferten Array an Objekten könnte das so aussehen:

/* make request ... */
  .getAsObjectList(YourType.class, new ParsedRequestListener<List<YourType>>() {
    @Override
    public void onResponse(List<YourType> data) {
      // ...
    }

    @Override
    public void onError(ANError anError) {
      // ...
    }
  });

Deine Klasse (hier: YourType) sollte im Aufbau dem JSON-Objekt entsprechen, welches in der Liste mitgeliefert wird. Angenommen, dies würde so aussehen:

[
  { "firstname": "Art", "lastname": "Garfunkel" },
  { "firstname": "Paul", "lastname": "Simon" }
]

Dann müsste dein Typ so aufgebaut sein:

public class YourType {
  String firstname;
  String lastname;
}

Wenn nur ein Objekt (statt einer Liste) geschickt wird, würde ein Mapping so aussehen:

/* make request ... */
  .getAsObject(YourType.class, new ParsedRequestListener<YourType>() {
    @Override
    public void onResponse(YourType data) {
      // ...
    }

    @Override
    public void onError(ANError anError) {
      // ...
    }
  });

Weiteres zu Objekt Mapping mit GSON kannst du hier nachlesen.

...zur Antwort