Java JMenu open upwards instead of downwards [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 days ago.
Improve this question
I need to display a Java JMenu opening upwards instead of downwards.
I am creating an application made of a series of JFames.
One of those JFrames hosts a JMenuBar, built by a series of JMenu instances, and given the size and the position of this JFrame, it is at the bottom of the application.
The application runs in a high resolution display shared with other applications, and it is placed at the top position of it.
So using the default settings of JMenu causes the menu opening downwards overlapping the others applications areas running on the bottom of the screen.
Can anyone help me in finding the correct way for forcing the menu opening upwards please?
I tried using the setLocation() method of the JMenu class, I was expecting the menu open at the coordinates I gave, but it did not work.
I also investigated at the BoxLayout features, but it did not help.

You can use a MenuListener to reset the location of the popup menu to display above the menu:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class MenuPopupUpListener implements MenuListener
{
#Override
public void menuSelected(MenuEvent e)
{
SwingUtilities.invokeLater(() ->
{
JMenu menu = (JMenu)e.getSource();
JPopupMenu popup = menu.getPopupMenu();
Rectangle bounds = popup.getBounds();
Point location = menu.getLocationOnScreen();
location.y -= bounds.getHeight();
popup.setLocation(location);
});
}
#Override
public void menuCanceled(MenuEvent e) {}
#Override
public void menuDeselected(MenuEvent e) {}
private static void createAndShowGUI()
{
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu 1");
menuBar.add( menu );
menu.add( new JMenuItem( "MenuItem 1a" ) );
menu.add( new JMenuItem( "MenuItem 1b" ) );
menu.add( new JMenuItem( "MenuItem 1c" ) );
// Add a listener to all menus to have the popup open above the menu
MenuListener ml = new MenuPopupUpListener();
menu.addMenuListener( ml );
JFrame frame = new JFrame("MenuPopupUp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(menuBar, BorderLayout.PAGE_END);
frame.setLocationByPlatform( true );
frame.setSize(300, 300);
frame.setVisible( true );
}
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
The listener would need to be added to all menus.

Related

How do I scroll a JPanel with keyboard, while other components have focus? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I've been looking for a solution for this, I think, very common, problem, with Java Swing, but can't find specific answers.
I have this Swing JPanel with a scrollable JPanel on top, showing an image of a document.
Below there is more Swing components, e.g. a JTable and some textboxes, JButton controls etc. in another panel. (There are more panels in the same JWindow.)
When user edits data etc. in the boxes below, these of course gains focus as it should be. Now when the user wants to scroll for some specific data in the document, he/she needs to set focus (with mouse/tab) on this first, and then scroll.
So user would like to use e.g. arrow up/down keyboard without leaving focus from the other component he is working with.
I've tried to set keyboard handlers up, but can not get it to work without involving moving focus to the top.
Isn't there a way to scroll a scrollable Swing component without this component (and another) has focus?
If the components are text fields in the scroll pane, it seems Page Down works if the (first, at least) text field is focused. This is the result of running such code and hitting Page Down a few times.
If this behavior is needed while components outside the scroll pane are focused, perhaps look to key bindings.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class KeyboardScroll {
private JComponent ui = null;
KeyboardScroll() {
initUI();
}
public void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
JPanel textPanel = new JPanel(new GridLayout(0, 1));
for (int ii = 1; ii < 101; ii++) {
textPanel.add(new JTextField("Field " + ii, 30));
}
JScrollPane scrollPane = new JScrollPane(textPanel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
ui.add(scrollPane);
Dimension d = textPanel.getPreferredSize();
scrollPane.getViewport().setPreferredSize(
new Dimension((int)d.getWidth(),100));
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
KeyboardScroll o = new KeyboardScroll();
JFrame f = new JFrame("Use 'Page Down'");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Isn't there a way to scroll a scrollable Swing component without this component (and another) has focus?
Then general solution is to use Key Bindings.
However, the problem is that each component can implement Key Bindings itself for the up/down event, in which case the related Action for that component is invoked.
The tutorial demonstrates how you can remove key bindings from a component.
a JTable and some textboxes
So these are examples of components the do implement up/down key bindings.
JButton controls
Is an example of a component that doesn't have default up/down key bindings.
So you could add your own with code like the following:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
setLayout( new BorderLayout() );
JPanel top = new JPanel();
top.add( new JTextField(10) );
top.add( new JButton("Button") );
add(top, BorderLayout.PAGE_START);
JLabel label = new JLabel( new ImageIcon("mong.jpg") );
JScrollPane scrollPane = new JScrollPane( label );
add(scrollPane, BorderLayout.CENTER);
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
InputMap im = getInputMap(JScrollBar.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke("pressed UP"), "up");
am.put("up", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
scrollBar.setValue(scrollBar.getValue() - scrollBar.getUnitIncrement(-1));
}
});
im.put(KeyStroke.getKeyStroke("pressed DOWN"), "down");
am.put("down", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
scrollBar.setValue(scrollBar.getValue() + scrollBar.getUnitIncrement(1));
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
In the above example the image will scroll when focus is on the button, but not on the text field.

Swing Actions - Linking Menus and Toolbar

I've been studying Java Swing and I'm working on learning actions.
I can successfully create action objects and use them to link items from a JToolBar to JMenuItems. My problem, is that the constructed actions display both icons and text in the toolbar (should only be the icons).
Check out the following code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MenuDemo{
MenuDemo(){
JFrame jfrm = new JFrame("Complete Menu Demo");
jfrm.setSize(220, 200);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar jmb = new JMenuBar();
/* Make the action object */
ImageIcon setIcon = new ImageIcon("setBP.png");
DebugAction setAct = new DebugAction("Set Breakpoint",
setIcon, KeyEvent.VK_S,
KeyEvent.VK_B, "Set Breakpoint");
/* Make the toolbar */
JButton jbtnSet = new JButton(setAct);
JToolBar jtb = new JToolBar("Breakpoints");
jtb.add(jbtnSet);
/* Make the menu */
JMenu jmDebug = new JMenu("Debug");
JMenuItem jmiSetBP = new JMenuItem(setAct);
jmDebug.add(jmiSetBP);
jmb.add(jmDebug);
jfrm.getContentPane().add(jtb, BorderLayout.NORTH);
jfrm.setJMenuBar(jmb);
jfrm.setVisible(true);
}
class DebugAction extends AbstractAction{
public DebugAction(String name, Icon image, int mnem,
int accel, String tTip){
super(name, image);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(accel,
InputEvent.CTRL_MASK));
putValue(MNEMONIC_KEY, new Integer(mnem));
putValue(SHORT_DESCRIPTION, tTip);
}
public void actionPerformed(ActionEvent ae){
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new MenuDemo();
}
});
}
}
This program yields the following GUI:
I just want the green button in the JToolBar, not text. I think my problem code is in the DebugAction constructor, where I call super(name, image). For the toolbar buttons, I would only want to pass in the image. But for the menu I want both. How can I "turn off" the text for the JToolBar items? Thanks!
How can I "turn off" the text for the JToolBar items?
You turn it off using:
JButton button = new JButton( action );
button.setHideActionText( true );
Or, you can just reset the text on the button:
JButton button = new JButton( action );
button.setText("");
I accepted camickr's answer, but there is a caveat.
For identification purposes, I am grabbing the actionCommand of these buttons. Both setHideActionText(true); and button.setText("") do remove the text, but both produce errors when I try to grab the actionCommand.
To fix this, I explicitly set the actionCommand when I create the action object by adding the additional line in the constructor:
putValue(ACTION_COMMAND_KEY, sometext);
This fixed the errors.

Access components of JFrame within MouseAdapter

what is the right way to access elements from a parent component when an adapter is used? Example:
In my JFrame is a Menu with an item "Connect". I handle the "pressed" event with a MouseAdapter:
mntmConnect.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
mainDialog.getY();
}
});
As you can see I want to access components or methods of the mainDialog where this Menu(item) belongs to. But in that MouseAdapter of course no "mainDialog" is known.
So here are my approaches:
1. Declare attributes that a needed as final
2. Create your own MouseAdapter that takes "mainDialog" as a variable in the ctor
Both of them seem circumstantial to me. What is the right way to do this?
What is the right way to do this?
All 3 of these approaches are right.
Declare attributes that are needed for an anonymous class as final.
Declare attributes that are needed for an anonymous class as class global.
Create a MouseAdapter class that takes "mainDialog" as a variable in the constructor.
I tend to use 2 for small MouseAdapter anonymous classes.
I tend to use 3 for larger MouseAdapter classes. I make these separate classes and put them in a controller package.
I handle the "pressed" event with a MouseAdapter
You should NOT be doing this. You should be adding and ActionListener (or Action) to the JMenuItem.
All compnents have a parent. So if you want to know the parent window of the menu item that was clicked you need to keep finding the parents component until you reach the window. Here is one way:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuItemFrame extends JFrame implements ActionListener
{
public MenuItemFrame()
{
JMenuBar menuBar = new JMenuBar();
setJMenuBar( menuBar );
JMenu menu = new JMenu( "File" );
menuBar.add( menu );
JMenuItem item1 = new JMenuItem("Item 1");
item1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, false));
menu.add( item1 );
JMenu subMenu1 = new JMenu("SubMenu 1");
menu.add( subMenu1 );
JMenuItem subItem1 = new JMenuItem("SubItem 1");
subMenu1.add( subItem1 );
JMenu subMenu12 = new JMenu("SubMenu 12");
subMenu1.add( subMenu12 );
JMenuItem subItem12 = new JMenuItem("SubItem 12");
subMenu12.add( subItem12 );
item1.addActionListener( this );
subItem1.addActionListener( this );
subItem12.addActionListener( this );
}
public void actionPerformed(ActionEvent e)
{
JMenuItem mi = (JMenuItem)e.getSource();
mi.setText(mi.getText() + "0");
JMenu menu = getMenuBarMenu(mi);
JRootPane rootPane = SwingUtilities.getRootPane(menu);
JFrame frame = (JFrame)SwingUtilities.windowForComponent(menu);
System.out.println(frame);
}
public JMenu getMenuBarMenu(JMenuItem item)
{
JMenu menu = null;
while (menu == null)
{
JPopupMenu popup = (JPopupMenu)item.getParent();
item = (JMenuItem)popup.getInvoker();
if (! (item.getParent() instanceof JPopupMenu) )
menu = (JMenu)item;
}
return menu;
}
public static void main(String[] args)
{
JFrame frame = new MenuItemFrame();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(200, 200);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}

How to make JMenuBar activate menu without popping it up?

I try to make my JMenuBar to activate first JMenu on Alt KeyEvent, but without opening popup, so that one could open popup with arrows keystrokes later. Just like it is done in NetBeans, Mozilla, any other program window.
Here is the code that works not as intended. The worst side effect is that it reacts on alt+tab combination, and it definitely should not popup menu on alt+tab. I just need to make a menu go to the "armed" state and be able to traverse menus by arrow keys (arrows right & left to "arm" menus and arrow down to open "armed" menu popup). Is there any simple way to make this happen?
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
public class Test5 extends JFrame {
public Test5() {
super("test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel pan = new JPanel(new BorderLayout());
final JMenuBar bar = new JMenuBar();
final JMenu menu = new JMenu("File", false);
menu.setMnemonic(KeyEvent.VK_ALT);
JMenuItem item = new JMenuItem("All");
JMenuItem item2 = new JMenuItem("Exit");
menu.add(item);
menu.add(item2);
JMenu menu1 = new JMenu("Test");
JMenuItem item1 = new JMenuItem("All");
menu1.add(item1);
bar.add(menu);
bar.add(menu1);
setJMenuBar(bar);
setSize(200, 200);
setVisible(true);
}
public static void main(String[] args) {
new Test5();
}
}
Solved thanks to Guillaume Polet:
There is some code in com.sun.java.swing.plaf.windows.WindowsLookAndFeel class, wich works with Alt keystrokes:
public void initialize() {
super.initialize();
// some more initialization here
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventPostProcessor(WindowsRootPaneUI.altProcessor);
}
And the AltProcessor class does all the magic.
If you don't have any custom LaF, you can just use WindowsLookAndFeel as it is, or there is proper example how to process Alt events in menus for your own special LaF.
Before starting your GUI, invoke this line:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
And remove the mnemonic.
This will automatically install the desired behaviour on Windows.
If you need this on all platforms, then you will have to go with KeyBindings, but since this behaviour is only observed on Windows, I don't find it problematic to recreate it only on Windows.
no idea why, but about answering the question
1st step
have to use KeyBindings and with output to the Swing Action (adviced) or ActionListener
there are two methods menu.setArmed(true) or menu.setSelected(true)
but in both cases JMenu is selected forever then to required 2nd. step to add MenuListener and restore previous selected or armed to false

Can't Add JMenuItem to JMenu in JPopupMenu

I've got a new UI I'm working on implementing in Java and I'm having trouble implementing a JPopupMenu containing a JMenu (as well as several JMenuItems), which itself contains several JMenuItems. The JPopupMenu appears where I click the RMB, and it looks good, but the "Connect" JMenu doesn't seem to have any children when I mouse-over, despite my best efforts to .add() them.
Having looked at several examples online, I haven't seen any that specifically implement a listener for mouseEntered() to roll out the sub-items. I'm of a mind that I'm messing something up in my menu initialization method.
I've attached the pertinent code for your perusal.
//Elsewhere...
private JPopupMenu _clickMenu;
//End Elsehwere...
private void initializeMenu()
{
_clickMenu = new JPopupMenu();
_clickMenu.setVisible(false);
_clickMenu.add(generateConnectionMenu());
JMenuItem menuItem;
menuItem = new JMenuItem("Configure");
addMenuItemListeners(menuItem);
_clickMenu.add(menuItem);
menuItem = new JMenuItem("Status");
addMenuItemListeners(menuItem);
_clickMenu.add(menuItem);
}
private JMenu generateConnectionMenu()
{
JMenu menu = new JMenu("Connect");
List<Port> portList = _database.getAllPortsInCard(_cardId);
for(int i = 0; i < portList.size(); i++)
{
menu.add(new JMenuItem(portList.get(i).getName()));
}
return menu;
}
The code is certainly not the prettiest, but go easy on me as it's been altered too many times today as time permitted while I tried to figure out why this wasn't working. I'm thinking it may be a question of scope, but I've tried a few different code configurations to no avail. Feel free to ask any followup questions or smack me for an obvious oversight (it's happened before...). Thanks all!
Edit:
Chalk this one up to a lack of experience with Java and Swing... I was manually positioning and making the JPopupMenu visible instead of using the JComponent.setComponentPopupMenu(menu) method. After doing this for the card module in the above image (itself a JButton), the submenu displays correctly. A different, functional version of the initialization code is included below.
private void initializeMenu()
{
_cardMenu = new JPopupMenu();
JMenu menu = new JMenu("Connect");
JMenuItem menuItem;
menuItem = new JMenuItem("1");
menu.add(menuItem);
menuItem = new JMenuItem("2");
menu.add(menuItem);
_cardMenu.add(menu);
_cardMenu.add(new JMenuItem("Configure"));
_cardMenu.add(new JMenuItem("Status"));
_mainButton.setComponentPopupMenu(_cardMenu); //Important, apparently!
}
So, lesson learned. Thanks for the help guys!
This is common Bug or Swing property that in one moment can be visible only one Lightweight popup window, same issue is e.g. with popup from JComboBox added into JPopupMenu,
change Lightweight property to the Heavyweight
better would be
use un_decorated JDialog or JOptionPane with JComponents
EDIT #trashgod
everything works as I excepted, all JMenus, JMenuItems are visible and repeatly fired correct evets
code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ContextMenu implements ActionListener, MenuListener, MenuKeyListener {
private JTextArea textArea = new JTextArea();
public ContextMenu() {
final JPopupMenu contextMenu = new JPopupMenu("Edit");
JMenu menu = new JMenu("Sub Menu");
menu.add(makeMenuItem("Sub Menu Save"));
menu.add(makeMenuItem("Sub Menu Save As"));
menu.add(makeMenuItem("Sub Menu Close"));
menu.addMenuListener(this);
JMenu menu1 = new JMenu("Sub Menu");
menu1.add(makeMenuItem("Deepest Sub Menu Save"));
menu1.add(makeMenuItem("Deepest Sub Menu Save As"));
menu1.add(makeMenuItem("Deepest Sub Menu Close"));
menu.add(menu1);
menu1.addMenuListener(this);
contextMenu.add(menu);
contextMenu.add(makeMenuItem("Plain Save"));
contextMenu.add(makeMenuItem("Plain Save As"));
contextMenu.add(makeMenuItem("Plain Close"));
contextMenu.addMenuKeyListener(this);
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
frame.add(panel);
panel.setComponentPopupMenu(contextMenu);
textArea.setInheritsPopupMenu(true);
panel.add(BorderLayout.CENTER, textArea);
JTextField textField = new JTextField();
textField.setInheritsPopupMenu(true);
panel.add(BorderLayout.SOUTH, textField);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
textArea.append(e.getActionCommand() + "\n");
}
private JMenuItem makeMenuItem(String label) {
JMenuItem item = new JMenuItem(label);
item.addActionListener(this);
return item;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ContextMenu contextMenu = new ContextMenu();
}
});
}
public void menuSelected(MenuEvent e) {
textArea.append("menuSelected" + "\n");
}
public void menuDeselected(MenuEvent e) {
textArea.append("menuDeselected" + "\n");
}
public void menuCanceled(MenuEvent e) {
textArea.append("menuCanceled" + "\n");
}
public void menuKeyTyped(MenuKeyEvent e) {
textArea.append("menuKeyTyped" + "\n");
}
public void menuKeyPressed(MenuKeyEvent e) {
textArea.append("menuKeyPressed" + "\n");
}
public void menuKeyReleased(MenuKeyEvent e) {
textArea.append("menuKeyReleased" + "\n");
}
}
I don't see an obvious problem in the code shown, although #mKorbel's point may apply. For reference, this ControlPanel adds a subMenu with several items.

Categories