如何解决点击图片即可进行JFrame图片更新
tldr; 如何在JFrame对象(特别是JLabel)上使用MouseEvent更新JFrame中显示的图像
我正在尝试创建一个程序,在该程序中,将图像分解为图块,并单击其中一个图块,该程序将图块移至图像中的空白处。 (有关更多信息,请参见Sliding Puzzle。
我目前能够选择一张图片,将该图片分成小块,然后“随机”删除其中一个小块。
我的下一步是,单击其中一个图块,将其与空图块交换(我将处理稍后要交换的图块的“资格”,但现在,只想能够将所选图块与当前空白图块交换)
要为3x3网格创建图像,我将bufferedImage分成9个相等的部分,将其中一张图像“随机”地空白,然后使用GridLayout将它们排列在jLabel中。
当我将mouseListeners添加到每个jLabel时,我可以看到正在进入MouseListener,因为可以看到如下所示的控制台日志消息“ Clicked”,但是无法根据需要更新图像。 / p>
如何在这些JFrame JLabel上使用MouseEvent来调用ImageContainer中的方法(即move())并更新显示的图像?
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class ImageJumble extends JPanel {
static int difficulty = 0;
ImageContainer imageContainer;
JFrame jFrame = new JFrame("Image Jumble");
private void run() {
SwingUtilities.invokelater(this::displayImage);
}
public static void main(String[] args) {
System.out.print("Please enter the difficulty level (1-3): ");
Scanner scanner = new Scanner(system.in);
difficulty = scanner.nextInt();
new ImageJumble().run();
}
private void displayImage() {
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Please choose an image...");
FileNameExtensionFilter filter = new FileNameExtensionFilter("JPEG","jpeg","jpg","png","bmp","gif");
fc.addChoosableFileFilter(filter);
BufferedImage image = null;
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
try {
image = ImageIO.read(selectedFile);
} catch (IOException ex) {
ex.printstacktrace();
}
}
jFrame.setDefaultCloSEOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setSize(image.getWidth(),image.getHeight());
jFrame.setVisible(true);
jFrame.setLayout(new GridLayout(difficulty,difficulty,0));
imageContainer = new ImageContainer(image,difficulty);
createImage();
}
private void createImage() {
imageContainer.randomize();
JLabel[] jLabels = new JLabel[difficulty * difficulty];
for(int i = 0; i < jLabels.length; i++) {
JLabel jLabel = new JLabel(new ImageIcon(imageContainer.getBufferedImages().get(i)));
jFrame.add(jLabel);
jLabel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked!");
imageContainer.move(i);
jFrame.removeAll();
createImage();
}
});
}
}
}
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ImageContainer {
private List<BufferedImage> bufferedImages = new ArrayList<>();
private int blankLocation = 0;
public ImageContainer(BufferedImage image,int difficulty) {
BufferedImage bi = new BufferedImage(image.getWidth(null),image.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(image,null);
int width = bi.getWidth();
int height = bi.getHeight();
int swidth = width / difficulty;
int sheight = height / difficulty;
for (int i = 0; i < difficulty; i++) {
for (int j = 0; j < difficulty; j++) {
BufferedImage bimg = bi.getSubimage(j * swidth,i * sheight,swidth,sheight);
bufferedImages.add(bimg);
}
}
}
public List<BufferedImage> getBufferedImages() {
return bufferedImages;
}
public void setBufferedImages(List<BufferedImage> bufferedImages) {
this.bufferedImages = bufferedImages;
}
public void randomize() {
int size = bufferedImages.size();
int width = bufferedImages.get(0).getWidth();
int height = bufferedImages.get(0).getHeight();
blankLocation = new Random().nextInt(size);
bufferedImages.set(blankLocation,new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB));
}
public void move(int i) {
bufferedImages.set(blankLocation,bufferedImages.get(i));
blankLocation = i;
}
}
解决方法
此答案基于this的上一个答案,该答案适用于您的代码。
这是一个文件的文件:可以将整个代码复制粘贴到ImageJumble.java
文件中并运行。
它支持从任何网格位置到任何其他位置的DnD。您可能要更改它。
请注意注释:
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class ImageJumble extends JPanel {
private static int difficulty = 3;
private static final String FLOWER = "http://www.digitalphotoartistry.com/rose1.jpg";
private static final int GAP = 4;
private JPanel content;
private void run() {
SwingUtilities.invokeLater(this::displayImage);
}
public static void main(String[] args) {
new ImageJumble().run();
}
private void displayImage() {
BufferedImage bi = null;
try {
bi = ImageIO.read(new URL(FLOWER));
} catch (IOException ex) {
ex.printStackTrace();
}
content = new JPanel(new GridLayout(difficulty,difficulty,GAP,GAP));
createImage(bi);
JFrame jFrame = new JFrame("Image Jumble");
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.add(content);
jFrame.pack();
jFrame.setVisible(true);
}
private void createImage( BufferedImage bi) {
ImageContainer imageContainer = new ImageContainer(bi,difficulty);
imageContainer.randomize();
for(int i = 0; i < difficulty * difficulty; i++) {
content.add(new DragDropPane(imageContainer.getBufferedImages().get(i)));;
}
}
}
class ImageContainer {
private final List<BufferedImage> bufferedImages = new ArrayList<>();
private int blankLocation = 0;
public ImageContainer(BufferedImage image,int difficulty) {
BufferedImage bi = new BufferedImage(image.getWidth(null),image.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(image,null);
int width = bi.getWidth();
int height = bi.getHeight();
int swidth = width / difficulty;
int sheight = height / difficulty;
for (int i = 0; i < difficulty; i++) {
for (int j = 0; j < difficulty; j++) {
BufferedImage bimg = bi.getSubimage(j * swidth,i * sheight,swidth,sheight);
bufferedImages.add(bimg);
}
}
}
public List<BufferedImage> getBufferedImages() {
return bufferedImages;
}
public void randomize() {
Collections.shuffle(bufferedImages);//shuffle images
int size = bufferedImages.size();
int width = bufferedImages.get(0).getWidth();
int height = bufferedImages.get(0).getHeight();
blankLocation = new Random().nextInt(size);
bufferedImages.set(blankLocation,new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB));
}
}
class DragDropPane extends JPanel implements DragGestureListener,DragSourceListener {
private JComponent dragable;
private final BufferedImage bi;
public DragDropPane(BufferedImage bi) {
setBackground(Color.BLACK);
this.bi = bi;
var label = new JLabel(new ImageIcon(bi),JLabel.CENTER);
setContent(label);
new MyDropTargetListener(this);
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
this,DnDConstants.ACTION_COPY,this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(),bi.getHeight());
}
public void setContent(JComponent component) {
removeAll();
dragable = component;
add(component);
repaint();
}
//-->DragGestureListener implementation
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
// Create our transferable wrapper
Transferable transferable = new TransferableComponent(dragable);
// Start the "drag" process...
DragSource ds = dge.getDragSource();
ds.startDrag(dge,Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR),transferable,this);
remove(dragable);
revalidate(); repaint();
}
//-->DragSourceListener implementation
@Override
public void dragEnter(DragSourceDragEvent dsde) {}
@Override
public void dragOver(DragSourceDragEvent dsde) {}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {}
@Override
public void dragExit(DragSourceEvent dse) {}
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {
// If the drop was not successful,we need to
// return the component back to it's previous
// parent
if (!dsde.getDropSuccess()) {
setContent(dragable);
}
}
}
class MyDropTargetListener extends DropTargetAdapter {
private final DragDropPane target;
public MyDropTargetListener(DragDropPane target) {
this.target = target;
new DropTarget(target,this,true,null);
}
@Override
public void drop(DropTargetDropEvent event) {
try {
var tr = event.getTransferable();
var component = (JComponent) tr.getTransferData(TransferableComponent.component);
if (event.isDataFlavorSupported(TransferableComponent.component)) {
event.acceptDrop(DnDConstants.ACTION_COPY);
target.setContent(component);
event.dropComplete(true);
} else {
event.rejectDrop();
}
} catch (Exception e) {
e.printStackTrace();
event.rejectDrop();
}
}
}
class TransferableComponent implements Transferable {
protected static final DataFlavor component =
new DataFlavor(JComponent.class,"A Component");
protected static final DataFlavor[] supportedFlavors = {
component
};
private final JComponent componentToTransfer;
public TransferableComponent(JComponent componentToTransfer) {
this.componentToTransfer = componentToTransfer;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return supportedFlavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(component);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (flavor.equals(component)) return componentToTransfer;
else throw new UnsupportedFlavorException(flavor);
}
}
,
不删除/添加组件。而是只需交换图标。
- 将JPanel与GridLayout一起使用,该GridLayout在每个网格中都包含一个JLabel
- 向每个JLabel添加ImageIcon(一个除外)
- 向每个JLabel添加一个MouseListner。
- 在mouseClicked事件中,您将获得单击的标签,然后删除ImageIcon并将图标添加到空白标签。
因此,当您创建木板时,您可能会有一个像emptyLabel
这样的变量,该变量将被初始化为不带图标的标签。那么mouseClicked中的逻辑可能类似于:
JLabel clicked = (JLabel)e.getSource();
emptyLabel.setIcon( clicked.getIcon() );
emptyLabel = clicked;
,
创建一个自定义JLabel类以保留位置(i):
class MyImageLabel extends JLabel {
private int position;
public MyImageLabel(Icon image,int position) {
super(image);
this.position=position;
}
public int getPosition()
{
return position;
}
}
自适应createImage
来实例化此类而不是JLabel
,在mouseListener中,您可以调用getPosition()
:
for(int i = 0; i < jLabels.length; i++) {
MyImageLabel jLabel = new MyImageLabel(new ImageIcon(imageContainer.getBufferedImages().get(i)),i);
jFrame.add(jLabel);
jLabel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked!");
imageContainer.move(jLabel.getPosition());
jFrame.removeAll();
createImage();
}
});
}
,
我的建议是不要在JFrame对象上调用.add和.removeAll,而是使用GridLayout创建一个新的JPanel并使用jframe.getContentPanel()。add(labelsPanel)。如果它没有刷新,则可以在JPanel上调用revalidate()。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。