JLabel does not display image

I am creating a Tic-Tac-Toe game using Java. Right now I have this, when you click on the button that the JButton will be removed from JPanel , a JLabel containing either an X or O image will be added, and the JPanel will be repainted. However, when I click the button, the image does not appear, but the button disappears.

Button Creation and JLabel / Image :

 package tictactoe; import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.ImageIcon; public class TicTacToe implements ActionListener { private JFrame holder = new JFrame(); private GridLayout layout = new GridLayout(3,3); private FlowLayout panel = new FlowLayout(FlowLayout.CENTER); private JPanel p11, p12, p13, p21, p22, p23, p31, p32, p33; private JButton b1, b2, b3, b4, b5, b6, b7, b8, b9; private ImageIcon iconX = new ImageIcon("iconX.png"); private JLabel xLabel = new JLabel(iconX); private ImageIcon iconO = new ImageIcon("iconO.png"); private JLabel oLabel = new JLabel(iconO); private int turn; private char s1, s2, s3, s4, s5, s6, s7, s8, s9; public TicTacToe() { paint(); } private void paint() { holder.setLayout(layout); holder.setSize(300,300); b1 = new JButton("1"); p11 = new JPanel(); p11.setLayout(panel); p11.add(b1); holder.add(p11); //Same block of code for the next 8 buttons/panels inserted here holder.setVisible(true); b1.addActionListener(this); //Other action listeners inserted here } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == b1) { ++turn; p11.remove(b1); if (turn % 2 == 1) { s1 = 'x'; p11.add(xLabel); } else if (turn % 2 == 0) { s1 = 'o'; p11.add(oLabel); } p11.repaint(); } //Other action events inserted here } public static void main(String[] args) { TicTacToe game = new TicTacToe(); } } 

Picture of the problem

+4
source share
2 answers

Try calling revalidate(); , then repaint(); in your JPanel instance as follows:

  p11.revalidate(); p11.repaint(); 

When a Component added or removed, you need to call revalidate() , this call is an instruction to LayoutManager to reset based on the new Component list. revalidate() will call repaint() on what the component considers "dirty regions". Obviously, not all areas of your JPanel are considered dirty by the RepaintManager .

repaint() used to tell the component to repaint itself. It often happens that you need to call this to clear conditions like yours.

+3
source
 @Override public void actionPerformed(final ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (e.getSource() == b1) { ++turn; p11.remove(b1); if (turn % 2 == 1) { s1 = 'x'; p11.add(new JLabel(iconX)); } else { s1 = 'o'; p11.add(new JLabel(iconO)); } //p11.revalidate(); //p11.repaint(); } **Other action events inserted here } }); } 

The invokeLater construct is a bit of syntax, but allows you to process the flow of event processing at the click of a button and then make changes. Otherwise, you cannot rely on immediate redrawing, and gui becomes less responsive. (A Runnable can only access external final variables, namely: variables that are no longer assigned.)

Components like JLabel have one field for their parent component. Therefore, you cannot reuse a single component. Therefore, new JLabel() .

About repainting; always try first without starting it yourself.

+1
source

All Articles