I have a problem with comboboxes which display list of buttons. What I have now is
http://hizliresim.com/djQzr7
However I want something more like this
http://hizliresim.com/QXDE3G
First button is combobox and the second one is that combobox when it is clicked.
Here is the code
package asd;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
public class asd extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
asd frame = new asd();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public asd() {
try {
// Set System L&F
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
}
catch (UnsupportedLookAndFeelException e) {
// handle exception
}
catch (ClassNotFoundException e) {
// handle exception
}
catch (InstantiationException e) {
// handle exception
}
catch (IllegalAccessException e) {
// handle exception
}
ComboBoxRender renderer;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JComboBox comboBox = new JComboBox();
comboBox.setBounds(92, 85, 60, 40);
renderer = new ComboBoxRender();
comboBox.setRenderer(renderer);
comboBox.addItem("1");
comboBox.addItem("2");
comboBox.addItem("3");
comboBox.setPreferredSize(new Dimension(60, 40));
comboBox.setMinimumSize(new Dimension(70, 30));
comboBox.setMaximumSize(new Dimension(500, 500));
comboBox.setBackground(Color.GRAY);
comboBox.setUI(new javax.swing.plaf.metal.MetalComboBoxUI(){
public void layoutComboBox(Container parent, MetalComboBoxLayoutManager manager) {
super.layoutComboBox(parent, manager);
arrowButton.setBounds(0,0,0,0);
}
});
contentPane.add(comboBox);
}
}
class ComboBoxRender implements ListCellRenderer<Object> {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,boolean isSelected, boolean cellHasFocus) {
JButton btn = new JButton(value.toString());
btn.setSelected(false);
btn.setBorderPainted(true);
btn.setBackground(Color.gray);
btn.setSize(new Dimension(100, 100));
btn.setMargin(new Insets(1, 1, 1, 1));
btn.setMinimumSize(new Dimension(200,200));
return btn;
}
}
For that you need to use ListCellRenderer. Read about custom renderers.
For example :
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class TestFrame extends JFrame {
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
JComboBox<String> box = new JComboBox<>(new String[]{"1","2"});
box.setRenderer(getRenderer());
add(box);
}
private ListCellRenderer<? super String> getRenderer() {
return new ListCellRenderer<String>() {
private JButton btn = new JButton();
public Component getListCellRendererComponent(JList<? extends String> list,String value, int index,
boolean isSelected, boolean cellHasFocus) {
btn.setText(value);
return btn;
};
};
}
public static void main(String args[]) {
new TestFrame();
}
}
Related
Try to use some "dark side" features of Swing and got problem when I try to populate the popup of a combo-box with some components. Here is my SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* #param combo combo-box to get new popup component.
* #param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
c.setPreferredSize(comp.getPreferredSize());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
I can open the combo-box but when I click a check-box in the popup the combo-box goes closed and check-box is still not selected. But, when I change the line
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
to
frm.add(new ComboBoxTryout(), BorderLayout.SOUTH);
all works fine: I can change state of check-boxes and popup is still visible! Any suggestions, how to get it working for BorderLayout.NORTH?
The following doesn't use a regular JComboBox, but rather mimics one to give you more control.
This example is inspired from Creating Pop-Up Components and from your code.
It uses a Popup component and listeners on the button and on the textfield (textfield + button to look like a combobox, this part is not visually optimized in this example) to manage the popup hiding/showing.
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingConstants;
public class ButtonPopupSample {
private final JTextField tField;
private final JButton start;
private final JPanel panel;
private boolean popping = false;
private Popup popup;
ButtonPopupSample() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
JFrame frame = new JFrame("Button Popup Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tField = new JTextField(20);
tField.setEditable(false);
start = new JButton("Pop");
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
popOrNot();
}
};
start.addActionListener(actionListener);
tField.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent me) {
popOrNot();
}
});
JPanel contPan = new JPanel();
contPan.add(tField);
contPan.add(start);
frame.setContentPane(contPan);
frame.setSize(350, 250);
frame.setVisible(true);
}
private JCheckBox createCheckBox(final String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
tField.setText(b.toString());
}
});
return cb;
}
private void popOrNot() {
if (popping) {
popup.hide();
} else {
PopupFactory factory = PopupFactory.getSharedInstance();
Point location = tField.getLocationOnScreen();
popup = factory.getPopup(tField, panel, location.x, location.y + tField.getHeight());
popup.show();
}
popping = !popping;
}
public static void main(final String args[]) {
new ButtonPopupSample();
}
}
Solution found. A strange focus change event provides the above described problem. So processing of this event must be prevented.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
#SuppressWarnings("serial")
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
private boolean avoidFocusChange;
/**
*
*/
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
#Override
protected void processFocusEvent(FocusEvent e) {
if (avoidFocusChange && FocusEvent.FOCUS_LOST == e.getID() && panel.isAncestorOf(e.getOppositeComponent())) {
System.out.println(e); // skip it
} else {
super.processFocusEvent(e);
}
avoidFocusChange = false;
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
cb.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
avoidFocusChange = SwingUtilities.isLeftMouseButton(e);
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* #param combo combo-box to get new popup component.
* #param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
Dimension dim = comp.getPreferredSize();
dim.width += 10; // need 10 px more width
c.setPreferredSize(dim);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
If somebody finds a better solution, please post it!!!
I'm writing a program where there is a JTable to be created (Which I'm able to). But I want to add a scroll bar to it. Below is my code.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class TagReplaceUI extends JFrame {
private JPanel contentPane;
private JTextField srcTextField;
private Executor executor = Executors.newCachedThreadPool();
static DefaultTableModel model = new DefaultTableModel();
static JTable table = new JTable(model);
/**
* Launch the application.
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
final TagReplaceUI frame = new TagReplaceUI();
frame.add(new JScrollPane(table));
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
// FileDownloadTest downloadTest = new
// FileDownloadTest(srcTextField.getText(), textArea);
public TagReplaceUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 552, 358);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
srcTextField = new JTextField();
srcTextField.setBounds(10, 26, 399, 20);
contentPane.add(srcTextField);
srcTextField.setColumns(10);
JButton srcBtn = new JButton("Source Excel");
srcBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fChoose = new JFileChooser();
fChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fChoose.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
srcTextField.setText(fChoose.getSelectedFile().getAbsolutePath());
} else {
System.out.println("No Selection");
}
}
});
table.setBounds(10, 131, 516, 178);
contentPane.add(table);
model.addColumn("Col1");
model.addColumn("Col2");
srcBtn.setBounds(419, 25, 107, 23);
contentPane.add(srcBtn);
JButton dNcButton = new JButton("Process");
dNcButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
executor.execute(new Test(srcTextField.getText(), model));
}
});
dNcButton.setBounds(212, 70, 89, 23);
contentPane.add(dNcButton);
}
}
When I run the above program, the table frame is also not displayed. But when I remove frame.add(new JScrollPane(table));, it is displaying the table in the JTable area, but there is no scrollbar in it.
Please let me know how can I get a scrollbar in the table and display the data correctly.
Thanks
At first don't use null layout, please read here.
frame.add(new JScrollPane(table)); this scroll pane is not displaying because in null layout each component needs to have bounds. Try below code. I just changed static variables to instance variables. And added scrollpane in to the constructor.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
public class TagReplaceUI extends JFrame {
private JPanel contentPane;
private JTextField srcTextField;
private Executor executor = Executors.newCachedThreadPool();
private DefaultTableModel model = new DefaultTableModel();
private JTable table = new JTable(model);
/**
* Launch the application.
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
final TagReplaceUI frame = new TagReplaceUI();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
// FileDownloadTest downloadTest = new
// FileDownloadTest(srcTextField.getText(), textArea);
public TagReplaceUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 552, 358);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
srcTextField = new JTextField();
srcTextField.setBounds(10, 26, 399, 20);
contentPane.add(srcTextField);
srcTextField.setColumns(10);
JButton srcBtn = new JButton("Source Excel");
srcBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fChoose = new JFileChooser();
fChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fChoose.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
srcTextField.setText(fChoose.getSelectedFile().getAbsolutePath());
} else {
System.out.println("No Selection");
}
}
});
JScrollPane scroll = new JScrollPane(table);
scroll.setBounds(10, 131, 516, 178);
contentPane.add(scroll);
model.addColumn("Col1");
model.addColumn("Col2");
srcBtn.setBounds(419, 25, 107, 23);
contentPane.add(srcBtn);
JButton dNcButton = new JButton("Process");
dNcButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
executor.execute(new Test(srcTextField.getText(), model));
}
});
dNcButton.setBounds(212, 70, 89, 23);
contentPane.add(dNcButton);
}
}
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 a Class that adds an ImageIcon in the East of a TextField if you pass it to that Class, it's working pretty good during runtime if I press a Button to change frames, but the Image is not showing up at the startup.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class TestStartFrame extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
TestStartFrame frame = new TestStartFrame();
frame.setVisible(true);
} catch (Exception e)
{
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestStartFrame()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JButton btnNewButton = new JButton("New button");
contentPane.add(btnNewButton, BorderLayout.CENTER);
btnNewButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
SecondFrame fr = new SecondFrame();
fr.setVisible(true);
try
{
int r = 250;
int g = 250;
int b = 250;
UIManager.put("control", new Color(r, g, b));
UIManager
.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
UIManager.put("control", new Color(r, g, b));
SwingUtilities
.updateComponentTreeUI(SecondFrame.contentPane);
} catch (Exception e1)
{
System.out.println(e1.getMessage());
}
dispose();
}
});
}
}
class SecondFrame extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
public final static JPanel contentPane = new JPanel();
/**
* Create the frame.
*/
public SecondFrame()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout());
JTextField txt = new JTextField();
contentPane.add(txt, BorderLayout.CENTER);
txt = ClearImage.addImage(txt);
}
}
class ClearImage
{
public static JTextField addImage(final JTextField comp)
{
Image image = new BufferedImage(10, 25, BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, 10, 25);
graphics.setColor(Color.LIGHT_GRAY);
graphics.fillOval(0, 7, 10, 10);
graphics.setColor(Color.GRAY);
graphics.drawLine(2, 9, 8, 15);
graphics.drawLine(2, 15, 8, 9);
JLabel lblClear = new JLabel(new ImageIcon(image));
comp.setLayout(new BorderLayout());
comp.add(lblClear, BorderLayout.EAST);
lblClear.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
lblClear.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
comp.setText("");
}
});
return comp;
}
public static JTextField removeImage(final JTextField comp)
{
comp.removeAll();
return comp;
}
}
If I place the UI change before the Frame visible, I don't have that problem, could anyone explain me why is it that way?
Your problem is caused by the change of UI factory on the JTextField (this is triggered by the installation of the Nimbus L&F and the updateComponentTreeUI()).
When you do that the second call, you automatically uninstall the previous L&F and UI factory of the JTextField. By default, this is Metal L&F Text UI (MetalTextFieldUI) which extends BasicTextUI. This invokes the method javax.swing.plaf.basic.BasicTextUI.uninstallUI(JComponent) and its content is the following:
public void uninstallUI(JComponent c) {
// detach from the model
editor.removePropertyChangeListener(updateHandler);
editor.getDocument().removeDocumentListener(updateHandler);
// view part
painted = false;
uninstallDefaults();
rootView.setView(null);
c.removeAll();
LayoutManager lm = c.getLayout();
if (lm instanceof UIResource) {
c.setLayout(null);
}
// controller part
uninstallKeyboardActions();
uninstallListeners();
editor = null;
}
Notice the call c.removeAll() which basically removes your label from the hierarchy and hence causes the issue you are seeing.
Arguably, we could say that adding components to primitive Swing widgets is not ideal and this is not how they were intended to be used. I personally find that argument quite weak, but I know that many Swing lovers are found of it.
Simply make sure to do the update of the UI before adding your JLabel or extends JTextField and upon update of the UI, re-install your JLabel in the JTextField.
Small example (just to demo my explanation):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class TestAddImageToTextField {
private static class MyJTextField extends JTextField {
#Override
public void updateUI() {
removeAll();
super.updateUI();
Image image = buildImage();
JLabel lblClear = new JLabel(new ImageIcon(image));
lblClear.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
MyJTextField.this.setText("");
}
});
setLayout(new BorderLayout());
add(lblClear, BorderLayout.EAST);
}
private Image buildImage() {
Image image = new BufferedImage(10, 25, BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, 10, 25);
graphics.setColor(Color.LIGHT_GRAY);
graphics.fillOval(0, 7, 10, 10);
graphics.setColor(Color.GRAY);
graphics.drawLine(2, 9, 8, 15);
graphics.drawLine(2, 15, 8, 9);
return image;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestAddImageToTextField frame = new TestAddImageToTextField();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private JComponent contentPane;
/**
* Create the frame.
*
* #throws UnsupportedLookAndFeelException
* #throws IllegalAccessException
* #throws InstantiationException
* #throws ClassNotFoundException
*/
public TestAddImageToTextField() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 450, 300);
contentPane = (JComponent) frame.getContentPane();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
MyJTextField comp = new MyJTextField();
contentPane.add(comp);
frame.setVisible(true);
installNimbusLAF();
}
private void installNimbusLAF() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
int r = 250;
int g = 250;
int b = 250;
UIManager.put("control", new Color(r, g, b));
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
UIManager.put("control", new Color(r, g, b));
SwingUtilities.updateComponentTreeUI(contentPane);
}
}
I have a problem with my JLayeredPane, I am probably doing something incredibly simple but I cannot wrap my head around it. The problem i have is that all the components are merged together and have not order. Could you please rectify this as I have no idea. The order I am trying to do is have a layout like this
output
label1 (behind)
input (in Front)
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class window extends JFrame implements KeyListener {
/**
*
*/
private static final long serialVersionUID = 7092006413113558324L;
private static int NewSize;
public static String MainInput;
public static JLabel label1 = new JLabel();
public static JTextField input = new JTextField(10);
public static JTextArea output = new JTextArea(main.Winx, NewSize);
public window() {
super("Satine. /InDev-01/");
JLabel label1;
NewSize = main.Winy - 20;
setLayout(new BorderLayout());
output.setToolTipText("");
add(input, BorderLayout.PAGE_END);
add(output, BorderLayout.CENTER);
input.addKeyListener(this);
input.requestFocus();
ImageIcon icon = new ImageIcon("C:\\Users\\" + System.getProperty("user.name") + "\\AppData\\Roaming\\.Satine\\img\\textbox.png", "This is the desc");
label1 = new JLabel(icon);
add(label1, BorderLayout.PAGE_END);
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
try {
MainMenu.start();
} catch (IOException e1) {
System.out.print(e1.getCause());
}
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
And the main class.
import java.awt.Container;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
public class main {
public static int Winx, Winy;
private static JLayeredPane lpane = new JLayeredPane();
public static void main(String[] args) throws IOException{
Winx = window.WIDTH;
Winy = window.HEIGHT;
window Mth= new window();
Mth.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Mth.setSize(1280,720);
Mth.setVisible(true);
lpane.add(window.label1);
lpane.add(window.input);
lpane.add(window.output);
lpane.setLayer(window.label1, 2, -1);
lpane.setLayer(window.input, 1, 0);
lpane.setLayer(window.output, 3, 0);
Mth.pack();
}
}
Thank you for your time and I don't expect the code to be written for me, all I want is tips on where I am going wrong.
I recommend that you not use JLayeredPane as the overall layout of your GUI. Use BoxLayout or BorderLayout, and then use the JLayeredPane only where you need layering. Also, when adding components to the JLayeredPane, use the add method that takes a Component and an Integer. Don't call add(...) and then setLayer(...).
Edit: it's ok to use setLayer(...) as you're doing. I've never used this before, but per the API, it's one way to set the layer.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class LayeredPaneFun extends JPanel {
public static final String IMAGE_PATH = "http://duke.kenai.com/" +
"misc/Bullfight.jpg";
public LayeredPaneFun() {
try {
BufferedImage img = ImageIO.read(new URL(IMAGE_PATH));
ImageIcon icon = new ImageIcon(img);
JLabel backgrndLabel = new JLabel(icon);
backgrndLabel.setSize(backgrndLabel.getPreferredSize());
JPanel forgroundPanel = new JPanel(new GridBagLayout());
forgroundPanel.setOpaque(false);
JLabel fooLabel = new JLabel("Foo");
fooLabel.setFont(fooLabel.getFont().deriveFont(Font.BOLD, 32));
fooLabel.setForeground(Color.cyan);
forgroundPanel.add(fooLabel);
forgroundPanel.add(Box.createRigidArea(new Dimension(50, 50)));
forgroundPanel.add(new JButton("bar"));
forgroundPanel.add(Box.createRigidArea(new Dimension(50, 50)));
forgroundPanel.add(new JTextField(10));
forgroundPanel.setSize(backgrndLabel.getPreferredSize());
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(backgrndLabel.getPreferredSize());
layeredPane.add(backgrndLabel, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(forgroundPanel, JLayeredPane.PALETTE_LAYER);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(new JScrollPane(new JTextArea("Output", 10, 40)));
add(layeredPane);
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("LayeredPaneFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LayeredPaneFun());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}