I want help somebody. I want to create a JPanel that will popup when i click on a button, it must appear there where the button is clicked, and it must not affect other components. An example of that is a JDateChooser, when you click on that button, a calendar appears right there, but when you click anywhere else, that panel disappears. what i want is to put a list of names in that panel when it pops. It is similar to JPopupmenu except that when you click anywhere else it must disappear.
I'm not sure what you're doing, but it seems to work just fine for me...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ButtonPopup {
public static void main(String[] args) {
new ButtonPopup();
}
public ButtonPopup() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
final JPopupMenu popup = new JPopupMenu();
DefaultListModel<String> model = new DefaultListModel<>();
model.addElement("Item 1");
model.addElement("Item 2");
model.addElement("Item 3");
model.addElement("Item 4");
model.addElement("Item 5");
JList list = new JList(model);
popup.setLayout(new BorderLayout());
popup.add(new JScrollPane(list));
final JButton button = new JButton("Pop");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Dimension size = popup.getPreferredSize();
int x = (button.getWidth() - size.width) / 2;
int y = button.getHeight();
popup.show(button, x, y);
}
});
list.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
popup.setVisible(false);
}
});
add(button);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
}
Related
I have a jPanel with background and I want to add a JToolbar on it.
My problem is when I add JToolbar its default background is bothering and I set it's opaque to false but has no effect.
I want to remove it's default background and make it transparent.
I read the following article but no help:
JToolbar background image
Here is my code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JToolBar;
public class Toolbar extends JToolBar {
private JButton manage;
private JButton add;
private JButton search;
private JButton exit;
public Toolbar() {
super();
manage = new JButton();
add = new JButton();
search = new JButton();
exit = new JButton();
ImageIcon icon = new ImageIcon("pics/Add-01.png");
Image img = icon.getImage();
Image newImage = img.getScaledInstance(80, 80, Image.SCALE_SMOOTH);
add.setIcon(new ImageIcon(newImage));
setOpaque(false);
setBackground(Color.RED);
add(add);
add(search);
add(manage);
add(exit);
}
}
Thank you for your support.
Not working code:
public class Toolbar extends JToolBar {
public Toolbar() {
setBackground(Color.RED);
setOpaque(false);
add(new JButton("add"));
}
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if (comp instanceof JButton) {
((JButton) comp).setContentAreaFilled(false);
}
}
}
Basically, the buttons are still "filling" their backgrounds. You can instruct them to not paint their content (background) through JButton#setContentAreaFilled
This example sets the background color of the JToolBar to red, so you can see that the buttons are now transparent. To make the tool bar transparent, simply add setOpaque(false) in the constructor
public class CustomToolBar extends JToolBar {
public CustomToolBar() {
setBackground(Color.RED);
}
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if (comp instanceof JButton) {
((JButton) comp).setContentAreaFilled(false);
}
}
}
Extended example....
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JButton manage = new JButton("Manage");
JButton add = new JButton("Add");
JButton search = new JButton("Search");
JButton exit = new JButton("Exit");
CustomToolBar tb = new CustomToolBar();
tb.add(manage);
tb.add(add);
tb.add(search);
tb.add(exit);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new TestPane());
frame.add(tb, BorderLayout.NORTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage bgImg;
public TestPane() {
setLayout(new BorderLayout());
try {
bgImg = ImageIO.read(new File("..."));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bgImg == null ? new Dimension(200, 200) : new Dimension(bgImg.getWidth(), bgImg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bgImg != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - bgImg.getWidth()) / 2;
int y = (getHeight() - bgImg.getHeight()) / 2;
g2d.drawImage(bgImg, x, y, this);
g2d.dispose();
}
}
}
public class CustomToolBar extends JToolBar {
public CustomToolBar() {
setBorder(new LineBorder(Color.BLACK, 2));
setOpaque(false);
}
#Override
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if (comp instanceof JButton) {
((JButton) comp).setContentAreaFilled(false);
}
}
}
}
I have the following JButton on the GUI interface I'm building.
I want to make the border around the button more thicker so it will stand out from the background. Is it possible to do this in Java?
You could simply use a LineBorder
JButton btn = ...;
btn.setBorder(BorderFactory.createLineBorder(Color.BLACK, 4));
Take a look at How to Use Borders for more details and ideas
Updating the border state based on the model state
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final Border NORMAL_BORDER = BorderFactory.createLineBorder(Color.BLACK, 4);
protected static final Border ROLLOVER_BORDER = BorderFactory.createLineBorder(Color.RED, 4);
public TestPane() {
JButton btn = new JButton("Click me!");
btn.setContentAreaFilled(false);
btn.setBorder(NORMAL_BORDER);
btn.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (btn.getModel().isRollover()) {
btn.setBorder(ROLLOVER_BORDER);
} else {
btn.setBorder(NORMAL_BORDER);
}
}
});
setLayout(new GridBagLayout());
add(btn);
}
}
}
Create a Border first -
Border border = new LineBorder(Color.WHITE, 13);
Then create a JButton and set the Border -
JButton button = new JButton("Button Name");
button.setBorder(border);
Hope it will Help.
Thanks a lot.
I'm making a piano interface and am trying to make it so that when the user clicks the white key it turns light gray, then when they release it. When I press the key, it beings the white key to the foreground and hides the black key.
Before clicking anything:
After clicking a few keys:
The keys are JPanels inside a JLayeredPanel and I'm setting the background colors to change the color. I'd like for the black keys to stay on top when I click the bottom keys. Is there any way I can do this? I'm using Netbeans GUI Builder
Start by having a closer look at How to Use Layered Panes. You need to specify the layer you want each component to reside, otherwise they will overlap each other
Just in case you miss it, they key factor here is the use of JLayeredPane#setLayer
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class TestLayer {
public static void main(String[] args) {
new TestLayer();
}
public TestLayer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JLayeredPane {
public TestPane() {
setLayout(new GridBagLayout());
ColorPane background = new ColorPane(Color.WHITE) {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
ColorPane foreground = new ColorPane(Color.BLACK) {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(background, gbc);
setLayer(background, 0);
add(foreground, gbc);
setLayer(foreground, 1);
}
#Override
public void doLayout() {
super.doLayout();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public class ColorPane extends JPanel {
public ColorPane(Color backGround) {
setBackground(backGround);
setBorder(new LineBorder(Color.RED));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
setBackground(Color.RED);
}
#Override
public void mouseReleased(MouseEvent e) {
setBackground(backGround);
}
});
}
}
}
}
I've noticed that ActionEvent would still be triggered within my group of JRadioButtonMenuItem even when specifying the conditional statement:
if(!button.isSelected())
//Do stuff
defaultTheme = new JRadioButtonMenuItem("Default theme");
defaultTheme.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(!defaultTheme.isSelected())
System.out.println("temp");
}
});
I have multiple theme options within my settings menu, however if a say (say default) is already selected, I don't want to execute any redundant code if the default menu is already selected and the user clicks on the already selected Radio Button.
ActionListener will tell you whenever the button is "actioned" (clicked, pressed, what ever), which doesn't always change it's state. Instead, you could attach a ItemListener to the buttons model, which will tell, more accurately, when the actual state of the button changes, for example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ButtonTest {
public static void main(String[] args) {
new ButtonTest();
}
public ButtonTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
ButtonGroup bg = new ButtonGroup();
final JRadioButton bananas = new JRadioButton("Bananas");
final JRadioButton apples = new JRadioButton("Apples");
bg.add(bananas);
bg.add(apples);
bananas.getModel().addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
System.out.println("Bananas " + bananas.isSelected());
}
});
apples.getModel().addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
System.out.println("Apples " + apples.isSelected());
}
});
add(bananas, gbc);
add(apples, gbc);
}
}
}
Not sure since I haven't seen the rest of your program, but you have to put all the radiobuttons in a ButtonGroup. Because if you don't it would be impossible to deselect the radiobutton.
I would like to have Eclipse behavior for mouse clicks outside menus and popup menus in Swing. Basically, in Eclipse, when you press the mouse OUTSIDE the menu, the menu disappears and the mouse press event is forwarded to the component on which you clicked with the mouse.
Irritatingly, Swing does not do this, and I can't find a way around it.
Right now, even with Windows LAF, i have to click a second time to get the component to register the mouse click.
For the sake of the response just do it on a table
final JPopupMenu popupMenu = new JPopupMenu();
JMenuItem viewProfile = new JMenuItem("View Profile");
viewProfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
popupMenu.add(viewProfile);
table.setComponentPopupMenu(popupMenu);
EDIT: here is a test code. I don't think it is convenient to add a mouse listener to every simple component so they can register mouse clicks after a popup menu. In the following example, the Table does implement it, but not the Button.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TestMouse {
public static void main(String[] args) {
new TestMouse();
}
private JLabel counter;
private int count;
private JPanel northPanel;
private JButton clickMe;
public TestMouse() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
DefaultTableModel model = new DefaultTableModel(new Object[] { "A", "B", "B", "B", "B", "B", "B" }, 10);
JTable table = new JTable(model);
northPanel = new JPanel();
clickMe = new JButton("Button");
clickMe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("clicked");
count++;
}
});
counter = new JLabel("0");
northPanel.add(counter);
northPanel.add(clickMe);
final JPopupMenu popupMenu = new JPopupMenu();
JMenuItem viewProfile = new JMenuItem("View Profile");
viewProfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
popupMenu.add(viewProfile);
table.setComponentPopupMenu(popupMenu);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("clicked");
count++;
counter.setText(String.valueOf(count));
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(northPanel, BorderLayout.NORTH);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I don't seem to be able to replicate the issue.
When I right click the table, the popup menu appears and when I click the table again (to dismiss the popup), the mouseClicked event is triggered.
Note the counter in the north position...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TestMouse {
public static void main(String[] args) {
new TestMouse();
}
private JLabel counter;
private int count;
public TestMouse() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
DefaultTableModel model = new DefaultTableModel(
new Object[]{"A", "B", "B", "B", "B", "B", "B"},
10
);
JTable table = new JTable(model);
counter = new JLabel("0");
final JPopupMenu popupMenu = new JPopupMenu();
JMenuItem viewProfile = new JMenuItem("View Profile");
viewProfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
popupMenu.add(viewProfile);
table.setComponentPopupMenu(popupMenu);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("clicked");
count++;
counter.setText(String.valueOf(count));
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(counter, BorderLayout.NORTH);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
A actual runnable example that demonstrates your problem would involve less guess work and better responses
I had exactly the same problem when closing JMenuBar popups, and this worked for me:
UIManager.put("PopupMenu.consumeEventOnClose", false);