I want to add/hide/remove jlayeredpanes dynamically on runtime and also should hide the contents on each pane when another pane is selected. I have tried the following code and i am not sure how to do this. The following code hides the content of each pane when alternate pane is selected but it does not hide its content constantly. When we mousemove over the hidden content area they are made visible again. Plz help me out in this!!
public class floorsetup {
public static void createfloor(String name)
{
String name1=name+"_pane";
JButton b = new JButton(name);
final JLayeredPane jp = new JLayeredPane();
jp.setName(name1);
floor_plan.dynamicPane_floors.put(name1, jp);
//jp.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jp.setAutoscrolls(true);
jp.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
jp.setMinimumSize(new java.awt.Dimension(1000, 700));
jp.setOpaque(true);
jp.setBounds(floor_plan.ground.getBounds());
floor_plan.jLayeredPane2.add(jp);
jp.addMouseListener(new java.awt.event.MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
//floor_plan.jLayeredPane2.setVisible(false);
int x = 0,y = 0;
//ComponentOrientation componentOrientation = jLayeredPane2.getComponentOrientation();
// Rectangle bounds = jLayeredPane2..getBounds();
// x=bounds.x;
//y=bounds.y;
//System.out.println(bounds);
x=evt.getX();
y=evt.getY();
System.out.println(x);
System.out.println(y);
// String name=floor_plan.table_name.getText();
String name="some name";
if(floor_plan.delete!=1)
tablesetup.addButton(name,x,y, (JLayeredPane) evt.getSource());
System.out.println((evt.getSource()));
}
});
b.setActionCommand(name);
b.setAlignmentX(Component.CENTER_ALIGNMENT);
b.setPreferredSize(new Dimension(125, 25));
b.setBackground(Color.green);
floor_plan.floors.add(b);
floor_plan.floors.add(Box.createRigidArea(new Dimension(10, 15)));
// b.setSize(125, 25);
floor_plan.dynamicButtons_floors.put(name, b);
MouseListenerClass M1 = new MouseListenerClass();
MouseClass M2 = new MouseClass();
b.addMouseMotionListener(M1);
b.addMouseListener(M2);
b.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if(floor_plan.delete==1)
{
removeButton(evt.getActionCommand());
}
else if(floor_plan.edit==1)
{
String edit_name = JOptionPane.showInputDialog("Name of the button:");
JButton source = (JButton) evt.getSource();
source.setActionCommand(edit_name);
source.setText(edit_name);
floor_plan.dynamicButtons_floors.put(edit_name, source);
}
else
{
String switcher=evt.getActionCommand();
switcher+="_pane";
switch_pane(switcher,evt);
}
}
});
floor_plan.floors.validate();
floor_plan.floors.repaint();
}
public static void removeButton(String name) {
JButton b = floor_plan.dynamicButtons_floors.remove(name);
floor_plan.jLayeredPane2.remove(b);
floor_plan.jLayeredPane2.invalidate();
floor_plan.jLayeredPane2.repaint();
}
public static void switch_pane(String name,ActionEvent evt)
{
JLayeredPane jp = floor_plan.dynamicPane_floors.get(name);
System.out.println(floor_plan.jLayeredPane2);
System.out.println(jp);
floor_plan.ground.setVisible(false);
floor_plan.ground.setEnabled(false);
jp.setVisible(true);
jp.moveToFront(floor_plan.ground);
}
}
This is the bit of code using getText(). but i am getting error!!
if(floor_plan.delete==1)
{
JButton source = (JButton) evt.getSource();
int index=floor_plan.floors.getComponentCount();
int val=0;
Component[] components = floor_plan.floors.getComponents();
for(int i=0; i<index;i++)
{
System.out.println(source.getName());
if(components[i].getText().equals(source.getName()))
{
val=i;
}
}
removeButton(evt.getActionCommand(),val);
}
It sounds like you might want to look at the JTabbedPane. This will allow you to have multiple tabs with different content in each tab. When a user selects a tab, only the content on that tab is shown.
Links:
JTabbedPane Javadocs
JTabbedPane Tutorial
To dynamically add a tab through a button, you could use code similar to the following:
JButton newTabButton = new JButton("Add Tab");
newTabButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
JPanel newTab = new JPanel();
newTab.setLayout(null);
// Dynamic panel is a JTabbedPane
dynamicPanel.addTab(JOptionPane.showInputDialog("Name of tab"), newTab);
}
});
Related
I am working on a simple counter swing app. I'm trying to make it so when you click the check box, it will stay on the top and display a message dialog being "On Top" or "Not On Top".
However, when I click the checkbox after compiling and running, both of the messages display, and after clicking OK on both messages, the checkbox isn't even enabled. If I were to remove the showMessageDialog, it would still function properly, but I want to learn how to appropriately implement this.
Thank you in advance. Here is all of the code for the program:
public Class Counter {
JFrame frame;
JPanel panel;
JButton button, clear;
JTextField textC;
JLabel label;
JCheckBox cbox;
boolean topC = false;
int icount = 0;
String scount;
String topStatus = "";
public Counter() {
gui();
setActions();
}
public void gui() {
frame = new JFrame("Counter Program");
panel = new JPanel();
label = new JLabel("Counter");
textC = new JTextField();
textC.setPreferredSize(new Dimension(72,28));
textC.setEditable(false);
button = new JButton("Click");
clear = new JButton("Clear");
cbox = new JCheckBox("Top");
frame.setSize(350,80);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(panel);
panel.add(label);
panel.add(textC);
panel.add(button);
panel.add(clear);
panel.add(cbox);
frame.setVisible(true);
}
public void setActions() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
icount++;
scount = Integer.toString(icount);
textC.setText(scount);
}
});
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
icount = 0;
textC.setText("");
}
});
cbox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
topC = !topC;
if (topC) {
topStatus = "Top";
}
else topStatus = "Not Top";
frame.setAlwaysOnTop(topC);
JOptionPane.showMessageDialog(frame, topStatus, "Top Setting", 1);
}
});
}
public static void main(String[]args) {
new Counter();
}
}
An ItemListener generates two events, one for the selection and one for the unselection (and vice versa). Read the section from the Swing tutorial on How to Write an ItemListener for more information and working exmaples if you really want to use an ItemListener.
Otherwise, use an ActionListener instead, it will only generate a single event.
So I am trying to create a virtual keyboard that can insert values in a Jtextfield of another Jframe. The problem is that the data is overlapping when editing other text fields. So, I tried renewing the object but it replaced the first Jtextfield value as well. what should i do with this, should i start from scratch or is there any other way? . Since, English is not my first language I am struggling to find the correct terminology to research the problem please enlighten me with your knowledge
import java.awt.*;
import javax.swing.*;
public class OnScreenKeyboard implements ActionListener {
JFrame keyboard;
static String keyboardKeys = "0123456789qwertyuiopasdfghjklzxcvbnm.< ";
JButton[] keys = new JButton[39];
GridLayout gl;
FlowLayout fl;
Dimension buttondimension;
JPanel panel1, panel2;
JToggleButton capslock;
private String message = "";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public OnScreenKeyboard() {
buttondimension = new Dimension(45, 40);
fl = new FlowLayout();
capslock = new JToggleButton("capslock");
panel1 = new JPanel(fl);
panel2 = new JPanel(fl);
char[] key = keyboardKeys.toCharArray();
for (int i = 0; i < 39; i++) {
keys[i] = new JButton(String.valueOf(key[i]));
keys[i].setFont(new Font("Arial", Font.PLAIN, 13));
if (i == 38) {
keys[i].setPreferredSize(new Dimension(100, 30));
} else {
keys[i].setPreferredSize(buttondimension);
}
keys[i].addActionListener(this);
}
keyboard = new JFrame("Keyboard");
keyboard.setSize(720, 220);
keyboard.setLocationRelativeTo(null);
keyboard.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
keyboard.setResizable(false);
Container content = keyboard.getContentPane();
content.setLayout(null);
panel1.setBounds(1, 1, 500, 210);
panel2.setBounds(510, 1, 200, 210);
for (int i = 0; i < 10; i++) {
panel2.add(keys[i]);
}
for (int i = 10; i < 39; i++) {
panel1.add(keys[i]);
}
panel1.add(capslock);
content.add(panel1);
content.add(panel2);
capslock.addActionListener(this);
keyboard.setVisible(true);
}
public static void main(String[] args) {
new OnScreenKeyboard();
}
public void reset(){
message = "";
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 36; i++) {
if (e.getSource() == keys[i]) {
setMessage(getMessage() + keys[i].getText());
break;
}
}
if (e.getSource() == capslock) {
if (capslock.isSelected()) {
for (int i = 10; i < 36; i++) {
keys[i].setFont(new Font("Arial", Font.PLAIN, 12));
keys[i].setText(keys[i].getText().toUpperCase());
}
} else if (!capslock.isSelected()) {
for (int i = 10; i < 36; i++) {
keys[i].setFont(new Font("Arial", Font.PLAIN, 13));
keys[i].setText(keys[i].getText().toLowerCase());
}
}
}
setMessage(getMessage());
//JOptionPane.showMessageDialog(null, getMessage());
}
}
this is the frame I am trying to put my values from the keyboard in
public class LoginScreen implements ActionListener, FocusListener {
JFrame frame;
Container content;
FlowLayout fl;
JTextField txtusername, txtpassword;
JLabel lblusername, lblpassword;
JPanel panel1, panel2;
JButton keyboard, signup, signin;
OnScreenKeyboard kyb;
Dimension text;
private void init() {
text =new Dimension(100, 30);
fl = new FlowLayout(FlowLayout.CENTER);
lblusername = new JLabel("enter username");
lblpassword = new JLabel("enter password");
txtusername = new JTextField();
txtpassword = new JPasswordField();
keyboard = new JButton("keyboard");
signup = new JButton("signup");
signin = new JButton("sign in");
panel1 = new JPanel(fl);
panel2 = new JPanel(fl);
keyboard = new JButton("keyboard");
txtusername.setPreferredSize(text);
txtpassword.setPreferredSize(text);
kyb = new OnScreenKeyboard();
}
public LoginScreen() {
init();
frame = new JFrame("BorderLayoutDemo");
frame.setTitle("Registration Form");
frame.setSize(300, 300);
frame.setDefaultCloseOperation(3);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
content = frame.getContentPane();
content.setLayout(new GridLayout(2, 1));
panel1.add(lblusername);
panel1.add(txtusername);
panel1.add(lblpassword);
panel1.add(txtpassword);
panel2.add(signup);
panel2.add(signin);
panel2.add(keyboard);
content.add(panel1);
content.add(panel2);
keyboard.addActionListener(this);
txtusername.addFocusListener(this);
txtpassword.addFocusListener(this);
}
public static void main(String[] args) {
new LoginScreen();
}
#Override
public void actionPerformed(ActionEvent e) {
if (!kyb.keyboard.isVisible()) {
if (e.getSource() == keyboard) {
kyb = new OnScreenKeyboard();
}
}
}
#Override
public void focusGained(FocusEvent e) {
if(txtusername == e.getSource()){
txtusername.setText(kyb.getMessage());
}else if(txtpassword == e.getSource()){
kyb.reset();
txtpassword.setText(kyb.getMessage());
}
}
#Override
public void focusLost(FocusEvent e) {
}
The problem is that it's weird how/when the text is taken from the keyboard.
You use the LoginScreen both as actionListener on the keyboard and as focusListener on the 2 textfields.
The way you implemented it now is that you "type" something in on the keyboard and after that put the focus on 1 of the 2 fields. Only at the moment you click the text from the keyboard is fetched (kyb.getMessage()).
It's especially a problem on the password. If you click on the txtpassword field you first reset the kyb and then fetch the message (which you just reset so is empty).
What felt weird for me is that you don't have a way in the keyboard to notion that you are done typing. So the flow of only getting the message when the focus changes to one of the text fields is wrong.
What I would do is create a new kind of KeyboardListener. This listener is put on the txtusername OR txtpassword depending on who last took focus (so in the focusGained() you should change who is listening to the keyboard).
Then each time a key is "typed" you should notify the listener of the letter and then the txtusername/txtpassword (whichever is listening at that time) should add that letter to its text.
This means that the keyboard itself doesn't need to remember any text. It just figures out which key was pressed and then sends the corresponding letter to the listener.
You should be using a TextAction as your ActionListener. The TextAction has a method getFocusedComponent() which will return the last text component to have focus.
Then in the can add the character to the text field. So the basic code in the actionPerformed(...) method of the TextAction might be something like:
JTextComponent component = getFocusedComponent();
component.replaceSelection( the character to add );
I want to ask what function or another have to write so that every time I pressed the Start button (function:addbutton), the other button to exit (function:addButton2) to change its title to how many times I press the start?
class DroppingFrame extends JFrame {
public DroppingFrame() {
int clicked=0;
String b="a";
setSize(1400, 700);
setTitle("Dropping");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Container contentPane = getContentPane();
canvas = new JPanel();
contentPane.add(canvas, "Center");
JPanel p = new JPanel();
addButton(p, "Drop ball", clicked, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//addButton.setText(String.valueOf(++clicked));
Ball b = new Ball(canvas);
// if(b== new Ball(canvas)){
// clicked++;
// }
b.start();
}
});
addButton2(p, b, clicked, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canvas.setVisible(false);
System.exit(0);
}
});
contentPane.add(p, "South");
}
public void addButton(Container c, String title, int i, ActionListener a) {
//i++;
//title = Integer.toString(i);
JButton b = new JButton(title);
c.add(b);
b.addActionListener(a);
}
public void addButton2(Container c, String title, int i, ActionListener a ) {
i++;
title = Integer.toString(i);
JButton b = new JButton(title);
c.add(b);
b.addActionListener(a);
}
private JPanel canvas;
}
My preference would be:
Make clicked a class field - that way you can access it and mutate it inside the event handler
Create a class field for a button
Refactor the addButton method so there is only one of them - this makes your code tidier:
Change the method return type to return the button created, then you decide if you store it or not from the caller. This just smells nicer.
The code looks like:
class DroppingFrame extends JFrame {
final JPanel canvas = new JPanel();
JButton button2;
int clicked = 0;
public DroppingFrame() {
setSize(1400, 700);
setTitle("Dropping");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Container contentPane = getContentPane();
contentPane.add(canvas, "Center");
JPanel p = new JPanel();
addButton(p, "Drop ball", clicked, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
Ball b = new Ball(canvas);
b.start();
button2.setText(String.valueOf(++clicked));
}
});
button2 = addButton(p, String.valueOf(clicked), clicked, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canvas.setVisible(false);
System.exit(0);
}
});
contentPane.add(p, "South");
}
public JButton addButton(Container c, String title, int i, ActionListener a) {
JButton b = new JButton(title);
c.add(b);
b.addActionListener(a);
return b;
}
}
It requires the reference of the second button so that start button can update its text.
Keep it simple:
Use setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); instead of adding WindowListener to close the window.
Use JFrame#dispose to close the JFrame programmatically.
Favor Composition over Inheritance It means if you are not overriding any logic/implementation of the existing class then don't extend it.
There is no meaning of creating separate method for adding each component. Either make the method generic or simply remove it.
Sample code:
public class DroppingFrame {
private int clicked = 0;
public DroppingFrame() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel p = new JPanel();
final JButton btn2 = new JButton(String.valueOf(clicked));
btn2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
frame.dispose();
}
});
JButton btn1 = new JButton("Drop ball");
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
btn2.setText(String.valueOf(++clicked));
}
});
p.add(btn1);
p.add(btn2);
contentPane.add(p, BorderLayout.SOUTH);
frame.setVisible(true);
}
}
It's not correct.. addButton always creates a new button and its reference is lost.. you should make it class-scoped.
So make a class variable:
JButton button = new JButton();
Change your function:
public void addButton(Container c, String title, int i, ActionListener a) {
button.setText(title);
c.add(button);
button.addActionListener(a);
}
And also change your actionPerformed override:
public void actionPerformed(ActionEvent evt) {
button.setText(String.valueOf(++clicked));
....
});
I have a JPopupMenu and I want to change it's inner size dynamically depending on it's inner components' size. In my SSCCE I described the problem.
SSCCE:
public class PopupTest2 {
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));
final JPopupMenu menu = new JPopupMenu();
// critical step
JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), 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);
}
});
}
}
Steps 2 reproduce:
Right-click to show popup menu.
Click the Press me button (on the top of window).
Right-click to show popup menu again (bug #1 - popup is still small-size)
Right-click to show popup menu again (popup menu size is OK)
Click the Press me button again.
Right-click to show popup menu. (bug #2 - popup is still large-size)
How can I force JPopupMenu to change its size before showing? And why does it work if I add items directly to popupMenu?
Here is one way to do this:
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));
final JPopupMenu menu = new JPopupMenu();
// critical step
final JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
item.setMaximumSize(new Dimension(70, 50));
item.setPreferredSize(new Dimension(70, 50));
item.setMinimumSize(new Dimension(70, 50));
itemPanel.invalidate();
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
item.setMaximumSize(new Dimension(130, 50));
item.setPreferredSize(new Dimension(130, 50));
item.setMinimumSize(new Dimension(130, 50));
itemPanel.invalidate();
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), 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);
}
});
}
Thanks all, but I've found the solution after continuous debugging. The problem was in layout used in JPanel (between Popup and items). It called the getPreferredSize() of JPanel which called directly menuItem.getPrefferedSize(), which called BasicMenuItemUI.getPrefferedSize(). The last method uses the MainMenuLayoutHelper class to get the preferred size. This class stores the data about size in Properties static object.
The default JPopupMenu layout - DefaultMenuLayout - clears this static data each time its preferredLayoutSize() method called, with call MenuItemLayoutHelper.clearUsedClientProperties(popupMenu). We will do the same - call this method with our JPanel parameter with further revalidate() call:
public class PopupTest2 {
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());
final JPopupMenu menu = new JPopupMenu();
final JPanel itemPanel = new JPanel();
itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
final JMenuItem[] items = new JMenuItem[1];
for (int i = 0; i < 1; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
items[i] = item;
}
menu.updateUI();
menu.add(itemPanel);
JToggleButton button = new JToggleButton("Press me");
button.addActionListener(new ActionListener() {
boolean pressed = false;
#Override
public void actionPerformed(ActionEvent e) {
pressed = !pressed;
if (pressed) {
for (JMenuItem item : items) {
item.setText(item.getText()+" changed");
}
} else {
for (JMenuItem item : items) {
item.setText(item.getText().substring(0, item.getText().length() - 8));
}
}
}
});
panel.add(button, BorderLayout.NORTH);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
MenuItemLayoutHelper.clearUsedClientProperties(itemPanel);
itemPanel.revalidate();
menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), 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);
}
});
}
}
PS: Dear reader, it is not the best way to write your code. I do that because I really need that (I have such requirements). If you can build your JPopupMenu without JPanel inside, do not use code in this answer, please.
You have to add
menu.updateUI();
after add menu items.
final JMenuItem[] items = new JMenuItem[10];
for (int i = 0; i < 10; i++) {
JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
itemPanel.add(item);
item.setUI(new MyUI());
items[i] = item;
}
menu.updateUI(); <<<<<<--------
menu.add(itemPanel);
I'm working in with a JTabbedPane, I need to add a close button in the tabs to close the current one.
I have been searching and as I understand I must extend from JPanel and add the close button as they say here
But, is there a way to add the close buttons extending JTabbedPane or is there a easier way to do it?
Thanks in advance, I really appreciate your time and your help.
Essentially, you're going to need to supply a "renderer" for the tab. Take a look at JTabbedPane.setTabComponentAt(...) for more information.
The basic idea is to supply a component that will be laid out on the tab.
I typically create a JPanel, onto which I add a JLabel (for the title) and, depending on what I want to display, some kind of control that acts as the close action.
tabPane.addTab(title, tabBody);
int index = tabPane.indexOfTab(title);
JPanel pnlTab = new JPanel(new GridBagLayout());
pnlTab.setOpaque(false);
JLabel lblTitle = new JLabel(title);
JButton btnClose = new JButton("x");
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
pnlTab.add(lblTitle, gbc);
gbc.gridx++;
gbc.weightx = 0;
pnlTab.add(btnClose, gbc);
tabPane.setTabComponentAt(index, pnlTab);
btnClose.addActionListener(myCloseActionHandler);
Now somewhere else, I establish the action handler...
public class MyCloseActionHandler implements ActionListener {
public void actionPerformed(ActionEvent evt) {
Component selected = tabPane.getSelectedComponent();
if (selected != null) {
tabPane.remove(selected);
// It would probably be worthwhile getting the source
// casting it back to a JButton and removing
// the action handler reference ;)
}
}
}
Now, you just as easily use any component you like and attach a mouse listener to it and monitor the mouse clicks...
Updated
The above example will only remove the currently active tab, there are a couple of ways to fix this.
The best is to probably provide some means for the action to find the tab it's associated with...
public class MyCloseActionHandler implements ActionListener {
private String tabName;
public MyCloseActionHandler(String tabName) {
this.tabName = tabName;
}
public String getTabName() {
return tabName;
}
public void actionPerformed(ActionEvent evt) {
int index = tabPane.indexOfTab(getTabName());
if (index >= 0) {
tabPane.removeTabAt(index);
// It would probably be worthwhile getting the source
// casting it back to a JButton and removing
// the action handler reference ;)
}
}
}
This uses the name of tab (as used with JTabbedPane#addTab) to find and then remove the tab and its associated component...
I found a tab example (from the java site) that appears to do that, at least in theirs. (Though I thought, when I tried it in the past, that it also closed the currently selected tab, though it works properly when you run their example, though I think when I updated it to work on a tabbed java notepad, it was closing the currently selected tab, though maybe I did it wrong.
http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabComponentsDemoProject/src/components/ButtonTabComponent.java
Yes, my thing is working now! This WILL work for the actual tab, rather than the currently selected tab!
Hopefully you have got the answer to your question. I want to give a link that was very useful for me.
JTabbedPane with a close button
Here is some code as well.
public static void createAndShowGUI()
{
JFrame frame = new JFrame("Tabs");
frame.setMinimumSize(new Dimension(500, 200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTabbedPane tabbedPane = new JTabbedPane();
JPanel panel = new JPanel();
panel.setOpaque(false);
tabbedPane.add(panel);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel), getTitlePanel(tabbedPane, panel, "Tab1"));
JPanel panel1 = new JPanel();
panel1.setOpaque(false);
tabbedPane.add(panel1);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel1), getTitlePanel(tabbedPane, panel1, "Tab2"));
JPanel panel2 = new JPanel();
panel2.setOpaque(false);
tabbedPane.add(panel2);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel2), getTitlePanel(tabbedPane, panel2, "Tab3"));
JPanel panel3 = new JPanel();
panel3.setOpaque(false);
tabbedPane.add(panel3);
tabbedPane.setTabComponentAt(tabbedPane.indexOfComponent(panel3), getTitlePanel(tabbedPane, panel3, "Tab4"));
frame.add(tabbedPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
I made some changes in the code of oracle.
http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabComponentsDemoProject/src/components/ButtonTabComponent.java
Giving the possibility to add an icon to the tab , plus the close tab button. Hope that helps.
public static void addTag(JTabbedPane tab, String title, Icon icon, int index){
MouseListener close = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
//your code to remove component
//I use this way , because I use other methods of control than normal: tab.remove(int index);
}
};
final ButtonClose buttonClose = new ButtonClose (title, icon, close );
tab.setTabComponentAt(index, buttonClose);
tab.validate();
tab.setSelectedIndex(index);
}
public class ButtonClose extends JPanel {
public ButtonClose(final String title, Icon icon, MouseListener e) {
JLabel ic = new JLabel(icon);
ic.setSize(icone.getIconWidth(), icone.getIconHeight());
JLabel text= new JLabel(title);
text.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
ButtonTab button = new ButtonTab();
button.addMouseListener(e);
button.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
JPanel p = new JPanel();
p.setSize(getWidth() - icone.getIconWidth(), 15);
p.add(text);
p.add(button);
add(ic);
add(p);
}
private class ButtonTab extends JButton {
public ButtonTab() {
int size = 13;
setPreferredSize(new Dimension(size, size));
setToolTipText("Close");
setUI(new BasicButtonUI());
setFocusable(false);
setBorderPainted(false);
addMouseListener(listener);
setRolloverEnabled(true);
}
#Override
public void updateUI() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
if (getModel().isPressed()) {
g2.translate(1, 1);
}
g2.setStroke(new BasicStroke(2));
g2.setColor(new Color(126, 118, 91));
if (getModel().isRollover()) {
g2.setColor(Color.WHITE);
}
int delta = 3;
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
g2.dispose();
}
}
private final MouseListener listener = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
Component component = e.getComponent();
if (component instanceof AbstractButton) {
AbstractButton button = (AbstractButton) component;
button.setContentAreaFilled(true);
button.setBackground(new Color(215, 65, 35));
}
}
#Override
public void mouseExited(MouseEvent e) {
Component component = e.getComponent();
if (component instanceof AbstractButton) {
AbstractButton button = (AbstractButton) component;
button.setContentAreaFilled(false); //transparent
}
}
};
}
Check out Peter-Swing here. It has a JClosableTabbedPane class in it, as well as many others.
When you download the jar file you can run it and have examples of all the classes.
You can have a JLabel named "x" and use the mouseListener
private final JLabel l = new JLabel(); // this is the label for tabbedPane
private final JLabel b = new JLabel("x");//Close Button
if (closeable)
{
b.setToolTipText("Click to close");
b.setOpaque(false);
b.setBackground(Color.gray);
b.addMouseListener(new MouseAdapter()
{
#Override
public void mouseExited(MouseEvent e)
{
b.setBorder(bordere);
b.setOpaque(false);
}
#Override
public void mouseEntered(MouseEvent e)
{
b.setBorder(borderl);
}
#Override
public void mouseReleased(MouseEvent e)
{
b.setOpaque(false);
b.repaint();
if (b.contains(e.getPoint()))
{
b.setBorder(borderl);
if (confirmTabClosing())
{
tab.remove(tabIndex());
if(tab.getTabCount() == 0)
spacialTabComponent.maximizeOrRestore.doClick();
}
}
else
b.setBorder(bordere);
}
#Override
public void mousePressed(MouseEvent e)
{
b.setOpaque(true);
b.repaint();
}
});
b.setBorder(bordere);
add(b, getLeftAlignedBothFilledGBC(1, 0, new Insets(0, 0, 0, 0), 0, 0));
}
}
jbCloseButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int index = jtbMainTabbedPane.indexOfTabComponent(jbCloseButton);
jtbMainTabbedPane.remove(index);
}
});