Merge PR #490: Menus: improved usability of submenus

This commit is contained in:
Karl Tauber
2022-03-13 19:07:59 +01:00
5 changed files with 1389 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ FlatLaf Change Log
#### New features and improvements
- Menus: Improved usability of submenus. (PR #490; issue #247)
- Linux: Support using custom window decorations. Enable with
`JFrame.setDefaultLookAndFeelDecorated(true)` and
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.

View File

@@ -103,6 +103,7 @@ public abstract class FlatLaf
private PopupFactory oldPopupFactory;
private MnemonicHandler mnemonicHandler;
private SubMenuUsabilityHelper subMenuUsabilityHelper;
private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;
@@ -244,6 +245,10 @@ public abstract class FlatLaf
mnemonicHandler = new MnemonicHandler();
mnemonicHandler.install();
// install submenu usability helper
subMenuUsabilityHelper = new SubMenuUsabilityHelper();
subMenuUsabilityHelper.install();
// listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling:
@@ -323,6 +328,12 @@ public abstract class FlatLaf
mnemonicHandler = null;
}
// uninstall submenu usability helper
if( subMenuUsabilityHelper != null ) {
subMenuUsabilityHelper.uninstall();
subMenuUsabilityHelper = null;
}
// restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
postInitialization = null;

View File

@@ -0,0 +1,316 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* Improves usability of submenus by using a
* <a href="https://height.app/blog/guide-to-build-context-menus#safe-triangle">safe triangle</a>
* to avoid that the submenu closes while the user moves the mouse to it.
*
* @author Karl Tauber
*/
class SubMenuUsabilityHelper
implements ChangeListener
{
private static final String KEY_USE_SAFE_TRIANGLE = "Menu.useSafeTriangle";
private static final String KEY_SHOW_SAFE_TRIANGLE = "FlatLaf.debug.menu.showSafeTriangle";
private SubMenuEventQueue subMenuEventQueue;
private SafeTrianglePainter safeTrianglePainter;
private boolean changePending;
// mouse location in screen coordinates
private int mouseX;
private int mouseY;
// target popup bounds in screen coordinates
private int targetX;
private int targetTopY;
private int targetBottomY;
private Rectangle invokerBounds;
void install() {
MenuSelectionManager.defaultManager().addChangeListener( this );
}
void uninstall() {
MenuSelectionManager.defaultManager().removeChangeListener( this );
uninstallEventQueue();
}
@Override
public void stateChanged( ChangeEvent e ) {
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
return;
// handle menu selection change later, but only once in case of temporary changes
// e.g. moving mouse from one menu item to another one, fires two events:
// 1. old menu item is removed from menu selection
// 2. new menu item is added to menu selection
synchronized( this ) {
if( changePending )
return;
changePending = true;
}
EventQueue.invokeLater( () -> {
synchronized( this ) {
changePending = false;
}
menuSelectionChanged();
} );
}
private void menuSelectionChanged() {
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
/*debug
System.out.println( "--- " + path.length );
for( int i = 0; i < path.length; i++ )
System.out.println( " " + i + ": " + path[i].getClass().getName() );
debug*/
// find submenu in menu selection
int subMenuIndex = findSubMenu( path );
// uninstall if there is no submenu in selection
if( subMenuIndex < 0 || subMenuIndex != path.length - 1 ) {
uninstallEventQueue();
return;
}
// get current mouse location
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
Point mouseLocation = (pointerInfo != null) ? pointerInfo.getLocation() : new Point();
mouseX = mouseLocation.x;
mouseY = mouseLocation.y;
// get invoker screen bounds
JPopupMenu popup = (JPopupMenu) path[subMenuIndex];
Component invoker = popup.getInvoker();
invokerBounds = (invoker != null)
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
: null;
// check whether mouse location is within invoker
if( invokerBounds != null && !invokerBounds.contains( mouseX, mouseY ) ) {
uninstallEventQueue();
return;
}
// compute top/bottom target locations
Point popupLocation = popup.getLocationOnScreen();
Dimension popupSize = popup.getSize();
targetX = (mouseX < popupLocation.x + (popupSize.width / 2))
? popupLocation.x
: popupLocation.x + popupSize.width;
targetTopY = popupLocation.y;
targetBottomY = popupLocation.y + popupSize.height;
// install own event queue to supress mouse events when mouse is moved within safe triangle
if( subMenuEventQueue == null )
subMenuEventQueue = new SubMenuEventQueue();
// create safe triangle painter
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
safeTrianglePainter = new SafeTrianglePainter( popup );
}
private void uninstallEventQueue() {
if( subMenuEventQueue != null ) {
subMenuEventQueue.uninstall();
subMenuEventQueue = null;
}
if( safeTrianglePainter != null ) {
safeTrianglePainter.uninstall();
safeTrianglePainter = null;
}
}
private int findSubMenu( MenuElement[] path ) {
for( int i = path.length - 1; i >= 1; i-- ) {
if( path[i] instanceof JPopupMenu &&
path[i - 1] instanceof JMenu &&
!((JMenu)path[i - 1]).isTopLevelMenu() )
return i;
}
return -1;
}
private Polygon createSafeTriangle() {
return new Polygon(
new int[] { mouseX, targetX, targetX },
new int[] { mouseY, targetTopY, targetBottomY },
3 );
}
//---- class SubMenuEventQueue --------------------------------------------
private class SubMenuEventQueue
extends EventQueue
{
private Timer mouseUpdateTimer;
private Timer timeoutTimer;
private int newMouseX;
private int newMouseY;
private AWTEvent lastMouseEvent;
SubMenuEventQueue() {
// timer used to slightly delay update of mouse location used for safe triangle
mouseUpdateTimer = new Timer( 50, e -> {
mouseX = newMouseX;
mouseY = newMouseY;
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
} );
mouseUpdateTimer.setRepeats( false );
// timer used to timeout safe triangle when mouse stops moving
timeoutTimer = new Timer( 200, e -> {
if( invokerBounds != null && !invokerBounds.contains( newMouseX, newMouseY ) ) {
// post last mouse event, which selects menu item at mouse location
if( lastMouseEvent != null ) {
postEvent( lastMouseEvent );
lastMouseEvent = null;
}
uninstallEventQueue();
return;
}
} );
timeoutTimer.setRepeats( false );
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
}
void uninstall() {
mouseUpdateTimer.stop();
mouseUpdateTimer = null;
timeoutTimer.stop();
timeoutTimer = null;
lastMouseEvent = null;
super.pop();
}
@Override
protected void dispatchEvent( AWTEvent e ) {
int id = e.getID();
if( e instanceof MouseEvent &&
(id == MouseEvent.MOUSE_MOVED || id == MouseEvent.MOUSE_DRAGGED) )
{
newMouseX = ((MouseEvent)e).getXOnScreen();
newMouseY = ((MouseEvent)e).getYOnScreen();
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
mouseUpdateTimer.stop();
timeoutTimer.stop();
// check whether mouse moved within safe triangle
if( createSafeTriangle().contains( newMouseX, newMouseY ) ) {
// update mouse location delayed (this changes the safe triangle)
mouseUpdateTimer.start();
timeoutTimer.start();
// remember last mouse event, which will be posted if the mouse stops moving
lastMouseEvent = e;
// ignore mouse event
return;
}
// update mouse location immediately (this changes the safe triangle)
mouseX = newMouseX;
mouseY = newMouseY;
}
super.dispatchEvent( e );
}
}
//---- class SafeTrianglePainter ------------------------------------------
private class SafeTrianglePainter
extends JComponent
{
SafeTrianglePainter( JPopupMenu popup ) {
Window window = SwingUtilities.windowForComponent( popup.getInvoker() );
if( window instanceof RootPaneContainer ) {
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
setSize( layeredPane.getSize() );
layeredPane.add( this, new Integer( JLayeredPane.POPUP_LAYER + 1 ) );
}
}
void uninstall() {
Container parent = getParent();
if( parent != null ) {
parent.remove( this );
parent.repaint();
}
}
@Override
protected void paintComponent( Graphics g ) {
Point locationOnScreen = getLocationOnScreen();
g.translate( -locationOnScreen.x, -locationOnScreen.y );
g.setColor( Color.red );
((Graphics2D)g).draw( createSafeTriangle() );
}
}
}

View File

@@ -0,0 +1,622 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatSubMenusTest
extends FlatTestPanel
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatSubMenusTest" );
UIManager.put( "FlatLaf.debug.menu.showSafeTriangle", true );
frame.applyComponentOrientationToFrame = true;
frame.showFrame( FlatSubMenusTest::new, panel -> ((FlatSubMenusTest)panel).menuBar );
} );
}
FlatSubMenusTest() {
initComponents();
}
private void showPopupMenuButtonActionPerformed(ActionEvent e) {
Component invoker = (Component) e.getSource();
PopupMenu popupMenu = new PopupMenu();
popupMenu.applyComponentOrientation( getComponentOrientation() );
popupMenu.show( invoker, 0, invoker.getHeight() );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JButton showPopupMenuButton = new JButton();
menuBar = new JMenuBar();
JMenu menu3 = new JMenu();
JMenuItem menuItem1 = new JMenuItem();
JMenuItem menuItem50 = new JMenuItem();
JMenu menu4 = new JMenu();
JMenuItem menuItem9 = new JMenuItem();
JMenuItem menuItem10 = new JMenuItem();
JMenuItem menuItem11 = new JMenuItem();
JMenu menu8 = new JMenu();
JMenu menu21 = new JMenu();
JMenuItem menuItem81 = new JMenuItem();
JMenuItem menuItem82 = new JMenuItem();
JMenuItem menuItem83 = new JMenuItem();
JMenuItem menuItem41 = new JMenuItem();
JMenuItem menuItem42 = new JMenuItem();
JMenuItem menuItem43 = new JMenuItem();
JMenuItem menuItem44 = new JMenuItem();
JMenuItem menuItem45 = new JMenuItem();
JMenuItem menuItem46 = new JMenuItem();
JMenuItem menuItem12 = new JMenuItem();
JMenuItem menuItem13 = new JMenuItem();
JMenuItem menuItem14 = new JMenuItem();
JMenuItem menuItem2 = new JMenuItem();
JMenu menu5 = new JMenu();
JMenuItem menuItem15 = new JMenuItem();
JMenuItem menuItem16 = new JMenuItem();
JMenuItem menuItem17 = new JMenuItem();
JMenuItem menuItem18 = new JMenuItem();
JMenuItem menuItem19 = new JMenuItem();
JMenuItem menuItem20 = new JMenuItem();
JMenuItem menuItem21 = new JMenuItem();
JMenuItem menuItem22 = new JMenuItem();
JMenuItem menuItem23 = new JMenuItem();
JMenuItem menuItem24 = new JMenuItem();
JMenuItem menuItem25 = new JMenuItem();
JMenuItem menuItem26 = new JMenuItem();
JMenuItem menuItem27 = new JMenuItem();
JMenuItem menuItem28 = new JMenuItem();
JMenuItem menuItem29 = new JMenuItem();
JMenu menu6 = new JMenu();
JMenuItem menuItem30 = new JMenuItem();
JMenuItem menuItem31 = new JMenuItem();
JMenuItem menuItem32 = new JMenuItem();
JMenu menu9 = new JMenu();
JMenuItem menuItem47 = new JMenuItem();
JMenuItem menuItem48 = new JMenuItem();
JMenuItem menuItem49 = new JMenuItem();
JMenuItem menuItem33 = new JMenuItem();
JMenuItem menuItem34 = new JMenuItem();
JMenuItem menuItem3 = new JMenuItem();
JMenuItem menuItem4 = new JMenuItem();
JMenuItem menuItem5 = new JMenuItem();
JMenuItem menuItem6 = new JMenuItem();
JMenuItem menuItem7 = new JMenuItem();
JMenuItem menuItem8 = new JMenuItem();
JMenu menu7 = new JMenu();
JMenuItem menuItem35 = new JMenuItem();
JMenuItem menuItem37 = new JMenuItem();
JMenuItem menuItem36 = new JMenuItem();
JMenuItem menuItem38 = new JMenuItem();
JMenuItem menuItem39 = new JMenuItem();
JMenuItem menuItem40 = new JMenuItem();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]",
// rows
"[]"));
//---- showPopupMenuButton ----
showPopupMenuButton.setText("show JPopupMenu");
showPopupMenuButton.addActionListener(e -> showPopupMenuButtonActionPerformed(e));
add(showPopupMenuButton, "cell 0 0");
//======== menuBar ========
{
//======== menu3 ========
{
menu3.setText("main menu");
//---- menuItem1 ----
menuItem1.setText("text");
menu3.add(menuItem1);
//---- menuItem50 ----
menuItem50.setText("text");
menu3.add(menuItem50);
//======== menu4 ========
{
menu4.setText("text");
//---- menuItem9 ----
menuItem9.setText("text");
menu4.add(menuItem9);
//---- menuItem10 ----
menuItem10.setText("text text");
menu4.add(menuItem10);
//---- menuItem11 ----
menuItem11.setText("text");
menu4.add(menuItem11);
//======== menu8 ========
{
menu8.setText("text");
//======== menu21 ========
{
menu21.setText("text");
//---- menuItem81 ----
menuItem81.setText("text");
menu21.add(menuItem81);
//---- menuItem82 ----
menuItem82.setText("text");
menu21.add(menuItem82);
//---- menuItem83 ----
menuItem83.setText("text");
menu21.add(menuItem83);
}
menu8.add(menu21);
//---- menuItem41 ----
menuItem41.setText("text");
menu8.add(menuItem41);
//---- menuItem42 ----
menuItem42.setText("text");
menu8.add(menuItem42);
//---- menuItem43 ----
menuItem43.setText("text");
menu8.add(menuItem43);
//---- menuItem44 ----
menuItem44.setText("text");
menu8.add(menuItem44);
//---- menuItem45 ----
menuItem45.setText("text");
menu8.add(menuItem45);
//---- menuItem46 ----
menuItem46.setText("text");
menu8.add(menuItem46);
}
menu4.add(menu8);
//---- menuItem12 ----
menuItem12.setText("text");
menu4.add(menuItem12);
//---- menuItem13 ----
menuItem13.setText("text");
menu4.add(menuItem13);
//---- menuItem14 ----
menuItem14.setText("text");
menu4.add(menuItem14);
}
menu3.add(menu4);
//---- menuItem2 ----
menuItem2.setText("text");
menu3.add(menuItem2);
//======== menu5 ========
{
menu5.setText("text");
//---- menuItem15 ----
menuItem15.setText("text bla bla");
menu5.add(menuItem15);
//---- menuItem16 ----
menuItem16.setText("text");
menu5.add(menuItem16);
//---- menuItem17 ----
menuItem17.setText("text");
menu5.add(menuItem17);
//---- menuItem18 ----
menuItem18.setText("text");
menu5.add(menuItem18);
//---- menuItem19 ----
menuItem19.setText("text");
menu5.add(menuItem19);
//---- menuItem20 ----
menuItem20.setText("text");
menu5.add(menuItem20);
//---- menuItem21 ----
menuItem21.setText("text");
menu5.add(menuItem21);
//---- menuItem22 ----
menuItem22.setText("text");
menu5.add(menuItem22);
//---- menuItem23 ----
menuItem23.setText("text");
menu5.add(menuItem23);
//---- menuItem24 ----
menuItem24.setText("text");
menu5.add(menuItem24);
//---- menuItem25 ----
menuItem25.setText("text");
menu5.add(menuItem25);
//---- menuItem26 ----
menuItem26.setText("text");
menu5.add(menuItem26);
//---- menuItem27 ----
menuItem27.setText("text");
menu5.add(menuItem27);
//---- menuItem28 ----
menuItem28.setText("text");
menu5.add(menuItem28);
//---- menuItem29 ----
menuItem29.setText("text");
menu5.add(menuItem29);
}
menu3.add(menu5);
//======== menu6 ========
{
menu6.setText("text");
//---- menuItem30 ----
menuItem30.setText("text o text");
menu6.add(menuItem30);
//---- menuItem31 ----
menuItem31.setText("text");
menu6.add(menuItem31);
//---- menuItem32 ----
menuItem32.setText("text");
menu6.add(menuItem32);
//======== menu9 ========
{
menu9.setText("text");
//---- menuItem47 ----
menuItem47.setText("text");
menu9.add(menuItem47);
//---- menuItem48 ----
menuItem48.setText("text");
menu9.add(menuItem48);
//---- menuItem49 ----
menuItem49.setText("text");
menu9.add(menuItem49);
}
menu6.add(menu9);
//---- menuItem33 ----
menuItem33.setText("text");
menu6.add(menuItem33);
//---- menuItem34 ----
menuItem34.setText("text");
menu6.add(menuItem34);
}
menu3.add(menu6);
//---- menuItem3 ----
menuItem3.setText("text");
menu3.add(menuItem3);
//---- menuItem4 ----
menuItem4.setText("longer text");
menu3.add(menuItem4);
//---- menuItem5 ----
menuItem5.setText("text");
menu3.add(menuItem5);
//---- menuItem6 ----
menuItem6.setText("text");
menu3.add(menuItem6);
//---- menuItem7 ----
menuItem7.setText("text");
menu3.add(menuItem7);
//---- menuItem8 ----
menuItem8.setText("text");
menu3.add(menuItem8);
//======== menu7 ========
{
menu7.setText("text");
//---- menuItem35 ----
menuItem35.setText("text abc");
menu7.add(menuItem35);
//---- menuItem37 ----
menuItem37.setText("text");
menu7.add(menuItem37);
//---- menuItem36 ----
menuItem36.setText("text");
menu7.add(menuItem36);
//---- menuItem38 ----
menuItem38.setText("text");
menu7.add(menuItem38);
//---- menuItem39 ----
menuItem39.setText("text");
menu7.add(menuItem39);
//---- menuItem40 ----
menuItem40.setText("text");
menu7.add(menuItem40);
}
menu3.add(menu7);
}
menuBar.add(menu3);
}
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenuBar menuBar;
// JFormDesigner - End of variables declaration //GEN-END:variables
//---- class PopupMenu ----------------------------------------------------
private class PopupMenu extends JPopupMenu {
private PopupMenu() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JMenuItem menuItem54 = new JMenuItem();
JMenuItem menuItem51 = new JMenuItem();
JMenu menu10 = new JMenu();
JMenuItem menuItem57 = new JMenuItem();
JMenuItem menuItem58 = new JMenuItem();
JMenu menu14 = new JMenu();
JMenu menu18 = new JMenu();
JMenu menu19 = new JMenu();
JMenuItem menuItem76 = new JMenuItem();
JMenuItem menuItem77 = new JMenuItem();
JMenuItem menuItem78 = new JMenuItem();
JMenu menu20 = new JMenu();
JMenuItem menuItem73 = new JMenuItem();
JMenuItem menuItem74 = new JMenuItem();
JMenuItem menuItem75 = new JMenuItem();
JMenuItem menuItem79 = new JMenuItem();
JMenuItem menuItem80 = new JMenuItem();
JMenuItem menuItem70 = new JMenuItem();
JMenuItem menuItem71 = new JMenuItem();
JMenuItem menuItem72 = new JMenuItem();
JMenuItem menuItem59 = new JMenuItem();
JMenuItem menuItem60 = new JMenuItem();
JMenuItem menuItem52 = new JMenuItem();
JMenu menu11 = new JMenu();
JMenuItem menuItem61 = new JMenuItem();
JMenuItem menuItem62 = new JMenuItem();
JMenuItem menuItem63 = new JMenuItem();
JMenu menu12 = new JMenu();
JMenuItem menuItem64 = new JMenuItem();
JMenuItem menuItem65 = new JMenuItem();
JMenuItem menuItem66 = new JMenuItem();
JMenuItem menuItem53 = new JMenuItem();
JMenuItem menuItem55 = new JMenuItem();
JMenuItem menuItem56 = new JMenuItem();
JMenu menu13 = new JMenu();
JMenuItem menuItem67 = new JMenuItem();
JMenuItem menuItem68 = new JMenuItem();
JMenuItem menuItem69 = new JMenuItem();
//======== this ========
//---- menuItem54 ----
menuItem54.setText("text");
add(menuItem54);
//---- menuItem51 ----
menuItem51.setText("text text");
add(menuItem51);
//======== menu10 ========
{
menu10.setText("text");
//---- menuItem57 ----
menuItem57.setText("text");
menu10.add(menuItem57);
//---- menuItem58 ----
menuItem58.setText("text");
menu10.add(menuItem58);
//======== menu14 ========
{
menu14.setText("text");
//======== menu18 ========
{
menu18.setText("text");
//======== menu19 ========
{
menu19.setText("text");
//---- menuItem76 ----
menuItem76.setText("text");
menu19.add(menuItem76);
//---- menuItem77 ----
menuItem77.setText("text");
menu19.add(menuItem77);
//---- menuItem78 ----
menuItem78.setText("text");
menu19.add(menuItem78);
}
menu18.add(menu19);
//======== menu20 ========
{
menu20.setText("text");
//---- menuItem73 ----
menuItem73.setText("text");
menu20.add(menuItem73);
//---- menuItem74 ----
menuItem74.setText("text");
menu20.add(menuItem74);
//---- menuItem75 ----
menuItem75.setText("text");
menu20.add(menuItem75);
}
menu18.add(menu20);
//---- menuItem79 ----
menuItem79.setText("text");
menu18.add(menuItem79);
//---- menuItem80 ----
menuItem80.setText("text");
menu18.add(menuItem80);
}
menu14.add(menu18);
//---- menuItem70 ----
menuItem70.setText("text");
menu14.add(menuItem70);
//---- menuItem71 ----
menuItem71.setText("text");
menu14.add(menuItem71);
//---- menuItem72 ----
menuItem72.setText("text");
menu14.add(menuItem72);
}
menu10.add(menu14);
//---- menuItem59 ----
menuItem59.setText("text");
menu10.add(menuItem59);
//---- menuItem60 ----
menuItem60.setText("text");
menu10.add(menuItem60);
}
add(menu10);
//---- menuItem52 ----
menuItem52.setText("text");
add(menuItem52);
//======== menu11 ========
{
menu11.setText("text");
//---- menuItem61 ----
menuItem61.setText("text");
menu11.add(menuItem61);
//---- menuItem62 ----
menuItem62.setText("text");
menu11.add(menuItem62);
//---- menuItem63 ----
menuItem63.setText("text");
menu11.add(menuItem63);
}
add(menu11);
//======== menu12 ========
{
menu12.setText("text");
//---- menuItem64 ----
menuItem64.setText("text");
menu12.add(menuItem64);
//---- menuItem65 ----
menuItem65.setText("text");
menu12.add(menuItem65);
//---- menuItem66 ----
menuItem66.setText("text");
menu12.add(menuItem66);
}
add(menu12);
//---- menuItem53 ----
menuItem53.setText("text");
add(menuItem53);
//---- menuItem55 ----
menuItem55.setText("text");
add(menuItem55);
//---- menuItem56 ----
menuItem56.setText("text");
add(menuItem56);
//======== menu13 ========
{
menu13.setText("text");
//---- menuItem67 ----
menuItem67.setText("text");
menu13.add(menuItem67);
//---- menuItem68 ----
menuItem68.setText("text");
menu13.add(menuItem68);
//---- menuItem69 ----
menuItem69.setText("text");
menu13.add(menuItem69);
}
add(menu13);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// JFormDesigner - End of variables declaration //GEN-END:variables
}
}

View File

@@ -0,0 +1,439 @@
JFDML JFormDesigner: "7.0.5.0.404" Java: "17" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[]"
"$rowConstraints": "[]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JButton" ) {
name: "showPopupMenuButton"
"text": "show JPopupMenu"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButtonActionPerformed", true ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 390, 130 )
} )
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
name: "menuBar"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu3"
"text": "main menu"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem50"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu4"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem9"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem10"
"text": "text text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem11"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu8"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu21"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem81"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem82"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem83"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem41"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem42"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem43"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem44"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem45"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem46"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem12"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem13"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem14"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem2"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu5"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem15"
"text": "text bla bla"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem16"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem17"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem18"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem19"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem20"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem21"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem22"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem23"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem24"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem25"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem26"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem27"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem28"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem29"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu6"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem30"
"text": "text o text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem31"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem32"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu9"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem47"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem48"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem49"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem33"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem34"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem3"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem4"
"text": "longer text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem5"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem6"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem7"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem8"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu7"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem35"
"text": "text abc"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem37"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem36"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem38"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem39"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem40"
"text": "text"
} )
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 175 )
} )
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
name: "popupMenu1"
auxiliary() {
"JavaCodeGenerator.className": "PopupMenu"
}
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem54"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem51"
"text": "text text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu10"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem57"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem58"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu14"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu18"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu19"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem76"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem77"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem78"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu20"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem73"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem74"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem75"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem79"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem80"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem70"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem71"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem72"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem59"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem60"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem52"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu11"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem61"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem62"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem63"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu12"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem64"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem65"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem66"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem53"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem55"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem56"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu13"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem67"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem68"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem69"
"text": "text"
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 275, 175 )
} )
}
}