Was ist Falsch, Java-Swing?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Zuerst sollte ich wohl darauf eingehen:

frame.setResizable(false);
// ...
frame.setLayout(null);

Solltest du das so von einem Tutorial haben, kannst du es gleich postwendend in die Tonne werfen. Sofern die Option besteht, eine Bewertung abzugeben, bitte negativ.

  1. Du nimmst dem Nutzer die Möglichkeit, die Fenstergröße selbst anzupassen. Wenn deine Anwendung also bspw. auf einem kleineren Bildschirm ausgeführt wird, kann der Nutzer schnell auf Probleme stoßen.
  2. Indem du den Layout Manager rauswirfst, zwingst du dem Nutzer auch noch ein inflexibles Layout auf. Auf verschiedenen Bildschirmen kann es also dazu kommen, dass deine Elemente verschoben werden, übereinanderlappen oder gar nicht erst sichtbar auftauchen.

Verwende in Swing immer Layout Manager. Wenn du das als zu kompliziert empfindest: Ein paar Alternativen habe ich auch hier schon einmal aufgelistet.

Zu deinem Problem: System.in zeigt auf den Eingabekanal der Konsole bzw. der Scanner liest von der Konsole. Du hast allerdings ein GUI, demzufolge sollten Eingabe auch über die ablaufen. Verwende Eingabefelder wie JTextField oder JTextArea.

Minibeispiel:

import java.awt.*;
import javax.swing.*;

public class Main {
  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      var frame = new JFrame("Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setLayout(new GridLayout(3, 1));
      var inputField = new JTextField();
      var output = new JLabel();
      var button = new JButton("Click me");
      button.addActionListener(event -> output.setText(inputField.getText()));

      frame.add(inputField);
      frame.add(button);
      frame.add(output);
      frame.pack();
      frame.setVisible(true);
    });
  }
}
neleidd  05.12.2021, 17:15

Wofür schreibst du immer „var“?

0
regex9  05.12.2021, 17:18
@neleidd

Das Schlüsselwort var wird vom Compiler mittels Typinterferenz gegen den tatsächlichen Datentyp ausgetauscht und erlaubt somit eine Verkürzung des Programmcodes. Es handelt sich um ein Feature, das mit Java 10 eingeführt wurde.

1
regex9  05.12.2021, 18:06
@neleidd

Typinterferenz bezeichnet die Fähigkeit, anhand des links- oder rechtsseitigen Ausdrucks einer Zuweisung, den richtigen Typ für die gegenüberliegende Seite ermitteln zu können.

Dazu drei Beispiele:

1) Bei einer Zuweisung wie dieser:

var frame = new JFrame("Example");

kann der Compiler den Typ der Variable ableiten, indem er sich am rechtsseitigen Wert orientiert. Die Variable soll auf ein JFrame-Objekt zeigen, also muss sich auch ein JFrame sein.

2) Hier:

ArrayList<Integer> numbers = new ArrayList<>();

kann rechts die Angabe des generischen Typs weggelassen werden, da bereits durch die Typangabe auf der linken Seite klar ist, dass in die Liste nur Integer eingefügt werden dürfen.

3)

int[] numbers = { 1, 2, 3 };

Der Compiler leitet anhand der linksseitigen Typinformation ab, dass der rechtsseitige Ausdruck einem int-Array entspricht. Die Anzahl der Werte wird zudem als Größenangabe für das Array verwendet.

2
regex9  06.12.2021, 19:52
@neleidd

Das ist eine Lambda-Expession.

Vergleiche einmal diesen Code:

event -> output.setText(inputField.getText())

mit diesem:

public void actionPerformed(ActionEvent event) {
  output.setText(inputField.getText());
}

Dir dürfte auffallen, dass das erste Snippet eine ziemliche Verkürzung zum Zweiten darstellt. Name, Rückgabetyp, Zugriffsmodifikator - so einiges fehlt und nur die allerwichtigsten Informationen bleiben.

(Parameterliste) -> { Funktionskörper }

Java kann in diesem speziellen Fall (addActionListener) eine ziemlich große Menge an Code selbst vervollständigen. Die Langform würde normalerweise so aussehen:

button.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent event) {
    output.setText(inputField.getText());
  }
});

Die Methode erhält eine anonyme Klasse überreicht, die das Interface implementiert.

Da sich ein gültiges Objekt anhand nur dieser einen Pflichtimplementation von actionPerformed erkennen lässt, reicht ein Lambda-Ausdruck aus. Er muss lediglich die Parameterliste und den Rückgabetyp berücksichtigen.

button.addActionListener((ActionEvent event) -> {
  output.setText(inputField.getText());
});

Im zweiten Schritt kann man noch Klammern, das Semikolon sowie den Typnamen für den Parameter entfernen, denn die Parameterliste beinhaltet nur einen Parameter, bei dem der Typ klar ist (andernfalls würde das Interface ja nicht erfüllt werden) und der Methodenkörper beinhaltet nur eine einzige Anweisung.

button.addActionListener(event -> output.setText(inputField.getText()));

Neben der erheblichen Verkürzung gibt es noch die Besonderheit, dass man Variablen vom äußeren Kontext im Lambda-Ausdruck benutzen kann. Im obigen Fall sieht man das bei output und inputField.

Weiteres bzw. noch genauere Erklärungen kannst du im Java Oracle Tutorial nachlesen. Eventuell hilft auch das Kapitel Lambda-Ausdrücke und funktionale Programmierung aus dem OpenBook Java ist auch eine Insel.

0
orochi02  06.12.2021, 20:25
@neleidd

es ist sowas wie eine methode die du wie ein objekt behandeln kannst (in variablen speichern, an andere methoden übergeben, etc.)

0