I have next structure: JPopupMenu contains JPanel which contains JMenuItems. The problem is, I cannot use it because JPopupMenu disappears when mouse enters to any menu item.
SSCCE:
public class PopupTest {
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
final JPopupMenu menu = new JPopupMenu();
JPanel menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem(String.valueOf(i));
menuPanel.add(item);
}
menu.add(menuPanel);
menu.show(panel, e.getX(), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
BTW, problem does not repeats when there is no JPanel between JPopupMenu and its items.
Does anyone know how to prevent that?
Not directly answering your question but I think, you are unnecessarily adding a panel with box layout to JPopupMenu when it supports adding JMenuitem directly to it. check the following code fragment:
final JPopupMenu menu = new JPopupMenu();
JPanel menuPanel = new JPanel();
menuPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
// menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++) {
JLabel item = new JLabel(i+"");
menuPanel.add(item);
}
menu.add(menuPanel);
menu.show(panel, e.getX(), e.getY());
Some tips:
Define your pop up menu just once instead every time a button is pressed.
You need to override mouseReleased or mousePressed method: Bringing Up a Popup Menu
Use MouseEvent.isPopupTrigger to find out if pop up should be shown.
Add menuItems directly to menu and not to a JPanel
Suggested changes:
final JPopupMenu menu = new JPopupMenu();
menu.setLayout(new GridLayout(2,5)); // How do you can, for example, lay out your menu items horizontally in 2 rows?
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem(String.valueOf(i));
menu.add(item);
}
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()){
menu.show(panel, e.getX(), e.getY());
}
}
};
panel.addMouseListener(mouseListener);
Picture
Related
This is my first time creating a Gui and I'm stumped on how to create interactions.
I'm trying to implement a single selection mode when the combobox is on single, and multiple when it's placed on multiple. I placed them on the multi line comment.
Any ideas?
//Interactions
//When “Single” is selected then the JList changes so only one item
can be selected.
//When “Multiple” is selected, the JList changes so multiple items can
be selected
//When a country, or multiple countries, is selected the JLabel
changes to reflect the new selections
public class GuiTest {
public static String[] Countries = {"Africa", "Haiti", "USA", "Poland", "Russia", "Canada", "Mexico", "Cuba"};
public static String[] Selection = {"Single", "Multiple"};
JPanel p = new JPanel();
JButton b = new JButton("Testing");
JComboBox jc = new JComboBox(Selection);
JList jl = new JList(Countries);
private static void constructGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
frame.setTitle("Countries Selection");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add a JLabel that says Welcome
JLabel label = new JLabel("Selected Items:");
frame.add(label);
frame.pack();
JComboBox jc = new JComboBox(Selection);
frame.add(jc);
frame.pack();
frame.setVisible(true);
JList jl = new JList(Countries);
frame.add(jl);
frame.pack();
JComponent panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JLabel("Choose Selection Mode:"));
panel.add(jc);
frame.add(panel, BorderLayout.NORTH);
frame.add(jl, BorderLayout.WEST);
frame.add(label, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
constructGUI();
}
});
}
}
you should start adding the modes to the ComboBox:
comboBoxCategoria.addItem("Single",0);
comboBoxCategoria.addItem("Multiple",1);
then add a ActionListener to your ComboBox to modify the list selection mode
jc.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(jc.getSelectedItem().equals("Single")){
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}else{//must equals
jl.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
}
});
finally add a MouseListener on the list to detect changes on the list selections and change the JLabel to reflect the new selections
jl.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
label.setText(list.getSelectedValuesList().toString());
}
});
edit: you should also add a KeyListener to update the label since the selection can be changed via arrow keys
jl.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
label.setText(list.getSelectedValuesList().toString());
}
});
It would be something like this:
jc.addActionListener((evt) -> {
if ("Single".equals(jc.getSelectedItem())) {
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
int[] sel = jl.getSelectedIndices();
if (sel != null && sel.length > 1) {
jl.setSelectedIndex(sel[0]);
}
} else {
jl.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
});
jl.addListSelectionListener((evt) -> {
StringBuilder buf = new StringBuilder();
for (Object o: jl.getSelectedValuesList()) {
if (buf.length() > 0) {
buf.append(", ");
}
buf.append(o);
}
label.setText(buf.toString());
});
jc.setSelectedItem("Single");
I'm trying to add a button using an JOptionPane in another button, but after I clicked the original button just keeps disappearing.
I've tried adding the JPanel manually instead of using 'handPanelNPC.getHandPanel()' by iterating through the handPanel.buttons but it stil wont work. I've checked the ArrayList size and it is already inserted properly.
LayoutTesting.java
public class LayoutTesting extends JFrame{
HandPanel handPanelNPC = new HandPanel();
public LayoutTesting(HandPanel handPanel, int type){
Container pane = getContentPane();
if (type==1){
handPanelNPC = handPanel;
}
pane.setLayout(new BorderLayout());
pane.add(handPanelNPC.getHandPanel(), BorderLayout.NORTH);
validate();
repaint();
}
public LayoutTesting(){
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
pane.add(handPanelNPC.getHandPanel(), BorderLayout.NORTH);
}
}
HandPanel.java
public class HandPanel implements ActionListener{
JFrame frame = null;
JPanel panel = new JPanel();
ArrayList<JButton> buttons = new ArrayList<JButton>();
public HandPanel(){
addNewButton();
panel.setLayout(new FlowLayout());
panel.add(buttons.get(0));
}
public JComponent getHandPanel(){
panel = new JPanel();
for(int i=0; i<buttons.size(); i++){
JButton button = buttons.get(i);
panel.add(button);
}
return panel;
}
public void addNewButton(){
JButton button = new JButton();
button.setPreferredSize(new Dimension(40,58));
button.addActionListener(this);
buttons.add(button);
}
public void actionPerformed(ActionEvent e) {
String[] options = {"Summon", "Set", "Add Card"};
int messageType = JOptionPane.QUESTION_MESSAGE;
int code = JOptionPane.showOptionDialog(
frame,
"What would you like to do?",
"Card Name",
0, messageType, null,
options, options[1]);
if (code==2){
addNewButton();
LayoutTesting frame = new LayoutTesting(this, 1);
}
}
}
Main.java
public class Main extends JFrame{
public static void main(String[] args){
LayoutTesting frame = new LayoutTesting();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
You have too many odd things happening in your code to give a simple answer.
Try debugging your own code by looking at this line in HandPanel.java:
LayoutTesting frame = new LayoutTesting(this, 1);
What does it really do? Now remove that line and the button will not disappear. Now try and work out what that line was doing, and why the button disappeared.
Also 'panel.add(buttons.get(0));' does nothing because there is never a button in the array when you make that call (You add the button afterwards in another method).
Here is a rough working demo that lets you add as many new cards as you want to the first frame, and each card has a button that will let you summon a new card.
public class LayoutTesting extends JFrame{
Container pane;
//Add card when button is pressed:
public void addCard(){
Container card = new JPanel();
card.setBackground(Color.red);
JButton newButton = addNewButton();
newButton.setBackground(Color.red);
card.add(newButton);
pane.add(card);
revalidate();
repaint();
}
//Setup window and add button:
public LayoutTesting(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setVisible(true);
setLayout(new FlowLayout());
pane = new JPanel();
pane.setLayout(new GridBagLayout());
JButton firstButton = addNewButton();
firstButton.setBackground(Color.green);
add(pane);
add(firstButton);
}
//Create button and action listener:
public JButton addNewButton(){
JButton button = new JButton();
button.setPreferredSize(new Dimension(40, 58));
button.addActionListener(new java.awt.event.ActionListener(){
#Override
public void actionPerformed(java.awt.event.ActionEvent evt){
buttonAction(evt);
}
});
return button;
}
//Action fer each button:
public void buttonAction(ActionEvent e) {
String[] options = {"Summon", "Set", "Add Card"};
int messageType = JOptionPane.QUESTION_MESSAGE;
int code = JOptionPane.showOptionDialog(
this,
"What would you like to do?",
"Card Name",
0, messageType, null,
options, options[1]);
if (code==2){
addCard();
}
}
}
I'm in the early stages of making Battleships (just started a computer science degree) and had been using Eclipse on Windows. So far I've just created the grids and have added an actionlistener to the jbuttons so they change colour when clicked.
It works fine when I run it on my Windows PC, however when I try to run it on a mac, it just shows the basic grid and doesn't change colours or anything.
Anyone had a problem like this or can help? I can't figure out why it would work on one and not the other.
Thanks
Here is my code, if that helps (I know it's not elegant or anything right now)
public class BattleshipFrame {
public static void main(String[] args) {
//creating JFrame
JFrame frame = new JFrame("Battleship");
frame.setLayout(new GridLayout(1, 3));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//creating User Panel
JPanel userpanel = new JPanel();
userpanel.setLayout(new GridLayout(10, 10));
userpanel.setSize(400, 400);
//creating JButton array
JButton[] button = new JButton[100];
//putting JButtons in User Panel
for (int i = 0; i < 100; i++) {
button[i] = new JButton();
button[i].setBackground(Color.BLUE);
userpanel.add(button[i]);
//changing colour of buttons when clicked
button[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
Object source = ev.getSource();
if (source instanceof Component) {
((Component) source).setBackground(Color.GREEN);
}
}
});
}
//creating computer panel
JPanel comppanel = new JPanel();
comppanel.setLayout(new GridLayout(10, 10));
comppanel.setSize(400, 400);
//putting JButtons in User Panel
for (int i = 0; i < 100; i++) {
button[i] = new JButton();
button[i].setBackground(Color.BLUE);
comppanel.add(button[i]);
//changing colour of buttons when clicked
button[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
Object source = ev.getSource();
if (source instanceof Component) {
((Component) source).setBackground(Color.GREEN);
}
}
});
}
//creating menu panel
JPanel menupanel = new JPanel();
//creating buttons for menu
JButton save = new JButton("Save");
JButton load = new JButton("Load");
save.setPreferredSize(new Dimension(100, 100));
load.setPreferredSize(new Dimension(100, 100));
//adding buttons to menu panel
menupanel.add(save);
menupanel.add(load);
//adding panels into frame
frame.add(userpanel, BorderLayout.WEST);
frame.add(menupanel, BorderLayout.CENTER);
frame.add(comppanel, BorderLayout.EAST);
frame.setVisible(true);
frame.setSize(2000, 1000);
}
}
As I say, it works perfectly on my Windows Eclipse but not on Mac
Can I scroll a JPanel using JButtons added to a JToolBar?
When I generate a large number of thumbnails, they don't all fit onto the JPanel. I want to use an up/down arrow JButton to scroll. Can this be done, and if so, how?
NOTE: I am trying to do this without a JScrollPane because I want the custom arrow icons, not a standard scroll bar.
Here is an SSCCE:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class PicSlider2 {
private JButton thumbs;
private JButton[] thumbnails;
private JLabel picViewer;
private JPanel thumbPanel;
private JToolBar toolBar;
public PicSlider2() {
final JFrame frame = new JFrame("Picture Slider");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(800, 600));
frame.setResizable(false);
frame.setLayout(new BorderLayout());
picViewer = new JLabel();
picViewer.setText("Image here");
picViewer.setHorizontalAlignment(JLabel.CENTER);
picViewer.setVerticalAlignment(JLabel.BOTTOM);
picViewer.setBorder(new LineBorder(Color.BLACK, 2));
JMenuBar frameMenuBar = new JMenuBar();
frame.setJMenuBar(frameMenuBar);
JMenu file = new JMenu("File");
frameMenuBar.add(file);
JMenuBar picViewerMenu = new JMenuBar();
picViewerMenu.setLayout(new FlowLayout(FlowLayout.LEFT));
thumbs = new JButton("THUMBNAILS");//an icon in actual program
thumbs.setPreferredSize(new Dimension(150,45));
thumbs.setToolTipText("Thumbnails");
thumbs.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
picViewer.setVisible(false);
thumbPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20,20));
thumbPanel.setBorder(BorderFactory.createEmptyBorder(50,100,50,30));
thumbnails = new JButton[30];//example size, chosen so all buttons won't fit on one page
for (int i = 0; i < 30; i++) {
thumbnails[i] = new JButton(Integer.toString(i));
thumbnails[i].setPreferredSize(new Dimension(100, 100));
thumbnails[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("thumbnail clicked - opens full-size view of pic in the JLabel picViewer");
}
});
thumbPanel.add(thumbnails[i]);
thumbPanel.setVisible(true);
}
toolBar = new JToolBar(null, JToolBar.VERTICAL);
toolBar.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 30));
JButton up = new JButton("Up Arrow");
up.setPreferredSize(new Dimension(80,60));
up.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Up Arrow Stub - NEEDS TO SCROLL UP PAGE, as needed");
}
} );
JButton down = new JButton("Down Arrow");
down.setPreferredSize(new Dimension(80,60));
down.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Down Arrow Stub - NEEDS TO SCROLL DOWN PAGE, as needed");
}
} );
toolBar.add(Box.createGlue());
toolBar.add(up);
toolBar.add(Box.createVerticalStrut(40));
toolBar.add(down);
toolBar.add(Box.createGlue());
frame.getContentPane().add(thumbPanel, BorderLayout.CENTER);
frame.getContentPane().add(toolBar, BorderLayout.LINE_END);
}
});
picViewerMenu.add(thumbs);
frame.getContentPane().add(picViewerMenu, BorderLayout.SOUTH);
frame.add(picViewer, BorderLayout.CENTER);
frame.setLocation(300, 50);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PicSlider2 ps = new PicSlider2();
}
});
}
}
I am trying to do this without a JScrollPane because I want the custom arrow icons
You can use a JScrollPane and use the default scroll Action to create a button with your custom Icon:
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
public class ScrollPaneSSCCE extends JPanel
{
public ScrollPaneSSCCE()
{
setLayout( new BorderLayout() );
JTable table = new JTable(50, 5);
JScrollPane scrollPane = new JScrollPane( table );
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
add(scrollPane);
JScrollBar vertical = scrollPane.getVerticalScrollBar();
JPanel east = new JPanel( new BorderLayout() );
add(east, BorderLayout.EAST);
JButton north = new JButton( new ActionMapAction("UP", vertical, "negativeUnitIncrement") );
east.add(north, BorderLayout.NORTH);
JButton south = new JButton( new ActionMapAction("DOWN", vertical, "positiveUnitIncrement") );
east.add(south, BorderLayout.SOUTH);
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("ScrollPaneSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ScrollPaneSSCCE());
frame.setSize(200, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
You will need the Action Map Action class which is just a simple wrapper class that gets the default Action from the ActionMap of the specified component.
You will need to set the scroll increment for you panel. Since your image size is 100 you might want to use:
vertical.setUnitIncrement( 100 );
I found a way to achieve your desired result by reordering the items on the JPanel. The JFrame needs to be declared outside of the constructor. I added an index variable for tracking the scroll position and a reloadThumbs() method for reloading the reordered thumbs.
This is the entire code after the changes:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class PicSlider2 {
private JButton thumbs;
private JButton[] thumbnails;
private JLabel picViewer;
private JPanel thumbPanel;
private JToolBar toolBar;
private int scrollIndex;
private final JFrame frame;
public PicSlider2() {
scrollIndex = 0;
frame = new JFrame("Picture Slider");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(800, 600));
frame.setResizable(false);
frame.setLayout(new BorderLayout());
picViewer = new JLabel();
picViewer.setText("Image here");
picViewer.setHorizontalAlignment(JLabel.CENTER);
picViewer.setVerticalAlignment(JLabel.BOTTOM);
picViewer.setBorder(new LineBorder(Color.BLACK, 2));
JMenuBar frameMenuBar = new JMenuBar();
frame.setJMenuBar(frameMenuBar);
JMenu file = new JMenu("File");
frameMenuBar.add(file);
JMenuBar picViewerMenu = new JMenuBar();
picViewerMenu.setLayout(new FlowLayout(FlowLayout.LEFT));
thumbs = new JButton("THUMBNAILS");//an icon in actual program
thumbs.setPreferredSize(new Dimension(150,45));
thumbs.setToolTipText("Thumbnails");
thumbs.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
picViewer.setVisible(false);
thumbPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20,20));
thumbPanel.setBorder(BorderFactory.createEmptyBorder(50,100,50,30));
thumbnails = new JButton[30];//example size, chosen so all buttons won't fit on one page
for (int i = 0; i < 30; i++) {
thumbnails[i] = new JButton(Integer.toString(i));
thumbnails[i].setPreferredSize(new Dimension(100, 100));
thumbnails[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("thumbnail clicked - opens full-size view of pic in the JLabel picViewer");
}
});
thumbPanel.add(thumbnails[i]);
thumbPanel.setVisible(true);
}
toolBar = new JToolBar(null, JToolBar.VERTICAL);
toolBar.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 30));
JButton up = new JButton("Up Arrow");
up.setPreferredSize(new Dimension(80,60));
up.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Up Arrow Stub - NEEDS TO SCROLL UP PAGE, as needed");
if(scrollIndex > 3) scrollIndex -= 4;
else scrollIndex = 0;
reloadThumbs();
}
} );
JButton down = new JButton("Down Arrow");
down.setPreferredSize(new Dimension(80,60));
down.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Down Arrow Stub - NEEDS TO SCROLL DOWN PAGE, as needed");
if(scrollIndex < 27) scrollIndex += 4;
else scrollIndex = 30;
reloadThumbs();
}
} );
toolBar.add(Box.createGlue());
toolBar.add(up);
toolBar.add(Box.createVerticalStrut(40));
toolBar.add(down);
toolBar.add(Box.createGlue());
frame.getContentPane().add(thumbPanel, BorderLayout.CENTER);
frame.getContentPane().add(toolBar, BorderLayout.LINE_END);
}
});
picViewerMenu.add(thumbs);
frame.getContentPane().add(picViewerMenu, BorderLayout.SOUTH);
frame.add(picViewer, BorderLayout.CENTER);
frame.setLocation(300, 50);
frame.pack();
frame.setVisible(true);
}
private void reloadThumbs(){
thumbPanel.removeAll();
for(int i = scrollIndex; i < 30; ++i){
thumbPanel.add(thumbnails[i]);
}
for(int i = 0; i < scrollIndex; ++i){
thumbPanel.add(thumbnails[i]);
}
thumbPanel.revalidate();
frame.revalidate();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PicSlider2 ps = new PicSlider2();
}
});
}
}
I'm using a JPopupMenu which contains multiple jCheckBoxMenuItem. User can check/uncheck several CheckBox. But when I click on JFrame the PopupMenu is not hiding.
This the entire code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PopupTest extends JFrame {
JButton button1;
public PopupTest() {
setTitle("Popup Test !");
setSize(400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
button1 = new JButton("Click me!");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int count = 250; // this count value is dynamic
JPopupMenu menu = new JPopupMenu();
JCheckBoxMenuItem item = null;
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(125, 200));
for (int i = 1; i <= count; i++) {
item = new JCheckBoxMenuItem("Page : " + i, new ImageIcon("test.png"));
item.setHorizontalTextPosition(JMenuItem.RIGHT);
item.addActionListener(new OpenAction(menu, button1));
panel.add(item);
}
menu.add(scrollPane);
JCheckBoxMenuItem selectAll = new JCheckBoxMenuItem("Select All", new ImageIcon("test.png"));
selectAll.addActionListener(new OpenAction(menu, button1));
menu.insert(selectAll, 0);
if (!menu.isVisible()) {
Point p = button1.getLocationOnScreen();
menu.setLocation((int) p.getX(), (int) p.getY() + button1.getHeight());
menu.setVisible(true);
} else {
menu.setVisible(false);
}
}
});
add(button1);
}
private static class OpenAction implements ActionListener {
private JPopupMenu menu;
private JButton button;
private OpenAction(JPopupMenu menu, JButton button) {
this.menu = menu;
this.button = button;
}
#Override
public void actionPerformed(ActionEvent e) {
String chkBoxText = e.getActionCommand().toString();
AbstractButton aButton = (AbstractButton) e.getSource();
boolean selected = aButton.getModel().isSelected();
Icon checkedIcon = new ImageIcon("test1.png");
Icon uncheckedIcon = new ImageIcon("test.png");
JScrollPane pane = null;
JViewport viewport = null;
JPanel panel = null;
JCheckBoxMenuItem item = null;
pane = (JScrollPane) menu.getComponent(1); //0th component is "Select All" check box
viewport = pane.getViewport();
panel = (JPanel) viewport.getComponent(0);
int totalChkBoxComponent = panel.getComponentCount();
if (selected) {
System.out.println(chkBoxText + " is Checked!");
if (chkBoxText.trim().equalsIgnoreCase("select all")) {
for (int i = 0; i < totalChkBoxComponent; i++) {
item = (JCheckBoxMenuItem) panel.getComponent(i);
item.setSelected(selected);
item.setIcon(item.isSelected() ? checkedIcon : uncheckedIcon);
}
}
} else if (!selected) {
System.out.println(chkBoxText + " is Un-Checked!");
if (chkBoxText.trim().equalsIgnoreCase("select all")) {
for (int i = 0; i < totalChkBoxComponent; i++) {
item = (JCheckBoxMenuItem) panel.getComponent(i);
item.setSelected(selected);
item.setIcon(item.isSelected() ? checkedIcon : uncheckedIcon);
}
} else { // this is for, after checking "Select All", if any other is unchecked, then "Select ALL" should be unchecked.
item = (JCheckBoxMenuItem) menu.getComponent(0);
item.setSelected(selected);
item.setIcon(selected ? checkedIcon : uncheckedIcon);
}
}
aButton.setIcon(aButton.isSelected() ? checkedIcon : uncheckedIcon);
}
}
public static void main(String args[]) {
new PopupTest();
}
}
Please help. Thanks.
First of all, your code is not really the best way to do such thing. You shouldn't create a new menu each time the button is clicked but rather create it once and keep a reference to it as field.
The reason PopupMenu does not hide is that you explicitly call setVisible(true); and you try to setVisible(false); in the very same ActionListener which is assigned to the button, not the frame.
You could:
1. Add another listener to the frame to set menu visiblity to false when clicked
2. Use show method instead of setVisible:
menu.show(button1, 0, button1.getHeight());
instead of
menu.setLocation((int) p.getX(), (int) p.getY() + button1.getHeight());
menu.setVisible(true);
However in our case, this causes other issues with menu disappearing. IMO the best way is to redesign your code.