I'm new to this and am using the book Big Java by Cay Hortsmann to learn. For one of the early projects, I'm making a tic-tac-toe game with a GUI, but I'm having trouble getting the board to show up on a JPanel. It shows up fine just in the frame, but since I want to add buttons, I try to put the board in a JPanel and then add the JPanel to the frame. Unfortunately, this isn't working. I'd appreciate any feedback you can give:
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TicTacToePlayer {
private static final int FRAME_WIDTH = 400;
private static final int FRAME_HEIGHT = 400;
private int count = 0;
public static void main(String[] args) {
final JFrame frame = new JFrame();
// create board
final LinesComponent boardLines = new LinesComponent();
JPanel panel = new JPanel();
panel.add(boardLines);
frame.add(panel);
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class LinesComponent extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Lines boardLines = new Lines();
boardLines.draw(g2);
}
}
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
public class Lines extends JComponent {
public Lines() {
setPreferredSize(new Dimension(400, 400));
}
public void draw(Graphics2D g2) {
Line2D.Double leftVertLine = new Line2D.Double(150, 50, 150, 350);
Line2D.Double rightVertLine = new Line2D.Double(250, 50, 250, 350);
Line2D.Double topHorizLine = new Line2D.Double(50, 150, 350, 150);
Line2D.Double bottomHorizLine = new Line2D.Double(50, 250, 350, 250);
g2.draw(leftVertLine);
g2.draw(rightVertLine);
g2.draw(topHorizLine);
g2.draw(bottomHorizLine);
}
}
Lets start with the obvious...
JPanel
uses a FlowLayout
which honours the preferredSize
of the components that are added to it. JComponent
has a default size of 0x0
, meaning that when you add boardLines
to it, it is effectivly made invisible and never painted. You can create this by using a BorderLayout
on panel
, for example JPanel panel = new JPanel(new BorderLayout());
super.paintComponent
when performing custom paintingpaintComponent
, especially when there state doesn't change in any way (that is, the result of creating a new instance is the same as it was for the previous instance you created). paintComponent
can be called repeatedly and in short order, this could an unnecessary strain on your systemLines
doesn't need to extend from JComponent
, seriously, it's just not doing anything...pack
instead of setSize
on JFrame
, it will make life a lot easier...As an example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TicTacToePlayer {
private static final int FRAME_WIDTH = 400;
private static final int FRAME_HEIGHT = 400;
private int count = 0;
public static void main(String[] args) {
new TicTacToePlayer();
}
public TicTacToePlayer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create board
final LinesComponent boardLines = new LinesComponent();
JPanel panel = new JPanel(new BorderLayout());
panel.add(boardLines);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class LinesComponent extends JComponent {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void draw(Graphics2D g2) {
Line2D.Double leftVertLine = new Line2D.Double(150, 50, 150, 350);
Line2D.Double rightVertLine = new Line2D.Double(250, 50, 250, 350);
Line2D.Double topHorizLine = new Line2D.Double(50, 150, 350, 150);
Line2D.Double bottomHorizLine = new Line2D.Double(50, 250, 350, 250);
g2.draw(leftVertLine);
g2.draw(rightVertLine);
g2.draw(topHorizLine);
g2.draw(bottomHorizLine);
}
}
}
You should considering having a look at Performing Custom Painting for more details