Zurück zum Content

Popup-Menü mit Cut/Copy/Paste in Java

“Das kann doch nicht so schwer sein!” mag man sich denken und durchforstet stundenlang die Java-Docs. Wieso gibt es keine einfache Methode ein Popup-Menü mit Optionen zum Ausschneiden, Kopieren und Einfügen zu erstellen? Leider hilft auch das, bei vielen anderen Fragen rund um die Java-Programmierung sehr nützliche, Java-Tutorial irgendwie nicht richtig weiter. Eine Google-Suche fördert ausschließlich Code ans Tageslicht, der sofort einen Ehrenplatz im Giftschrank bekommt. Es hilft alles nichts: Man muss eine eigene, möglichst einfache Lösung basteln. Los geht’s!

Ich werde exemplarisch ein Popup-Menü für JTextFields erstellen. Natürlich kann man die Lösung noch weiter optimieren, sie lässt sich jedoch auch ohne Probleme unverändert verwenden.
Wir machen uns die Tatsache zunutze, dass JTextField (wie übrigens auch JEditorPane und JTextArea) die Klasse JTextComponent erweitert. Dadurch erben wir direkt die Methoden cut(), copy() und paste(). Wie praktisch 🙂
Außerdem ist natürlich jedes JTextField auch eine JComponent und erbt somit die Methode setComponentPopupMenu(JPopupMenu popup).
Wenn wir nun also ein geeignetes JPopupMenu zur Verfügung stellen, welches auf dem entsprechenden JTextField cut()/copy()/paste() aufruft, haben wir unser Ziel erreicht.
Nichts leichter als das. Als erstes werden wir für jede Aktion den passenden Menü-Eintrag erstellen. Wir benötigen also drei JMenuItems.
Zuerst der Menüpunkt zum Ausschneiden:

private static JMenuItem getMntmAusschneiden() {
  final JMenuItem mntmAusschneiden = new JMenuItem("Ausschneiden");
  mntmAusschneiden.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
	  ((JTextComponent) cutCopyPastePopup.getInvoker()).cut();
    }
  });
  return mntmAusschneiden;
}

Bei cutCopyPastePopup handelt es sich übrigens um unser JPopupMenu, welches wir zur besseren Wiederverwendbarkeit als Variable definiert haben. Um eine ClassCastException zu vermeiden könnte man noch überprüfen, ob getInvoker() wirklich eine JTextComponent zurückgibt.

Das Kopieren- und das Einfügen-Menü sind nach dem gleichen Muster aufgebaut:

private static JMenuItem getMntmKopieren() {
  JMenuItem mntmKopieren = new JMenuItem("Kopieren");
  mntmKopieren.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
      ((JTextComponent) cutCopyPastePopup.getInvoker()).copy();
    }
  });
  return mntmKopieren;
}
private static JMenuItem getMntmEinfgen() {
  JMenuItem mntmEinfgen = new JMenuItem("Einfügen");
  mntmEinfgen.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
      ((JTextComponent) cutCopyPastePopup.getInvoker()).paste();
    }
  });
  return mntmEinfgen;
}

Diese Methoden benutzen wir nun beim Zusammenbau unseres JPopupMenus:

public static JPopupMenu buildCutCopyPaste() {
  final JPopupMenu popupMenu = new JPopupMenu();
  final JMenuItem mntmAusschneiden = getMntmAusschneiden();
  final JMenuItem mntmKopieren = getMntmKopieren();
  final JMenuItem mntmEinfgen = getMntmEinfgen();
  popupMenu.add(mntmAusschneiden);
  popupMenu.add(mntmKopieren);
  popupMenu.add(mntmEinfgen);
  return popupMenu;
}

Vom Prinzip her sind wir hier schon fertig. Wir wollen jedoch das Verhalten des Menüs noch ein klein wenig anpassen. So wäre es schön, wenn die Menüpunkte zum Ausschneiden und Kopieren deaktiviert sind, falls kein Text im entsprechenden JTextField markiert wurde. Außerdem macht der Menüpunkt Einfügen bei einer leeren Zwischenablage keinen Sinn. Diese Überprüfungen werden wir jedes mal vornehmen, wenn das Menü angezeigt wird. Hierfür benötigen wir noch einen PopupMenuListener:

popupMenu.addPopupMenuListener(new PopupMenuListener() {
    @Override
    public void popupMenuCanceled(PopupMenuEvent e) {
      // Who cares? We don't, because we don't need it.
    }
    @Override
      public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        // Who cares? We don't, because we don't need it.
    }

    @Override
    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
      JTextComponent jtc = (JTextComponent) popupMenu.getInvoker();
      boolean enableCutCopy =
        (jtc.getSelectionEnd() - jtc.getSelectionStart()) > 0;
      boolean enablePaste =
        Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null) != null;
      mntmAusschneiden.setEnabled(enableCutCopy);
      mntmKopieren.setEnabled(enableCutCopy);
      mntmEinfgen.setEnabled(enablePaste);
    }
  });

Fertig ist das JPopupMenumit Ausschneiden, Kopieren und Einfügen. Viel Spaß damit 🙂Screenshot

2 Comments

  1. alex alex

    bei mir nimmt der die zeile mit dem jtc.getSelectionEnd() als fehler an wegen dem &gt und der 0 hab alles ausprobiert ohne lösung

    • DaJunkie DaJunkie

      Der Code ist auch nicht vollständig. Das > soll natürlich ein ‘größer’, also > darstellen. Das wurde beim copy/pasten nach WordPress nicht korrekt übernommen. Ich schau mir das Posting nochmal genauer an, um eventuell Fehler auszubügeln. Interesse am funktionierenden Code-Beispiel?

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *