Viele Benutzer eines Programms sind es gewohnt, das sie mit einem Klick auf die rechte Maustaste Editierbefehle auslösen können, welche in einem auftauchenden Fenster angeboten werden; Beispiele dafür sind die beliebten „copy and paste“ Befehle.
Dieser Artikel erläutert Euch, wie Ihr ein Popup-Menü in Euer Programm einbaut. So sieht später das fertige Programm aus:
Beim vorherigen Artikel (TextPane Menue) habe ich Euch das Konzept der Starterklasse vorgestellt und auf dieser Basis zeige ich Euch das Popup-Menü.
Alle notwendigen Programmierungen erledigen wir in der TextPane.java-Klasse. Wir legen ein Popup-Menü händisch analog zu einem Menü an (JPopupMenu und JMenuItem):
1 2 3 4 5 6 7 8 9 10 11 12 |
// for popup menu popupMenu = new JPopupMenu(); // add menu items to popupMenu JMenuItem menuItemCut = new JMenuItem("cut"); popupMenu.add(menuItemCut); JMenuItem menuItemCopy = new JMenuItem("copy"); popupMenu.add(menuItemCopy); JMenuItem menuItemPaste = new JMenuItem("paste"); popupMenu.add(menuItemPaste); popupMenu.addSeparator(); JMenuItem menuItemSelectAll = new JMenuItem("select all"); popupMenu.add(menuItemSelectAll); |
Dann verbinden wir die JTextPane über einen Mouse Listener mit dem Popup-Menü:
1 2 3 4 5 |
textPane.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent me) { showPopup(me); // showPopup() is our own user-defined method } }); |
Jeder Popup-Menüpunkt benötigt einen Action Listener, um auf den Klick zu reagieren. Da das Popup-Menü „in“ der JTextPane ausgelöst wird kann ich die natürlichen (oder bereits eingebauten) Aktionen dadurch starten, das ich Mausklicks simuliere (hier am Beispiel der Tastenkombination Ctrl-X für ausschneiden):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
menuItemCut.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // send key to textpane ctrl-x try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_CONTROL); robot.keyPress(KeyEvent.VK_X); robot.keyRelease(KeyEvent.VK_CONTROL); robot.keyRelease(KeyEvent.VK_X); } catch (AWTException eX) { eX.printStackTrace(); } } }); |
Zu guter Letzt fehlt noch eine Routine, welche das Popmenü auch innerhalb der JTextPane anzeigt:
1 2 3 4 5 |
// for popup menu void showPopup(MouseEvent e) { if (e.isPopupTrigger()) popupMenu.show(e.getComponent(), e.getX(), e.getY()); } |
Hier nun die kompletten Programmcodes, wie immer benötigt Ihr intelliJ zum Nachbau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* * Herkunft/Origin: http://java-crypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenttext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * getestet mit/tested with: Java Runtime Environment 11.0.4 x64 * Datum/Date (dd.mm.jjjj): 12.02.2020 * Funktion: TextPane Popup Menü * Function: TextPane PopupMenü * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine korrekte Funktion, * insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! */ import javax.swing.*; public class Main { public static void main(String[] args) { TextPane form = new TextPane(); JFrame frame = new JFrame("TextPane Popup Menue"); frame.setContentPane(form.getPanel()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setSize(500, 300); frame.setVisible(true); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/* * Herkunft/Origin: http://java-crypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenttext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * getestet mit/tested with: Java Runtime Environment 11.0.4 x64 * Datum/Date (dd.mm.jjjj): 12.02.2020 * Funktion: TextPane Popup Menü * Function: TextPane PopupMenü * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine korrekte Funktion, * insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! */ import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.StyleContext; import javax.swing.text.StyledDocument; import javax.swing.text.rtf.RTFEditorKit; import java.awt.*; import java.awt.event.*; import java.io.*; public class TextPane { private JPanel panelMain; private JPanel panelButtons; private JButton buttonLoad; private JScrollPane scrollPane; private JTextPane textPane; private JButton buttonSave; // für popup menu private JPopupMenu popupMenu; public TextPane() { textPane.setContentType("text/rtf"); textPane.setEditorKit(new RTFEditorKit()); buttonLoad.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { loadRtf("textpane_rtf.rtf"); } }); buttonSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { saveRtf("textpane_rtf.rtf"); } }); // for popup menu popupMenu = new JPopupMenu(); // add menu items to popupMenu JMenuItem menuItemCut = new JMenuItem("cut"); popupMenu.add(menuItemCut); JMenuItem menuItemCopy = new JMenuItem("copy"); popupMenu.add(menuItemCopy); JMenuItem menuItemPaste = new JMenuItem("paste"); popupMenu.add(menuItemPaste); popupMenu.addSeparator(); JMenuItem menuItemSelectAll = new JMenuItem("select all"); popupMenu.add(menuItemSelectAll); textPane.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent me) { showPopup(me); // showPopup() is our own user-defined method } }); menuItemCut.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // send key to textpane ctrl-x try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_CONTROL); robot.keyPress(KeyEvent.VK_X); robot.keyRelease(KeyEvent.VK_CONTROL); robot.keyRelease(KeyEvent.VK_X); } catch (AWTException eX) { eX.printStackTrace(); } } }); menuItemCopy.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // send key to textpane ctrl-c try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_CONTROL); robot.keyPress(KeyEvent.VK_C); robot.keyRelease(KeyEvent.VK_CONTROL); robot.keyRelease(KeyEvent.VK_C); } catch (AWTException eX) { eX.printStackTrace(); } } }); menuItemPaste.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // send key to textpane ctrl-v try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_CONTROL); robot.keyPress(KeyEvent.VK_V); robot.keyRelease(KeyEvent.VK_CONTROL); robot.keyRelease(KeyEvent.VK_V); } catch (AWTException eX) { eX.printStackTrace(); } } }); menuItemSelectAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // send key to textpane ctrl-a try { Robot robot = new Robot(); robot.keyPress(KeyEvent.VK_CONTROL); robot.keyPress(KeyEvent.VK_A); robot.keyRelease(KeyEvent.VK_CONTROL); robot.keyRelease(KeyEvent.VK_A); } catch (AWTException eX) { eX.printStackTrace(); } } }); } public JPanel getPanel() { return panelMain; } public void loadRtf(String filename) { RTFEditorKit RTF_KIT = new RTFEditorKit(); textPane.setContentType("text/rtf"); InputStream inputStream; try { inputStream = new FileInputStream(filename); final DefaultStyledDocument styledDocument = new DefaultStyledDocument(new StyleContext()); RTF_KIT.read(inputStream, styledDocument, 0); textPane.setDocument(styledDocument); // delete added last line String content = textPane.getDocument().getText(0, textPane.getDocument().getLength()); int lastLineBreak = content.lastIndexOf('\n'); textPane.getDocument().remove(lastLineBreak, textPane.getDocument().getLength() - lastLineBreak); } catch (IOException | BadLocationException e) { e.printStackTrace(); } textPane.requestFocus(); } public void saveRtf(String filename) { try { FileOutputStream fos = new FileOutputStream(filename); RTFEditorKit kit = (RTFEditorKit) textPane.getEditorKit(); StyledDocument doc = textPane.getStyledDocument(); int len = doc.getLength(); kit.write(fos, doc, 0, len - 2); fos.close(); } catch (IOException | BadLocationException e) { e.printStackTrace(); } textPane.requestFocus(); } // for popup menu void showPopup(MouseEvent e) { if (e.isPopupTrigger()) popupMenu.show(e.getComponent(), e.getX(), e.getY()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<?xml version="1.0" encoding="UTF-8" ?> - <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="TextPane"> - <grid id="27dc6" binding="panelMain" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="10" left="10" bottom="10" right="10" /> - <constraints> <xy x="20" y="20" width="500" height="400" /> </constraints> <properties /> <border type="none" /> - <children> - <grid id="69623" binding="panelButtons" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0" /> - <constraints> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false" /> </constraints> <properties /> <border type="none" /> - <children> - <component id="b1559" class="javax.swing.JButton" binding="buttonLoad"> - <constraints> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false" /> </constraints> - <properties> <text value="load" /> </properties> </component> - <component id="1e556" class="javax.swing.JButton" binding="buttonSave"> - <constraints> <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false" /> </constraints> - <properties> <text value="save" /> </properties> </component> </children> </grid> - <scrollpane id="5bf0e" binding="scrollPane"> - <constraints> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false" /> </constraints> <properties /> <border type="none" /> - <children> - <component id="100bc" class="javax.swing.JTextPane" binding="textPane"> <constraints /> <properties /> </component> </children> </scrollpane> </children> </grid> </form> |
Alle Quellcodes zur JTextPane findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/JTextPane. Alle Programme sind unter Java 11 lauffähig (vermutlich auch unter Java 8) und wurden mit intelliJ IDEA entwickelt, welches für das eigene „Spielen“ notwendig ist.
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Bearbeitung: 12.02.2020