【问题标题】:How do I make my custom Swing component visible?如何使我的自定义 Swing 组件可见?
【发布时间】:2011-01-12 21:30:18
【问题描述】:

我不知道为什么它不会显示。首先,我创建组件的一个实例,然后将其添加到二维 JPanel 数组中的某个元素。然后我遍历该数组并将每个 JPanel 添加到另一个 JPanel 容器中,该容器将容纳所有 JPanel。

然后我将最后一个容器添加到我的 JFrame 窗口并将可见性设置为 true,它应该是可见的吗?

public class View extends JFrame {

    Board      gameBoard;
    JFrame     gameWindow   = new JFrame("Chess");
    JPanel     gamePanel    = new JPanel();
    JPanel[][] squarePanel  = new JPanel[8][8];
    JMenuBar   gameMenu     = new JMenuBar();
    JButton    restartGame  = new JButton("Restart");
    JButton    pauseGame    = new JButton("Pause");
    JButton    log          = new JButton("Log");

    View(Board board){
        gameWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
        gameWindow.setSize(400, 420);
        gameWindow.getContentPane().add(gamePanel, BorderLayout.CENTER);
        gameWindow.getContentPane().add(gameMenu, BorderLayout.NORTH);
        gameMenu.add(restartGame);
        gameMenu.add(pauseGame);
        gameMenu.add(log);
        gameBoard = board;
        drawBoard(gameBoard);
        gameWindow.setResizable(false);
        gameWindow.setVisible(true);

    }

    public void drawBoard(Board board){
        for(int row = 0; row < 8; row++){
            for(int col = 0; col < 8; col++){
                Box box = new Box(board.getSquare(col, row).getColour(), col, row);
                squarePanel[col][row] = new JPanel();
                squarePanel[col][row].add(box);
            }
        }
        for(JPanel[] col : squarePanel){
            for(JPanel square : col){
                gamePanel.add(square);
            }
        }
    }
}

@SuppressWarnings("serial")
class Box extends JComponent{
    Color boxColour;
    int col, row;
    public Box(Color boxColour, int col, int row){
        this.boxColour = boxColour;
        this.col = col;
        this.row = row;
        repaint();
    }
    protected void paintComponent(Graphics drawBox){
        drawBox.setColor(boxColour);
        drawBox.drawRect(50*col, 50*row, 50, 50);
        drawBox.fillRect(50*col, 50*row, 50, 50);
    }
}

还有最后一个问题。注意每个 Box 组件是如何有一个位置的,当我将组件添加到 JPanel 并将 JPanel 添加到我的 JFrame 时,位置会发生什么变化? 它相对于其他 Box 组件的位置是否仍然相同?

【问题讨论】:

  • 你的main在哪里?据我所知,View 的构造函数从未被调用过。此外,View 类是 JFrame,它永远不会可见。
  • 对了,忘记说了。构造函数在另一个类 Game 中调用,其中“board”作为参数传递。 Board 拥有一个 Square[][] 和 getSquare 方法获取索引 col, row 处的正方形。 getColour 方法从正方形中获取 squareColour 属性。板子通过遍历数组在构造函数中设置 squareColour。
  • gameWindow 是否可见?另外,奇怪的是我的菜单是可见的,按钮也是可见的。只是盒子不是。

标签: java swing


【解决方案1】:

我尝试扩展 JPanel,但在我的菜单下有一个 10x10 像素的灰色小框。至少一个开始

当您使用 JComponent 时,首选大小是 (0, 0),这就是您什么都看不到的原因。

当您使用 JPanel 时,默认情况下使用 FlowLayout,并且 FlowLayout 在添加到面板的每个组件之前/之后都有 5 个像素的间隙。由于您不添加任何组件,因此首选大小只是间隙,因此您将获得 (10, 10) 的大小。

因此,当您进行自定义绘画时,您需要重写 getPreferredSize() 方法,以便为您打算实现的自定义绘画返回适当的值。

编辑:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener
{
    JLayeredPane layeredPane;
    JPanel chessBoard;
    JLabel chessPiece;
    int xAdjustment;
    int yAdjustment;

    public ChessBoard()
    {
        Dimension boardSize = new Dimension(600, 600);

        //  Use a Layered Pane for this this application

        layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize( boardSize );
        layeredPane.addMouseListener( this );
        layeredPane.addMouseMotionListener( this );
        getContentPane().add(layeredPane);

        //  Add a chess board to the Layered Pane

        chessBoard = new JPanel();
        chessBoard.setLayout( new GridLayout(8, 8) );
        chessBoard.setPreferredSize( boardSize );
        chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
        layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);

        //  Build the Chess Board squares

        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                JPanel square = new JPanel( new BorderLayout() );
                square.setBackground( (i + j) % 2 == 0 ? Color.red : Color.white );
                chessBoard.add( square );
            }
        }

        // Add a few pieces to the board

        ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here

        JLabel piece = new JLabel( duke );
        JPanel panel = (JPanel)chessBoard.getComponent( 0 );
        panel.add( piece );
        piece = new JLabel( duke );
        panel = (JPanel)chessBoard.getComponent( 15 );
        panel.add( piece );
    }

    /*
    **  Add the selected chess piece to the dragging layer so it can be moved
    */
    public void mousePressed(MouseEvent e)
    {
        chessPiece = null;
        Component c =  chessBoard.findComponentAt(e.getX(), e.getY());

        if (c instanceof JPanel) return;

        Point parentLocation = c.getParent().getLocation();
        xAdjustment = parentLocation.x - e.getX();
        yAdjustment = parentLocation.y - e.getY();
        chessPiece = (JLabel)c;
        chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);

        layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
        layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    }

    /*
    **  Move the chess piece around
    */
    public void mouseDragged(MouseEvent me)
    {
        if (chessPiece == null) return;

        //  The drag location should be within the bounds of the chess board

        int x = me.getX() + xAdjustment;
        int xMax = layeredPane.getWidth() - chessPiece.getWidth();
        x = Math.min(x, xMax);
        x = Math.max(x, 0);

        int y = me.getY() + yAdjustment;
        int yMax = layeredPane.getHeight() - chessPiece.getHeight();
        y = Math.min(y, yMax);
        y = Math.max(y, 0);

        chessPiece.setLocation(x, y);
     }

    /*
    **  Drop the chess piece back onto the chess board
    */
    public void mouseReleased(MouseEvent e)
    {
        layeredPane.setCursor(null);

        if (chessPiece == null) return;

        //  Make sure the chess piece is no longer painted on the layered pane

        chessPiece.setVisible(false);
        layeredPane.remove(chessPiece);
        chessPiece.setVisible(true);

        //  The drop location should be within the bounds of the chess board

        int xMax = layeredPane.getWidth() - chessPiece.getWidth();
        int x = Math.min(e.getX(), xMax);
        x = Math.max(x, 0);

        int yMax = layeredPane.getHeight() - chessPiece.getHeight();
        int y = Math.min(e.getY(), yMax);
        y = Math.max(y, 0);

        Component c =  chessBoard.findComponentAt(x, y);

        if (c instanceof JLabel)
        {
            Container parent = c.getParent();
            parent.remove(0);
            parent.add( chessPiece );
            parent.validate();
        }
        else
        {
            Container parent = (Container)c;
            parent.add( chessPiece );
            parent.validate();
        }
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

    public static void main(String[] args)
    {
        JFrame frame = new ChessBoard();
        frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
        frame.setResizable( false );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
     }
}

【讨论】:

  • 太好了,谢谢!现在我可以看到一些正方形,它们有一个间隙,所以我必须改变布局来摆脱它,对吧?它们看起来仍然不正确,如果我将 setOpaque 设置为 true,它们会显示出来但没有颜色并且有间隙。但是,如果我不运行 setOpaque,我会得到一个灰色框,而第二个框应该在的位置只有一条粗的水平灰线。同样在中间的下一行,有一条深灰色/黑色垂直粗线,后跟一个相同颜色的点。
  • 不应使用 Box 作为组件名称。 Swing 已经有一个同名的组件。此外,您不需要为此创建自定义组件。您只需调用 JPanel 上的 setBackground(...) 方法,它就会为您绘制背景。我包括了我的棋盘示例供您查看。由于代码不完整,我不确定您的问题是什么。
  • 感谢您,我尝试使用 GridLayout。非常实用,但是我将带有正方形的 JPanel 添加到我的 View JFrame 中,它似乎总是占据整个窗口。我使用了包()。我尝试将 View 的首选尺寸设置为大于带有板子的 JPanel 的尺寸,并且板子仍然占据整个窗口。另外,我注意到你的正方形颜色是相反的:P 大多数棋盘左上角的正方形是白色的,如果你使用 (i + j) % 2 == 0 它会变成黑色,应该是!= 0。
【解决方案2】:

过去,我通过扩展JPanel 而不是JComponent 解决了这个问题。我找到了一个很好的例子here。这是它的改编版,它将绘制一个框:

public class Box extends JPanel {
  Color color;

  public Box (Color c, int w, int h) {
    color = color;
    setSize(w, h);
  }

  @Override
  public void paintComponent(Graphics g) {
    g.setColor(color);
    g.drawOval(0, 0, getWidth(), getHeight());
 }

 ...

这与您上面的代码并不完全相同,但希望它能让您朝着正确的方向开始!

快速说明(原始回复):上面的示例View 是一个永远不会可见的JFrame。而是使用类变量gameWindow。将顶级类设为可见窗口是一种很好的做法。

【讨论】:

  • 谢谢!问题仍然存在:/。
  • 好的,我现在明白这个问题了——扩展的JComponent 没有重绘。对不起。好像我过去也遇到过类似的问题,最终扩展了JPanel...现在开始挖掘! :-)
  • 哦,至少我知道现在的问题是什么:P 我尝试扩展 JPanel,在我的菜单下得到一个 10x10 像素的灰色小框。至少一个开始! :p
  • 我不敢苟同,我警告原发帖人对 zourtney 的建议持保留态度。 JPanels 也没有 repaintComponent 方法。不过,这两个类都有 paintComponent 方法,而且这个方法对两个类都有效。只要他遵循 rob camick 的建议,他的代码应该可以使用 JComponent。
  • @Hovercraft,对,我刚刚意识到(额头一巴掌!)。我混淆了paintComponent()repaint() 方法。对不起。我试图相应地更新我的答案。
猜你喜欢
  • 2015-10-20
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2012-04-18
相关资源
最近更新 更多