2

パズル プログラムを作成して、Java、特に Java GUI の理解を深めようとしています。現在、ユーザーは指定された数の断片に切り分けられた画像を選択します。ピースは画面にランダムに描画されますが、他のピースの空白部分に覆われているように見え、すべてが表示されるわけではありませんが、すべての座標を印刷できます。LayoutManager が機能していないように見えるため、絶対配置を使用しています。私は簡単にlayeredPanesを試しましたが、混乱し、問題を解決していないようです。助けていただければ幸いです。
関連する 2 つのクラスを次に示します。

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

public class PuzzlePieceDriver extends JFrame
{
  private static Dimension SCREENSIZE = Toolkit.getDefaultToolkit().getScreenSize();
  private static final int HEIGHT = SCREENSIZE.height;
  private static final int WIDTH = SCREENSIZE.width;

  public static int MY_WIDTH;
  public static int MY_HEIGHT;

  private static BufferedImage image;


  private int xPieces = PuzzleMagicDriver.getXPieces();
  private int yPieces = PuzzleMagicDriver.getYPieces();

  private PuzzlePiece[] puzzle = new PuzzlePiece[xPieces*yPieces];

  public Container pane = this.getContentPane();
  private JLayeredPane layeredPane = new JLayeredPane();


  public PuzzlePieceDriver(ImageIcon myPuzzleImage)
  {
    MY_WIDTH = myPuzzleImage.getIconWidth()+(int)myPuzzleImage.getIconHeight()/2;
    MY_HEIGHT = myPuzzleImage.getIconHeight()+(int)myPuzzleImage.getIconHeight()/2;
    setTitle("Hot Puzz");
setSize(MY_WIDTH,MY_HEIGHT);
setLocationByPlatform(true);

pane.setLayout(null);


image = iconToImage(myPuzzleImage); //pass image into bufferedImage form

puzzle = createClip(image);

//pane.add(layeredPane);


setVisible(true);
  }//end constructor



  public static BufferedImage iconToImage(ImageIcon icon)
  {
    Image img = icon.getImage();
 int w = img.getWidth(null);
 int h = img.getHeight(null);
 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
 Graphics g = image.createGraphics();
     // Paint the image onto the buffered image
    g.drawImage(img, 0, 0, null);
    g.dispose();

    return image;
  }//end BufferedImage

  protected int randomNumber(int min, int max)
  {
    int temp = 
    min + (int)(Math.random() * ((max - min) + 1));

 return temp;
  }//end randomNumber


  private PuzzlePiece[] createClip(BufferedImage passedImage)
  {

 int cw, ch;
 int w,h;
 w = image.getWidth(null);
 h = image.getHeight(null);
 cw = w/xPieces;
     ch = h/yPieces;

 int[] cells=new int[xPieces*yPieces];

 int dx, dy;

 BufferedImage clip = passedImage;

 //layeredPane.setPreferredSize(new Dimension(w,h));

    for (int x=0; x<xPieces; x++) 
      {
        int sx = x*cw;
        for (int y=0; y<yPieces; y++) 
            {
            int sy = y*ch;
            int cell = cells[x*xPieces+y];
            dx = (cell / xPieces) * cw;
            dy = (cell % yPieces) * ch;

            clip= passedImage.getSubimage(sx, sy, cw, ch);
    int myX = randomNumber(0,(int)w);
    int myY = randomNumber(0,(int)h);

    PuzzlePiece piece=new PuzzlePiece(clip,myX,myY);
    puzzle[x*xPieces+y]=piece;
    piece.setBounds(myX,myY,w,h);
    //layeredPane.setBounds(myX,myY,w,h);
    //layeredPane.add(piece,new Integer(x*xPieces+y));
    pane.add(piece);
    piece.repaint();

        }//end nested for
}//end for
return puzzle;
  }//end createClip

}//end class

少し間隔がずれていたらごめんなさい!

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

public class PuzzlePiece extends JPanel
{
private Point imageCorner;      //the image's top-left corner location
private Point prevPt;               //mouse location for previous event
private Boolean insideImage =false;

private BufferedImage image;

public PuzzlePiece(BufferedImage clip, int x, int y)
{
 image = clip;
 imageCorner = new Point(x,y);
 //repaint();
}//end constructor

public void paintComponent(Graphics g)
{
     super.paintComponent(g);
 g.drawImage(image, (int)getImageCornerX(),(int)getImageCornerY(), this);
     System.out.println("paint "+getImageCornerX()+"   "+getImageCornerY());
    //repaint(); 
//g.dispose();
}//end paintComponent

public Point getImageCorner()
{
  return imageCorner;
}//end getImageCorner
public double getImageCornerY()
{
  return imageCorner.getY();
}//end getImageCornerY
public double getImageCornerX()
{
  return imageCorner.getX();
}//end getPoint


}//end class PuzzlePiece

どんな助けでも大歓迎です、私は本当に立ち往生しています! ありがとう!!

4

3 に答える 3

6

私はこのアイデアに非常に興味をそそられたので、カスタム レイアウト マネージャーを使用して別の例を作成しました。

public class MyPuzzelBoard extends JPanel {

    public static final int GRID_X = 4;
    public static final int GRID_Y = 4;
    private BufferedImage image;

    public MyPuzzelBoard(BufferedImage image) {
        setLayout(new VirtualLayoutManager());
        setImage(image);

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    removeAll();
                    generatePuzzel();
                } else {
                    Component comp = getComponentAt(e.getPoint());
                    if (comp != null && comp != MyPuzzelBoard.this) {
                        setComponentZOrder(comp, 0);
                        invalidate();
                        revalidate();
                        repaint();
                    }
                }
            }
        });
    }

    public void setImage(BufferedImage value) {
        if (value != image) {
            image = value;
            removeAll();
            generatePuzzel();
        }
    }

    public BufferedImage getImage() {
        return image;
    }

    protected float generateRandomNumber() {
        return (float) Math.random();
    }

    protected void generatePuzzel() {
        BufferedImage image = getImage();

        if (image != null) {
            int imageWidth = image.getWidth();
            int imageHeight = image.getHeight();

            int clipWidth = imageWidth / GRID_X;
            int clipHeight = imageHeight / GRID_Y;
            for (int x = 0; x < GRID_X; x++) {
                for (int y = 0; y < GRID_Y; y++) {

                    float xPos = generateRandomNumber();
                    float yPos = generateRandomNumber();
                    Rectangle bounds = new Rectangle((x * clipWidth), (y * clipHeight), clipWidth, clipHeight);
                    MyPiece piece = new MyPiece(image, bounds);
                    add(piece, new VirtualPoint(xPos, yPos));

                }
            }
        }

        invalidate();
        revalidate();
        repaint();
    }

    public class VirtualPoint {

        private float x;
        private float y;

        public VirtualPoint(float x, float y) {
            this.x = x;
            this.y = y;
        }

        public float getX() {
            return x;
        }

        public float getY() {
            return y;
        }

        public void setX(float x) {
            this.x = x;
        }

        public void setY(float y) {
            this.y = y;
        }
    }

    public class VirtualLayoutManager implements LayoutManager2 {

        private Map<Component, VirtualPoint> mapConstraints;

        public VirtualLayoutManager() {
            mapConstraints = new WeakHashMap<>(25);
        }

        @Override
        public void addLayoutComponent(Component comp, Object constraints) {
            if (constraints instanceof VirtualPoint) {
                mapConstraints.put(comp, (VirtualPoint) constraints);
            }
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
            mapConstraints.remove(comp);
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return new Dimension(400, 400);
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        @Override
        public void layoutContainer(Container parent) {
            int width = parent.getWidth();
            int height = parent.getHeight();

            for (Component comp : parent.getComponents()) {

                VirtualPoint p = mapConstraints.get(comp);
                if (p != null) {

                    int x = Math.round(width * p.getX());
                    int y = Math.round(height * p.getY());

                    Dimension size = comp.getPreferredSize();

                    x = Math.min(x, width - size.width);
                    y = Math.min(y, height - size.height);

                    comp.setBounds(x, y, size.width, size.height);

                }
            }
        }
    }
}

基本的に、これは「仮想」座標系を使用します。絶対的な x/y 位置をピクセル単位で指定するのではなく、親コンテナーのパーセンテージとして指定します。正直なところ、絶対配置に戻すのにそれほど時間はかかりません。この方法で、レイアウトのスケーリングも取得できます。

この例では、Z 並べ替え (念のため) も示しており、ダブルクリックするだけでパズルが再ランダム化されます。

あ、作品も透明にしました( opaque = false)

ランダムなレイアウト

ああ、私が言及しなければならないことの1つは、この例を調べているときに、ピースを画面外に(完全にまたは部分的に)配置できることがわかったということです。

配置コードをチェックして、画像がレイアウトされたときに画像が画面外に移動していないことを確認することをお勧めします;)

于 2012-08-06T04:33:38.430 に答える
3

パズル ピース コンストラクターでを使用setBorder(new LineBorder(Color.RED))して、パズル ピースの境界がどこにあるかを確認してみてください。期待どおりの位置にある場合は、ポジショニングが間違っている可能性があります。JComponentまた、代わりにパズルのピースを伸ばすか、伸ばすsetOpaque(false)場合は を使用しますJPanel

于 2012-08-05T20:23:38.180 に答える
3

提案したいことはたくさんありますが、まずは...

ランダムな位置を選択する方法がオフです...

int myX = randomNumber(0,(int)w);
int myY = randomNumber(0,(int)h);

これにより、重複した位置を生成できます (およびセルをオーバーレイできます)。

更新 (レイアウト マネージャーを使用)

さて、これはパラダイムのわずかなシフトです。クリップを作成して作品に渡すのではなく、作品をどのようにレンダリングするかを作品に選択させました。代わりに、それが担当する Rectangle を渡しました。

つまり、setCell(Rectangle)ピースを変更するようなものを使用するだけで済みます (ドラッグ アンド ドロップが苦手な場合を除きます ;))。

BoardJava 7 での興味深い動作のためにパネルを使用することになりましたが、それは別の質問です ;)

package puzzel;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.*;

public class PuzzlePieceDriver extends JFrame {


    public PuzzlePieceDriver(ImageIcon myPuzzleImage) {

        setTitle("Hot Puzz");

        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setLayout(new BorderLayout());
        add(new Board(myPuzzleImage));

        pack();

        setVisible(true);


    }//end constructor

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                ImageIcon image = new ImageIcon(PuzzlePieceDriver.class.getResource("/issue459.jpg"));

                PuzzlePieceDriver driver = new PuzzlePieceDriver(image);
                driver.setLocationRelativeTo(null);
                driver.setVisible(true);

            }
        });

    }
}//end class

ピースパネル...パネルはpreferredand minimumsize メソッドをオーバーライドします...この例では機能しますが、代わりにsetPreferredSizeandを使用する方がおそらく良いでしょう;)setMiniumumSize

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package puzzel;

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;

public class PuzzlePiece extends JPanel {

    private BufferedImage masterImage;
    private Rectangle pieceBounds;
    private BufferedImage clip;

    public PuzzlePiece(BufferedImage image, Rectangle bounds) {

        masterImage = image;
        pieceBounds = bounds;

        // Make sure the rectangle fits the image
        int width = Math.min(pieceBounds.x + pieceBounds.width, image.getWidth() - pieceBounds.x);
        int height = Math.min(pieceBounds.y + pieceBounds.height, image.getHeight() - pieceBounds.y);

        clip = image.getSubimage(pieceBounds.x, pieceBounds.y, width, height);

    }//end constructor

    @Override
    public Dimension getPreferredSize() {

        return pieceBounds.getSize();

    }

    @Override
    public Dimension getMinimumSize() {

        return getPreferredSize();

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        int x = 0;
        int y = 0;

        g.drawImage(clip, x, y, this);

        g.setColor(Color.RED);
        g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);

    }//end paintComponent

}//end class PuzzlePiece

ボードパネル.​​..主にJava 7で発生したいくつかの興味深い問題のために使用されました...MouseListenerプログラムを実行するときにボードをクリックすると、楽しいです;)

package puzzel;

import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

/**
 *
 * @author shane
 */
public class Board extends JPanel {

    public static final int X_PIECES = 4;
    public static final int Y_PIECES = 4;
    private PuzzlePiece[] puzzle = new PuzzlePiece[X_PIECES * Y_PIECES];

    private static BufferedImage image;

    public Board(ImageIcon myPuzzleImage) {

        image = iconToImage(myPuzzleImage); //pass image into bufferedImage form

        puzzle = createClip();

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                removeAll();

                invalidate();

                createClip();

//                doLayout();

                invalidate();
                revalidate();
                repaint();

            }
        });

    }

    public static BufferedImage iconToImage(ImageIcon icon) {
        Image img = icon.getImage();
        int w = img.getWidth(null);
        int h = img.getHeight(null);
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(img, 0, 0, null);
        g.dispose();

        return image;
    }//end BufferedImage

    protected int randomNumber(int min, int max) {
        int temp = min + (int) (Math.random() * ((max - min) + 1));

        return temp;
    }//end randomNumber

    private PuzzlePiece[] createClip() {

        int cw, ch;
        int w, h;
        w = image.getWidth(null);
        h = image.getHeight(null);
        cw = w / X_PIECES;
        ch = h / Y_PIECES;

        // Generate a list of cell bounds
        List<Rectangle> lstBounds = new ArrayList<>(25);

        for (int y = 0; y < h; y += ch) {

            for (int x = 0; x < w; x += cw) {

                lstBounds.add(new Rectangle(x, y, cw, ch));

            }

        }

        BufferedImage clip = image;

        setLayout(new GridBagLayout());

        for (int x = 0; x < X_PIECES; x++) {
            for (int y = 0; y < Y_PIECES; y++) {

                // Get a random index
                int index = randomNumber(0, lstBounds.size() - 1);

                // Remove the bounds so we don't duplicate any positions
                Rectangle bounds = lstBounds.remove(index);

                PuzzlePiece piece = new PuzzlePiece(clip, bounds);
                puzzle[x * X_PIECES + y] = piece;

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = x;
                gbc.gridy = y;
                gbc.fill = GridBagConstraints.BOTH;

                add(piece, gbc);
                piece.invalidate();
                piece.repaint();

            }//end nested for
        }//end for

        invalidate();
        repaint();

        return puzzle;
    }//end createClip

}

最終的にピースを移動する方法について質問することになると思いますが、問題のコンポーネントをレイアウトするために使用される制約を取得できるgetConstraintsGridBagLayoutという素晴らしいメソッドがあります。その後、 andの値を変更し、setConstraintsを使用して更新できます ( andを呼び出すことを忘れないでください;))gridxgridyinvalidaterepaint

詳細については、 GridBagLayout の使用方法をお読みになることをお勧めします ;)

最終的には、次のような結果になります。

パズル 1パズル 2

于 2012-08-05T23:06:06.357 に答える