Java JPanel中的图形有问题,但它在一个框架中工作

Java JPanel中的图形有问题,但它在一个框架中工作,java,swing,jpanel,tic-tac-toe,Java,Swing,Jpanel,Tic Tac Toe,我是新手,正在使用Cay Hortsmann的《大Java》一书来学习。对于早期的一个项目,我正在用GUI制作一个tic-tac-toe游戏,但是我很难让板显示在JPanel上。它只在框架中显示得很好,但是因为我想添加按钮,所以我尝试将板放在JPanel中,然后将JPanel添加到框架中。不幸的是,这不起作用。如果您能提供以下反馈,我将不胜感激: import javax.swing.JFrame; import javax.swing.JPanel; public class TicTa

我是新手,正在使用Cay Hortsmann的《大Java》一书来学习。对于早期的一个项目,我正在用GUI制作一个tic-tac-toe游戏,但是我很难让板显示在JPanel上。它只在框架中显示得很好,但是因为我想添加按钮,所以我尝试将板放在JPanel中,然后将JPanel添加到框架中。不幸的是,这不起作用。如果您能提供以下反馈,我将不胜感激:

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);
    }
}

面板的默认布局管理器是从左到右排列元素的
FlowLayout
。由于您希望网格显示在主视图中,因此可以考虑使用不同的布局管理器,如<代码>边界布局< /代码>。如果使用
边框布局
,则可以将栅格放置到中心区域,以便栅格填充主视图:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;

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) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JFrame frame = new JFrame();

                // create board
                final LinesComponent boardLines = new LinesComponent();
                JPanel panel = new JPanel();
                panel.setLayout(new BorderLayout(0, 0));
                panel.add(boardLines, BorderLayout.CENTER);
                frame.getContentPane().add(panel);
                frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}
要在使用
BorderLayout
时向窗口添加按钮,可以将按钮添加到另一个
JPanel
,并将该面板添加到其他区域之一的
BorderLayout
(即:
BorderLayout.NORTH
BorderLayout.SOUTH
)中

另外,请注意,在上面更正的代码中,Swing GUI代码位于。您不应该在EDT之外运行任何Swing代码,因为大多数Swing对象方法都不是线程安全的


有关布局管理器的详细信息,请阅读。

面板的默认布局管理器是一个从左到右排列元素的
FlowLayout
。由于您希望网格显示在主视图中,因此可以考虑使用不同的布局管理器,如<代码>边界布局< /代码>。如果使用
边框布局
,则可以将栅格放置到中心区域,以便栅格填充主视图:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;

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) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JFrame frame = new JFrame();

                // create board
                final LinesComponent boardLines = new LinesComponent();
                JPanel panel = new JPanel();
                panel.setLayout(new BorderLayout(0, 0));
                panel.add(boardLines, BorderLayout.CENTER);
                frame.getContentPane().add(panel);
                frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}
要在使用
BorderLayout
时向窗口添加按钮,可以将按钮添加到另一个
JPanel
,并将该面板添加到其他区域之一的
BorderLayout
(即:
BorderLayout.NORTH
BorderLayout.SOUTH
)中

另外,请注意,在上面更正的代码中,Swing GUI代码位于。您不应该在EDT之外运行任何Swing代码,因为大多数Swing对象方法都不是线程安全的


有关布局管理器的更多信息,请阅读。

让我们从明显的

  • JPanel
    使用
    FlowLayout
    ,该布局尊重添加到其中的组件的
    首选大小
    JComponent
    的默认大小为
    0x0
    ,这意味着当您向其添加
    线路板时,它将被有效地设置为不可见且从不绘制。您可以通过使用
    面板上的
    边框布局
    来创建此对话框,例如
    JPanel面板=新的JPanel(new BorderLayout())
  • 虽然技术上不需要,但在执行自定义绘制时调用
    super.paintComponent
    始终是一个好的实践
  • 您不应该在
    paintComponent
    中创建短期对象,尤其是在状态没有任何变化的情况下(即,创建新实例的结果与创建的上一个实例的结果相同)
    paintComponent
    可以在短时间内重复调用,这可能会对系统造成不必要的压力
  • 不需要从
    JComponent
    扩展,说真的,它什么都没做
  • 使用
    pack
    而不是
    JFrame
    上的
    setSize
    ,这将使生活更加轻松
  • Swing UI应该在事件调度线程的上下文中创建和操作
例如:

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);
        }
    }
}

您应该考虑查看更多详细信息

让我们从显而易见的

  • JPanel
    使用
    FlowLayout
    ,该布局尊重添加到其中的组件的
    首选大小
    JComponent
    的默认大小为
    0x0
    ,这意味着当您向其添加
    线路板时,它将被有效地设置为不可见且从不绘制。您可以通过使用
    面板上的
    边框布局
    来创建此对话框,例如
    JPanel面板=新的JPanel(new BorderLayout())
  • 虽然技术上不需要,但在执行自定义绘制时调用
    super.paintComponent
    始终是一个好的实践
  • 您不应该在
    paintComponent
    中创建短期对象,尤其是在状态没有任何变化的情况下(即,创建新实例的结果与创建的上一个实例的结果相同)
    paintComponent
    可以在短时间内重复调用,这可能会对系统造成不必要的压力
  • 不需要从
    JComponent
    扩展,说真的,它什么都没做
  • 使用
    pack
    而不是
    JFrame
    上的
    setSize
    ,这将使生活更加轻松
  • Swing UI应该在事件调度线程的上下文中创建和操作
例如:

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);
        }
    }
}
你应该考虑看看更多细节