【问题标题】:Trouble with graphics in a Java JPanel, but it works in a frameJava JPanel 中的图形有问题,但它在框架中工作
【发布时间】:2014-07-03 05:45:16
【问题描述】:

我是新手,正在使用 Cay Hortsmann 的 Big Java 一书进行学习。对于早期项目之一,我正在制作一个带有 GUI 的井字游戏,但我无法让棋盘出现在 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);
    }
}

【问题讨论】:

    标签: java swing jpanel tic-tac-toe


    【解决方案1】:

    让我们从显而易见的开始......

    • JPanel 使用 FlowLayout,它尊重添加到其中的组件的 preferredSizeJComponent 的默认大小为0x0,这意味着当您向其添加boardLines 时,它实际上是不可见的并且永远不会被绘制。您可以通过在panel 上使用BorderLayout 来创建它,例如JPanel panel = new JPanel(new BorderLayout());
    • 虽然技术上不需要,但在执行自定义绘画时致电 super.paintComponent 总是很好的做法
    • 您不应该在paintComponent 中创建短期对象,尤其是当状态没有以任何方式改变时(即,创建新实例的结果与您创建的前一个实例的结果相同) )。 paintComponent 可以在短时间内重复调用,这可能会对您的系统造成不必要的压力
    • Lines 不需要从 JComponent 扩展,说真的,它只是没有做任何事情......
    • JFrame 上使用pack 而不是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);
            }
        }
    }
    

    您应该考虑查看Performing Custom Painting 了解更多详情

    【讨论】:

      【解决方案2】:

      面板的默认布局管理器是FlowLayout,它从左到右排列元素。由于您希望网格出现在主视图中,您可以考虑使用不同的布局管理器,例如 BorderLayout。如果您使用BorderLayout,您可以将网格放置在中心区域,以便网格填满主视图:

      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、@987654331 @ 等)。

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

      有关布局管理器的更多信息,请阅读A Visual Guide to Layout Managers

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-27
        • 2015-11-08
        • 1970-01-01
        • 2013-12-31
        • 1970-01-01
        相关资源
        最近更新 更多