绝对定位graphicsJPanel里面的空白部分阻止JFrame
我试图通过制作一个谜题程序来提高对Java的了解,尤其是Java GUI。 目前,用户select一个图像,它被分割成指定的数量。 这些作品随机抽取到屏幕上,但似乎被其他作品的空白部分覆盖,并不是所有作品都显示出来,但是我可以打印出所有的坐标。 我正在使用绝对定位,因为LayoutManager似乎没有工作。 我简单地尝试了layeredPanes,但他们混淆了我,似乎没有解决问题。 我真的很感谢一些帮助。
这里有两个相关的类:
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
任何帮助将不胜感激,我已经真的卡住了! 谢谢!!
我对这个想法非常感兴趣,所以我做了另一个例子,使用自定义布局pipe理器。
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-reording(以防万一),双击简单重新随机化puzzel
哦,我也做了这件作品透明( opaque = false
)
哦,我应该提到的一点是,在通过这个例子的时候,我发现有可能把部分片断放在屏幕上(完全和部分)。
您可能需要检查您的定位代码,以确保图像布局时没有移出屏幕;)
尝试在你的拼图构造函数中使用setBorder(new LineBorder(Color.RED))
来查看拼图的边界在哪里。 如果他们是你所期望的,那么你的定位可能是错误的。 也可以让拼图扩展JComponent
,或者使用setOpaque(false)
扩展JPanel
。
我想提出很多build议,但是首先…
你select随机位置的方式是closures的
int myX = randomNumber(0,(int)w); int myY = randomNumber(0,(int)h);
这允许重复的位置被生成(并覆盖单元格)
更新(使用布局pipe理器)
好的,这是一个范式的轻微转变。 而不是制作一个剪辑并将其传递给作品,我允许作品select关于如何渲染作品。 相反,我通过它负责的矩形。
这意味着,你可以简单地使用像setCell(Rectangle)
这样的东西来改变一个片断(除非你是setCell(Rectangle)
地setCell(Rectangle)
)
由于Java 7下的一些有趣的行为,我最终使用了Board
面板,但这是另一个问题;)
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
一个面板…面板覆盖preferred
和minimum
尺寸的方法…虽然它适用于这个例子,它可能会更好地使用setPreferredSize
和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 }
现在我知道你最终会问如何移动一块, GridBagLayout
有这个叫做getConstraints的精彩方法,它允许你检索用于布置有问题的组件的约束。 然后你可以修改gridx
和gridy
值并使用setConstraints来更新它(不要忘记调用invalidate
和repaint
;))
我build议阅读如何使用GridBagLayout的更多信息;)
最终,你会最终得到像这样的东西: