Was ist Falsch, Java-Swing?
Hallo,
Möchte, dass wenn man auf "Schreiben" klickt zum ActionListener kommt und dann auf einen neuen JFrame seinen Text schreiben kann, aber irgendwie geht das nicht, funktioniert das mit den Parametern nicht ?
- Klasse (beinhaltet main)
package Swing;
import javax.swing.*;
public class Menubar {
static JMenuItem item1, item2, item3; // 2 Items für Menü
public Menubar() {
String text;
JFrame frame = new JFrame("Fenstertext");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null); // Mitte
frame.setLayout(null);
frame.requestFocus();
JMenuBar bar = new JMenuBar();
JMenu menu = new JMenu("Datei");// Bekommt Items, Beispiel auf File klicken ist Menu,namens "Datei" darunter dann Item
item1 = new JMenuItem("Neu"); // 1. Itemname
item1.addActionListener(new MenuHandler());
item2 = new JMenuItem("Beenden");
item2.addActionListener(new MenuHandler());
item3 = new JMenuItem("Schreiben");
item3.addActionListener(new MenuHandler());
menu.add(item1);
menu.addSeparator(); // Strich für Abtrennung (organisierter)
menu.add(item2);
menu.addSeparator();
menu.add(item3);
bar.add(menu); // Menu zu Bar hinzufügen
frame.setJMenuBar(bar); // Setzen, da nur eine bar...
frame.setVisible(true);
}
public static void main(String[] args) {
new Menubar();
}
}
2 Klasse :
package Swing;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Scanner;
public class MenuHandler implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// WAS SOLL PASSIEREN ?
if (e.getSource() == Menubar.item1) { // Ein bestimmtes Item ?
System.out.println("Neu...");
} else if (e.getSource() == Menubar.item2) {
System.exit(0); // Programm beenden
} else if (e.getSource() == Menubar.item3) {
JFrame neuer = new JFrame();
File file1 = new File("src/textSpeichern.txt");
neuer.setSize(800, 600);
neuer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
neuer.setResizable(false);
neuer.setLocationRelativeTo(null); // Mitte
neuer.setLayout(null);
neuer.requestFocus();
neuer.setVisible(true);
System.out.println("Was möchtest du schreiben?");
Scanner scanner = new Scanner(System.in);
String as = scanner.next();
JPanel panel = new JPanel();
JLabel label = new JLabel(as);
panel.add(label);
neuer.add(panel);
}
}
}
Warum geht das nicht ???
Danke für die Antworten bzw. die Hilfe ! :)
1 Antwort
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.
- 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.
- 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);
});
}
}
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.
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.
Wofür schreibst du immer „var“?