My question here is how can I display an image into a JPanel? Other topics here asking something similar aren't clear to my about how can I do that.
I have a directory in my project folder that have image files Project Folder/GUI/img, specifically gray.png and green.png which I want to display in a JPanel.
I tried with the following code using ImageIcon and JLabel that I found in other post:
ImageIcon image = new ImageIcon("GUI/img/gray.png");
JLabel label = new JLabel(image);
//JPanel panel is already initialized by the IDE
panel.add(label)
But doesn't work... The JPanel remain empty without displaying any image. How can I do that?
Additional to this, I want that the image inside the JPanel change (gray.png for green.png) when some action is performed, for example pressing a button. I can archive that by the same method for display the image in the JPanel right?
Thanks in advance!
EDIT: Here's an example of a test code for get this. The initialization is done automatically by the IDE.
import java.awt.Image;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class Sample extends javax.swing.JFrame {
public Sample() {
initComponents();
}
//Initialization
private void initComponents() {
PanelImage = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowOpened(java.awt.event.WindowEvent evt) {
formWindowOpened(evt);
}
});
javax.swing.GroupLayout PanelImageLayout = new javax.swing.GroupLayout(PanelImage);
PanelImage.setLayout(PanelImageLayout);
PanelImageLayout.setHorizontalGroup(
PanelImageLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 100, Short.MAX_VALUE)
);
PanelImageLayout.setVerticalGroup(
PanelImageLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 100, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(61, 61, 61)
.addComponent(PanelImage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(239, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(45, 45, 45)
.addComponent(PanelImage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(155, Short.MAX_VALUE))
);
pack();
}
private void formWindowOpened(java.awt.event.WindowEvent evt) {
try {
DisplayImage(PanelImage, "/GUI/img/gray.png");
} catch (Exception ex) {
Logger.getLogger(Sample.class.getName()).log(Level.SEVERE, null, ex);
}
}
//For display the url image in a JPanel
private void DisplayImage(JPanel jp, String url) throws IOException, Exception {
try {
Image image=ImageIO.read(this.getClass().getResource(url));
ImageIcon imageicon=new ImageIcon(image);
JLabel label=new JLabel(imageicon);
jp.add(label);
} catch (IOException ex) {
throw new IOException();
} catch (Exception ex) {
throw new Exception();
}
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Sample.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Sample().setVisible(true);
}
});
}
// Variables declaration
private javax.swing.JPanel PanelImage;
}
The private void DisplayImage(JPanel jp, String url) is what I need to work for display the image, from the url String url in the JPanel jp
Looking for pieces of code in Google I ended up with a solution... And was applying the same pattern that previous comments refer.
The code that gave me the solution was:
label.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/gray.png")))
With that, I made then the method that I wanted to implement:
private static void DisplayImage(JPanel jp, String url) {
JLabel jl=new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(url)));
jp.add(jl);
}
Maybe this is not the perfect and most-correct solution, but works perfect to my, that is what I want.
Thanks all for the answers and suggestions!
I had a similar issue when I was working on creating Minesweeper. I ended up finding a solution and getting it to work by first loading an Image and then creating an ImageIcon from that Image.
Image myImage = ImageIO.read(getClass().getResource("image_path.jpg"));
myImage = myImage.getScaledInstance(30, 30, java.awt.Image.SCALE_SMOOTH);
ImageIcon myImageIcon = new ImageIcon(myImage);
you have to use ImageIcon(this.getClass().getResource("/Gui/img/gray.png"));
here is example its working.
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ExImage extends JPanel
{
public ExImage()
{
ImageIcon imageIcon = new ImageIcon(this.getClass().getResource("/gray.png"));
JLabel label = new JLabel(imageIcon);
add(label);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new ExImage());
frame.setVisible(true);
frame.setPreferredSize(new Dimension(200, 300));
}
}
Related
I'm trying to create a kind of zoom whit the mouse wheel. Everytime i move the wheel, teoricaly both the jlable and the image change sizes according(im showing the width value).
Verifiable Example:
Whitout setIcon: Whit setIcon:
Img:144 Img:144
jLable:144 jLable:144
Img:160 Img:144
jLable:160 jLable:144
Img:176 Img:160
jLable:176 jLable:160
Img:192 Img:144
jLable:192 jLable:144
The problem happens when i try insert the image into the jframe:
jLabel1.setIcon(resizedImage);
Can anyone explain me this behavior? It seems for some reason setIcon uses the previous layout, instead of the correct one.
Minimal Version of code:
public void mouseWheelMoved(MouseWheelEvent e) {
int delta = 16 * (int)e.getPreciseWheelRotation();
Dimension factor = new Dimension(jLabel1.getWidth()+delta, jLabel1.getHeight()+delta);
jLabel1.setSize(factor);//force jlabel1 to get the new size
//Relocate Image
Image img = image.ScaleImage(factor);//Teoricaly give the image whit the new size
ImageIcon resizedImage = new ImageIcon(img);
//Gives the image to jlabel
jLabel1.setIcon(resizedImage);
}
});
Complete Version of Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import pokemon.classes.BitmapController;
import pokemon.objects.ResizableImage;
import javax.swing.border.Border;
public class Aplicacao extends javax.swing.JFrame {
public Aplicacao() {
initComponents();
setExtendedState(JFrame.MAXIMIZED_BOTH);
///
BitmapController file = new BitmapController();
ResizableImage image = new ResizableImage(file.readImage());//reads the bmp image
ImageIcon icon = new ImageIcon(image.master);
jLabel1.setIcon(icon);
//Create the Controller for scroll effect
scrollController(image);
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Aplicacao().setVisible(true);
}
});
}
public void scrollController(ResizableImage image){
Border border = BorderFactory.createLineBorder(Color.BLUE, 5);
jLabel1.setBorder(border);
jLabel1.addMouseWheelListener(new MouseAdapter() {
public void mouseWheelMoved(MouseWheelEvent e) {
int delta = 16 * (int)e.getPreciseWheelRotation();
Dimension factor = new Dimension(jLabel1.getWidth()+delta, jLabel1.getHeight()+delta);
//jLabel1.setSize(factor);
//Relocate Image
//System.out.println("width: " + image.ScaleImage(factor).getWidth(rootPane));
Image img = image.ScaleImage(factor);
System.out.println("Img:"+img.getWidth(rootPane));
System.out.println("jLable:"+jLabel1.getWidth());
ImageIcon resizedImage = new ImageIcon(img);
jLabel1.setIcon(resizedImage);
}
});
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(68, 68, 68)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(472, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(74, 74, 74)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 256, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(143, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
}
////Class ResizableImage
import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.BufferedImage;
public class ResizableImage {
public BufferedImage master;
private Image scaled;
public ResizableImage(BufferedImage master){
this.master=master;
}
public Image ScaleImage(Dimension size){
Image scaledImg = master.getScaledInstance(size.width, size.height,Image.SCALE_DEFAULT);
return scaledImg;
}
}
//Class BitmapController
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class BitmapController {
public BufferedImage readImage(){
BufferedImage image = null;
try{
image = ImageIO.read(new File("D:/Tileset42.bmp"));
//System.out.println("ola");
}catch (Exception ex){ System.out.println("error");}
return image;
}
}
I am writing an application which uses a JScrollPane. In this JScrollPane I want to automatically display search results, This means, that I have to dynamically add and remove the results within the JScrollPane. The results are realised as JTextArea, which are embeded within a GridBagLayout.
When there is a high number of search results, the JScrollPane automatically scrolls to the bottom (It should be at the top). I have solved it with a solution I found here. The problem hereby is, that you can see, how it scrolls back to the top. Is it possible to remove this behaviour?
The following things I found out:
I have to remove the previous search results to display the new ones. If I don't remove the previous ones, it displays correctly.
It neither solves the prblem wgeb I update the JScrollPane every tune after adding arow nor when updating only after adding all rows.
The best would be to just disable autoscroll. I have created an executable example to demonstrate this behavior. When clicking the button "Add Row", 500 rows are added. When clicking it several times, it becomes very clear.
Thank you very much for your help!
import java.awt.GridBagConstraints;
import javax.swing.JTextArea;
public class ScrollPaneTest extends javax.swing.JFrame {
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
/**
* Creates new form ScrollPaneTest
*/
public ScrollPaneTest() {
initComponents();
}
/**
* Adds a new row.
* #param index The index of the new row.
*/
private void addRow(int index) {
JTextArea row = new JTextArea("Area " + index);
row.setEditable(false);
row.setBorder(null);
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = index;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 0, 2, 0);
jPanel2.add(row, gridBagConstraints);
}
/**
* Initializes the components.
*/
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane1.setPreferredSize(new java.awt.Dimension(400, 400));
jScrollPane1.setViewportView(jPanel1);
jPanel1.setLayout(new java.awt.BorderLayout());
jPanel2.setLayout(new java.awt.GridBagLayout());
jPanel1.add(jPanel2, java.awt.BorderLayout.NORTH);
jScrollPane1.setViewportView(jPanel1);
jButton1.setText("Create Rows");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(148, 148, 148)
.addComponent(jButton1)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 245, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jButton1)
.addGap(0, 21, Short.MAX_VALUE))
);
pack();
}
/**
* Creates 500 new rows.
* #param evt
*/
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
jPanel2.removeAll();
for(int i = 0; i < 1000; i++) {
addRow(i);
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jScrollPane1.getVerticalScrollBar().setValue(0);
}
});
jPanel2.validate();
jPanel2.repaint();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollPaneTest().setVisible(true);
}
});
}
}
UPDATE 1
I removed the lambda expressions. Hopefully it should be now compileable also with < Java 8.
UPDATE 2
The problem with the disturbing scrolling behavior has been solved by replacing
jPanel2.validate();
jPanel2.repaint();
with
jScrollPane1.validate();
jScrollPane1.repaint();
Nevertheless, both answers to this question can be very helpful in some other cases and should be given attention.
One way to achieve this is to have a custom JViewPort for your scrollpane. This custom viewport overrides setViewPosition and uses a flag to prevent the scroll, or not.
Here is an example of such code, before changing the content of the textarea, we "lock" the viewport to prevent scrolling, and we unlock it later:
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestNoScrolling {
private int lineCount = 0;
private LockableViewPort viewport;
private JTextArea ta;
private final class LockableViewPort extends JViewport {
private boolean locked = false;
#Override
public void setViewPosition(Point p) {
if (locked) {
return;
}
super.setViewPosition(p);
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
}
protected void initUI() {
JFrame frame = new JFrame("test");
ta = new JTextArea(5, 30);
JScrollPane scrollpane = new JScrollPane();
viewport = new LockableViewPort();
viewport.setView(ta);
scrollpane.setViewport(viewport);
frame.add(scrollpane);
frame.pack();
frame.setVisible(true);
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
viewport.setLocked(true);
ta.append("Some new line " + lineCount++ + "\n");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
viewport.setLocked(false);
}
});
}
});
t.setRepeats(true);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestNoScrolling().initUI();
}
});
}
}
You could simply set the Caret position to the start position (0), for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ScrollNoMore {
public static void main(String[] args) {
new ScrollNoMore ();
}
public ScrollNoMore () {
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 {
private JTextArea ta;
private JScrollPane sp;
private Random rnd = new Random();
private boolean initalised = false;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(20, 40);
sp = new JScrollPane(ta);
add(sp);
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long value = rnd.nextLong();
ta.append(String.valueOf(value) + "\n");
if (!initalised) {
ta.setCaretPosition(0);
initalised = true;
}
}
});
timer.start();
}
}
}
This will only set it the first time the Timer runs, this means that if you move the Caret or scroll position for some reason, it won't "flick" back. You could set up a series of states where by if the user moved the current view, it didn't effect the scrolling, but could be reset as required.
Sometimes the setBounds() works but only in the actionlistener.
my code:
-does not work
public panel() {
initComponents();
setBounds(100,100,105,105);
setMaximumSize(new Dimension(100,100));
}
-does work
private void btnBestellingItemToevActionPerformed(java.awt.event.ActionEvent evt) {
setBounds(100,100,105,105);
setMaximumSize(new Dimension(100,100));
}
-layout manager:
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnBestellingItemToev, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(txtWat, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtTafelNr, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)))
.addGap(0, 131, Short.MAX_VALUE))
);
Can anyone help me so it works in the constructor also?
As I said, the problem you're having is the fact that the container the component you are trying to move/size has a layout manager on it.
The layout manager is responsible for determining the position and size of all the components within in it.
You have two choices. Write your own layout manager that does what you want it to do. This is reasonably complex process, but is generally a better choice or do without a layout manager.
Personally, when doing things like this, I paint the result directly to the panel, but that's me...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BouncyBall {
public static void main(String[] args) {
new BouncyBall();
}
public BouncyBall() {
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 BallCourt());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BallCourt extends JPanel {
private JLabel beachBall;
private int delta = 4;
public BallCourt() {
setLayout(null);
beachBall = new JLabel();
try {
beachBall.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("/BeachBallOfDoom.png"))));
} catch (IOException ex) {
ex.printStackTrace();
}
beachBall.setBounds(0, 100 - 16, 32, 32);
add(beachBall);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int x = beachBall.getX() + delta;
if (x + beachBall.getWidth() > getWidth()) {
delta *= -1;
x = (getWidth() - beachBall.getWidth()) + delta;
} else if (x < 0) {
delta *= -1;
x = delta;
}
beachBall.setLocation(x, beachBall.getY());
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
How to make a text field visible on itemStatechanged event of a check box in Swing?
I am trying to create a frame with a check box and a text field. I want the text field to be displayed only when the check box is selected. So when I initialize the components, I have set the textfield.setvisible to false and for the check box added a addItemListener and call the itemStateChanged event and there is the check box is selected, I set the setVisible method to true.
My SSCCE looks like:
package ui;
public class Evaluator extends javax.swing.JFrame {
public Evaluator() {
initComponents();
}
private void initComponents() {
jCheckBox1 = new javax.swing.JCheckBox();
jTextField1 = new javax.swing.JTextField();
jTextField1.setVisible(false);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new java.awt.Dimension(800, 800));
jCheckBox1.setFont(new java.awt.Font("Tahoma", 0, 14));
jCheckBox1.setText("Properties");
jCheckBox1.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jCheckBox1ItemStateChanged(evt);
}
});
jTextField1.setFont(new java.awt.Font("Tahoma", 0, 14));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jCheckBox1)
.addGap(41, 41, 41)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(155, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(229, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jCheckBox1)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(34, 34, 34))
);
pack();
}
private void jCheckBox1ItemStateChanged(java.awt.event.ItemEvent evt) {
// TODO add your handling code here:
if(evt.getStateChange()== java.awt.event.ItemEvent.SELECTED){
jTextField1.setVisible(true);
}
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Evaluator().setVisible(true);
}
});
}
private javax.swing.JCheckBox jCheckBox1;
private javax.swing.JTextField jTextField1;
}
Basically, you need to invalidate the frame (or parent container) to force it be re-layout
private void jCheckBox2ItemStateChanged(java.awt.event.ItemEvent evt) {
jTextField1.setVisible(jCheckBox2.isSelected());
invalidate();
validate();
}
Updated
I'd also suggest that you avoid adding your entire UI onto a top level container, instead use a JPanel as you base component and build you UI's around them. When you're ready, simply add the base panel to what ever top level container you need.
For many components in one space, use a CardLayout as see in this short example.
Here is a more specific example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
public static void main(String[] args) {
Runnable r = new Runnable () {
public void run() {
final JCheckBox show = new JCheckBox("Have Text", false);
JPanel ui = new JPanel(new
FlowLayout(FlowLayout.CENTER, 5, 5));
ui.add( show );
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
ui.add(cards);
cards.add(new JPanel(), "notext");
cards.add(new JTextField(8), "text");
ItemListener al = new ItemListener(){
public void itemStateChanged(ItemEvent ie) {
if (show.isSelected()) {
cl.show(cards, "text");
} else {
cl.show(cards, "notext");
}
}
};
show.addItemListener(al);
JOptionPane.showMessageDialog(null, ui);
}
};
SwingUtilities.invokeLater(r);
}
}
great lesson, how the LayoutManager works, only GridLayout can do that without any issue, but this is its property
last JComponent in the row or column (part of then is about) can't be invisible, then container is shrinked
easiest work_around is to display container, then to call setVisible(false) wrapped into invokeLater
... ....
import java.awt.event.ItemEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Evaluator {
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private JCheckBox checkBox = new JCheckBox();
private JTextField textField = new JTextField(10);
public Evaluator() {
checkBox.setText("Properties");
checkBox.addItemListener(new java.awt.event.ItemListener() {
#Override
public void itemStateChanged(java.awt.event.ItemEvent evt) {
if (evt.getStateChange() == ItemEvent.SELECTED) {
textField.setVisible(true);
} else {
textField.setVisible(false);
}
}
});
//panel.setLayout(new GridLayout());
//panel.setLayout(new SpringLayout());
//panel.setLayout(new BorderLayout());
//panel.setLayout(new GridBagLayout());
//panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(checkBox/*, BorderLayout.NORTH*/);
panel.add(textField/*, BorderLayout.SOUTH*/);
//panel.doLayout();
//textField.setVisible(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
textField.setVisible(false);
}
});
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Evaluator evaluator = new Evaluator();
}
});
}
}
EDIT: Using the solutions presented below, I have changed the code to have a JPanel inside a JScrollPane. Using a JButton i add JCheckBoxes to the JPanel inside the JScrollPane. This was one problem solved, as the a JScrollPanecan only take one JComponent. The rest of the issues were solved setting a gridlayout to the JPanel inside JScrollPane. I have kept my original question here for the sake of posterity:
ORIGINAL QUESTION: I'm trying to dynamically create JCheckBox and add them to a JScrollPane, but alas i am achieving little success. I have reduced this to a single proof-of-concept implementation.
I have a JScrollPaneon a JPanel inside a JFrame. Also on the JPanel, i have added a button that is supposed to add a JCheckBox to the JScrollPane when clicked. Should be simple enough. The code inside the button is as follows:
private void addCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {
JCheckBox cb = new JCheckBox("New CheckBox");
jScrollPaneCheckBoxes.add(cb);
jScrollPaneCheckBoxes.revalidate();
}
The code runs seemingly without error. I have no exceptions and using the debugger shows that the JCheckBox is in fact added to the JScrollPane . Unfortunately, nothing is displayed in the application. I need direction as to where to look for the problem.
Here is a quick piece of code that you can just run. Unfortunately i threw this together using Netbeans and it's GUI designer and as such it's a bit longer than it needs to be, especially the generated code. Focus on the method jButton1ActionPerformed, that's where the above code is taken from.
EDIT: This code now does what i need it to. :-)
package dynamiccheckboxsscce;
import javax.swing.JCheckBox;
public class Main extends javax.swing.JFrame {
/**
* Creates new form Main
*/
public Main() {
initComponents();
}
#SuppressWarnings("unchecked")
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane1.setPreferredSize(new java.awt.Dimension(250, 250));
jPanel1.setPreferredSize(new java.awt.Dimension(300, 250));
jPanel1.setLayout(new java.awt.GridLayout(0, 2, 10, 10));
jScrollPane1.setViewportView(jPanel1);
jButton1.setText("Add Checkbox");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 309, Short.MAX_VALUE)
.addContainerGap())
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(jButton1)
.addGap(112, 112, 112)))));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE)
.addComponent(jButton1)
.addContainerGap()));
pack();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
JCheckBox cb = new JCheckBox("New CheckBox");
jPanel1.add(cb);
jPanel1.revalidate();
jPanel1.repaint();
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/*
* Set the Nimbus look and feel
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
}
Thanks in advance.
without posting a SSCCE you have to accepting that JScrollPane is designated to nest only one JComponent,
if you want to add more that one JComponent to the JScrollPane, the put there JPanel and then add a new JComponent to the JPanel instead of JScrollPane
to check how dynamically add / remove JComponents
EDIT
you have to set proper LayoutManager to the JPanel
you ahve to add JPanel to the JScrollPane
for example (without using built_in designer, even safe time for ..., required best knowledge about used SwingFramework and Swing too, I'm satisfied with plain Swing)
code
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class AddJCheckBoxToJScrollPane {
private static final long serialVersionUID = 1L;
private JFrame frame = new JFrame();
private JButton jButton1;
private JPanel jPanel1;
private JScrollPane jScrollPane1;
public AddJCheckBoxToJScrollPane() {
jPanel1 = new JPanel();
jPanel1.setLayout(new GridLayout(0, 2, 10, 10));
jScrollPane1 = new JScrollPane(jPanel1);
jButton1 = new JButton("Add Checkbox");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
JCheckBox cb = new JCheckBox("New CheckBox");
jPanel1.add(cb);
jPanel1.revalidate();
jPanel1.repaint();
}
});
frame.add(jScrollPane1);
frame.add(jButton1, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
//frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new AddJCheckBoxToJScrollPane();
}
});
}
}
You should be calling repaint() instead of revalidate().
See Revalidate vs. Repaint