Make a JPopupMenu display with a specific bottom left coordinate

Let's say that I want to make a button in Java so that when I click on it, JPopupMenu appears. The corresponding code for it is menu.show(button, button.getWidth()/2, button.getHeight()/2); , which makes JPopupMenu displayed in the upper left corner in the center of the button, as shown below:

Current Swing JPopupMenu

However, I would like the bottom left corner to be in the center of the button instead, something like iTunes does (there is a button under the bottom left corner that is the same size as + left of it):

enter image description here

I tried to do this by getting the height of JPopupMenu and adding it to the y coordinate that the popup menu displays, but I found that JPopupMenu has a height of 0 before it is visible, which doesn't help me, as I try to tell the computer where it is to do. In addition, hard coding in offset is not possible, as the number of items in the pop-up menu will not necessarily be the same.

How can I make my JPopupMenu with an unknown height display so that the bottom left coordinate matches the given coordinate?

+4
source share
3 answers

Basically, this creates a popup menu and registers it using the JComponent#setComponentPopupMenu . This means that I no longer need to track mouse events or make decisions about when to show the popup.

Then I override JComponent#getPopupLocation and compute the location where I want the popup to appear.

Basically, I get JComponent#getComponentPopupMenu , get its preferred size and calculate the corresponding offset, so that the bottom left corner now appears in the center of the component ...

enter image description here

 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Point; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class TestPopup02 { public static void main(String[] args) { new TestPopup02(); } public TestPopup02() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { JPopupMenu menu = new JPopupMenu(); menu.add(new JMenuItem("Edit Playlist")); menu.addSeparator(); menu.add(new JMenuItem("Check for Available Downloads...")); menu.addSeparator(); menu.add(new JMenuItem("Export...")); menu.add(new JMenuItem("Burn Playlist to Disc")); menu.add(new JMenuItem("Copy To Play Order")); menu.addSeparator(); menu.add(new JMenuItem("Delete")); setComponentPopupMenu(menu); } @Override public Point getPopupLocation(MouseEvent event) { // Get the registered popup menu... JPopupMenu popup = getComponentPopupMenu(); // Get the super point, just in case... Point pos = super.getPopupLocation(event); if (popup != null) { // Create a new "point" location pos = new Point(); // get the preferred size of the menu... Dimension size = popup.getPreferredSize(); // Adjust the x position so that the left side of the popup // appears at the center of the component pos.x = (getWidth() / 2); // Adjust the y position so that the y postion (top corner) // is positioned so that the bottom of the popup // appears in the center pos.y = (getHeight() / 2) - size.height; } return pos; } @Override public Dimension getPreferredSize() { return new Dimension(400, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Simply draws a cross in the center of the window, so you // know where the center is... int width = getWidth() - 1; int height = getHeight() - 1; g.drawLine(width / 2, 0, width / 2, height); g.drawLine(0, height / 2, width, height / 2); } } } 

Mac Update

enter image description here

Button Example

It is unlikely that you will ever find a solution that meets your needs. One of the greatest skills that any developer can develop is the ability to think and shape it there.

The previous example contains everything you need, you just need to make the transition from concept to solution.

getPopupLocation is part of the component’s API, so either overriding the method or calling it is probably not quite what you need (if you don’t have a dedicated button for the task, which can be good) so you will need to adapt the solution to your needs ...

enter image description here

 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class TestPopup02 { public static void main(String[] args) { new TestPopup02(); } public TestPopup02() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private JButton button; private JPopupMenu popup; public TestPane() { popup = new JPopupMenu(); popup.add(new JMenuItem("Edit Playlist")); popup.addSeparator(); popup.add(new JMenuItem("Check for Available Downloads...")); popup.addSeparator(); popup.add(new JMenuItem("Export...")); popup.add(new JMenuItem("Burn Playlist to Disc")); popup.add(new JMenuItem("Copy To Play Order")); popup.addSeparator(); popup.add(new JMenuItem("Delete")); setLayout(new GridBagLayout()); button = new JButton("+"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { popup.pack(); Point pos = new Point(); // get the preferred size of the menu... Dimension size = popup.getPreferredSize(); // Adjust the x position so that the left side of the popup // appears at the center of the component pos.x = (button.getWidth() / 2); // Adjust the y position so that the y postion (top corner) // is positioned so that the bottom of the popup // appears in the center pos.y = (button.getHeight() / 2) - size.height; popup.show(button, pos.x, pos.y); } }); add(button); } @Override public Dimension getPreferredSize() { return new Dimension(400, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Simply draws a cross in the center of the window, so you // know where the center is... int width = getWidth() - 1; int height = getHeight() - 1; g.drawLine(width / 2, 0, width / 2, height); g.drawLine(0, height / 2, width, height / 2); } } } 
+7
source

This is actually a lot easier than I thought and should work in most cases. I used your pastebin code and played around a bit. After you called setVisible(true) in the frame, I was able to call menu.getPreferredSize() . Just printing it to standard, they gave me java.awt.Dimension[width=31,height=62] . This can be done before your ActionListener is called so that you can use the height.

If you use a border in your menu, you may have to take this into account, but the above should work.

0
source

This answer just serves to back up my popup comment and getPreferredSize ().

Please note that you CAN get a preferred height of zero for the popup ... if it has zero menu items, this will be a logical conclusion.

Again, MadProgrammer's answer should be accepted.

 import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; public class ButtonPopup extends JFrame { private JButton button; public ButtonPopup() { setLayout(new GridBagLayout()); button = new JButton("Click Meh~ /o/"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JPopupMenu popup = new JPopupMenu(); popup.add(new JMenuItem("A")); popup.add(new JMenuItem("B")); popup.add(new JMenuItem("C")); // you want this int height = popup.getPreferredSize().height; popup.show( button, button.getWidth() / 2, -height + (button.getHeight() / 2)); } }); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(5, 5, 5, 5); add(button, gbc); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new ButtonPopup().setVisible(true); } }); } } 

PS: I usually don’t return long dead questions, but this time I was looking for something similar, this was the first hit on google.

0
source

Source: https://habr.com/ru/post/1480039/


All Articles