Other ways of subreferencing images? - java

The only way I've found of drawing part of an image is with this drawImage function:
public abstract boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageObserver observer)
Is there a way of drawing a section of an image which only requires destination coordinates rather than a rectangle? I want to specify my image cut and then draw it at a coordinate rather than having to worry that the destination rectangle matches the size of my cut. I find this has more room for error as if you get it wrong it squeezes/stretches your image to fit etc. Plus when you have images moving around on screen it means moving two sets of points rather than one simple top left coordinate point.
(I'm sure I've seen a video where someone does this I just can't remember what the function is)

You can create a sub-image from your Image and then draw that.
Please check out the BufferedImage API, the getSubImage() method. This will return a cut out image from the big image as a BufferedImage object. Then you can draw this with a simpler drawImage(...) overload that just takes the position.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SubImageEg extends JPanel {
// images from Wikimedia Commons
// http://commons.wikimedia.org/wiki/Main_Page
public static final String MAIN_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/" +
"thumb/4/43/Sarcophilus_harrisii_taranna.jpg/800px-Sarcophilus_harrisii_taranna.jpg";
public static final String SECOND_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/" +
"thumb/f/f8/Soldering_a_0805.jpg/800px-Soldering_a_0805.jpg";
public static final String[] IMAGE_PATHS = {MAIN_IMG_PATH, SECOND_IMG_PATH};
private static final int SUB_X = 520;
private static final int SUB_Y = 340;
private static final int SUB_W = 150;
private static final int SUB_H = 150;
private static final int SEC_SUB_X = 400;
private static final int SEC_SUB_Y = 200;
private BufferedImage[] images = new BufferedImage[IMAGE_PATHS.length];
private BufferedImage secondImgSubImg;
public SubImageEg() {
try {
for (int i = 0; i < IMAGE_PATHS.length; i++) {
images[i] = ImageIO.read(new URL(IMAGE_PATHS[i]));
}
secondImgSubImg = images[1].getSubimage(SUB_X, SUB_Y, SUB_W, SUB_H);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (images[0] != null) {
g.drawImage(images[0], 0, 0, this);
}
if (secondImgSubImg != null) {
g.drawImage(secondImgSubImg, SEC_SUB_X, SEC_SUB_Y, this);
}
}
#Override
public Dimension getPreferredSize() {
if (images[0] != null) {
return new Dimension(images[0].getWidth(), images[0].getHeight());
} else {
return super.getPreferredSize();
}
}
private static void createAndShowGui() {
SubImageEg mainPanel = new SubImageEg();
JFrame frame = new JFrame("SubImageEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

How to remain KeyListener Images on JFrame after pressing a new Key

I'm completely new to Java and my project is to make a postcard generator with the keyboard.
My problem now is that I don't know how to make the images stay in the Frame when a new Key is pressed. Im sure I need an ArrayList but I don't know where it belongs in the code.
I would appreciate any help :)
public class Funktionier extends Canvas implements KeyListener {
private static final long serialVersionUID = 2576012469492443014L;
public JFrame frame;
private Image []pngs;
private int currentImage;
private Random random;
private int x;
private int y;
public Funktionier(int width, int height)
{
pngs = new Image[26];
for (int i=0; i<26; i++) {
try {
pngs[i] = ImageIO.read(new File("./res/JAVA-"+(char) ('A'+i)+".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
frame = new JFrame ();
JTextField field = new JTextField (30);
field.setBounds(219, 10, 437, 20);
frame.add(field);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Deine Karte");
frame.setResizable(false);
frame.setSize(width, height);
field.addKeyListener(this);
frame.add(this);
this.addKeyListener(this);
this.requestFocus();
frame.setVisible(true);
//currentImage = 0;
random = new Random ();
randomXY ();
}
public static void main (String[] args) {
new Funktionier (874,620);
}
public void randomXY () {
x= random.nextInt(getWidth()-130);
y= random.nextInt(getHeight()-110);
}
public void paint (Graphics g)
{
g.drawImage(pngs[currentImage], x, y, pngs[currentImage].getWidth(null), pngs[currentImage].getHeight(null), null);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyChar() < 'a' || e.getKeyChar() > 'z') return;
currentImage= e.getKeyChar()-'a' ;
randomXY ();
repaint ();
}
}
You should draw on a JPanel and not a Canvas so make class Funktionier extend JPanel and not Canvas.
You should override method paintComponent() and not method paint(). The first thing you need to do in your overridden paintComponent() method is to call super.paintComponent().
Each time paintComponent() is called, you need to draw everything because each time paintComponent() is called, you're starting with a blank JPanel. So don't just draw the "current" image. Also draw all the images you drew up to the current image.
Refer to Painting in AWT and Swing and also Performing Custom Painting
EDIT
Explanations after the code.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
public class Funktionier extends JPanel implements DocumentListener, Runnable {
private static final long serialVersionUID = 4909941254467865823L;
private static final Image[] PNGS;
private JFrame frame;
private List<ImagLocn> imagesToDraw;
private Random rand;
static {
PNGS = new Image[26];
for (int i = 0; i < 26; i++) {
try {
PNGS[i] = ImageIO.read(new File("JAVA-" + (char) ('A' + i) + ".png"));
}
catch (IOException xIo) {
throw new RuntimeException(xIo);
}
}
}
public Funktionier(int width, int height) {
imagesToDraw = new ArrayList<>();
rand = new Random();
setPreferredSize(new Dimension(width, height));
}
#Override // javax.swing.event.DocumentListener
public void insertUpdate(DocumentEvent docEvent) {
if (docEvent.getLength() > 0) {
Document doc = docEvent.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
text = text.strip();
length = text.length();
String lastLetter = text.substring(length - 1, length);
int index = lastLetter.charAt(0) - 'A';
if (index >= 0 && index < PNGS.length) {
imagesToDraw.add(new ImagLocn(PNGS[index],
rand.nextInt(getWidth()),
rand.nextInt(getHeight())));
repaint();
}
}
catch (BadLocationException xBadLocation) {
throw new RuntimeException(xBadLocation);
}
}
}
#Override // javax.swing.event.DocumentListener
public void removeUpdate(DocumentEvent docEvent) {
// Do nothing.
}
#Override // javax.swing.event.DocumentListener
public void changedUpdate(DocumentEvent docEvent) {
// Do nothing.
}
#Override // java.lang.Runnable
public void run() {
showGui();
}
#Override // javax.swing.JComponent
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (ImagLocn il : imagesToDraw) {
g.drawImage(il.getImage(), il.getX(), il.getY(), null);
}
}
private JPanel createTextFieldPanel() {
JPanel textFieldPanel = new JPanel();
JTextField field = new JTextField(30);
Document doc = field.getDocument();
doc.addDocumentListener(this);
if (doc instanceof AbstractDocument) {
AbstractDocument absDoc = (AbstractDocument) doc;
absDoc.setDocumentFilter(new DocuFltr());
}
textFieldPanel.add(field);
return textFieldPanel;
}
private void showGui() {
frame = new JFrame("Deine Karte");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createTextFieldPanel(), BorderLayout.PAGE_START);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Funktionier(500, 500));
}
}
class DocuFltr extends DocumentFilter {
#Override
public void insertString(FilterBypass fb,
int offset,
String string,
AttributeSet attr) throws BadLocationException {
if (string.matches("^[A-Za-z]+$")) {
fb.insertString(offset, string.toUpperCase(), attr);
}
}
#Override
public void replace(FilterBypass fb,
int offset,
int length,
String text,
AttributeSet attrs) throws BadLocationException {
if (text.matches("^[A-Za-z]+$")) {
fb.replace(offset, length, text.toUpperCase(), attrs);
}
}
}
class ImagLocn {
private Image image;
private int x;
private int y;
public ImagLocn(Image img, int anX, int aY) {
image = img;
x = anX;
y = aY;
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Here is how it looks when I run the above code.
Refer to Laying Out Components Within a Container. Don't use setBounds() to place your components on the screen. Use a layout manager. The default layout manager for the content pane of a JFrame is BorderLayout.
I use a document filter to ensure that only letters of the alphabet can be entered into the JTextField. The document filter also converts lower case letters to upper case.
I implement a document listener rather than a KeyListener. In the document listener, each time another letter is entered into the JTextField, I add another image to the list of images that need to be drawn.
As I wrote in my original answer, I override method paintComponent() and always draw the entire list of images.
I placed all the PNG images in the working directory, i.e. the value returned by System.getProperty("user.dir"). I did this only to make things easier for myself. You can put them anywhere you like. Just make sure you use the correct path to the files in your code.

JFrame Image Update on click of image

tldr; How do you use a MouseEvent on a JFrame object(specifically JLabel) to update the displayed image in the JFrame
I am trying to create a program where an image is broken into tiles and on click of one of those tiles, the program moves the tile to the open space in the image. (See Sliding Puzzle for more information).
I currently am able to select an image, break the image into tiles, and "randomly" remove one of the tiles.
My next step would be, on click of one of the tiles, to swap it with the empty tile (I will work on the "eligibility" of tiles to be swapped at a later time, but for now, just want to be able to swap the tile selected with the current blank tile)
To create my image for a 3x3 grid, I split a bufferedImage into 9 equal pieces, "randomly" blank one of the images, and then display the images in jLabels using GridLayout to line them up.
When I add mouseListeners to each jLabel, I am able to see that I am entering the MouseListener as I can see the console log message "Clicked" as shown below, however, am not able to update the image as desired.
How can I use a MouseEvent on these JFrame JLabels to call a method within ImageContainer(i.e. move()) and update the displayed image?
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,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, 0, 0, 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 answer is based on this previous answer, adapted to your code.
It is a one-file mre : the entire code can be copy-pasted to ImageJumble.java file, and run.
It supports DnD from any grid location to any other. You may want to change it. Please note the comments:
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, 0, 0, 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, DnDConstants.ACTION_COPY, 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);
}
}
Don't remove/add components. Instead just swap the Icon.
Use a JPanel with a GridLayout that contains a JLabel in each grid
Add an ImageIcon to each JLabel (except for one)
Add a MouseListner to each JLabel.
In the mouseClicked event you get the label that was clicked and remove the ImageIcon and add the Icon to the empty label.
So when you create the board you could have a variable like emptyLabel which would be initialized to the label without the Icon. Then the logic in the mouseClicked might be something like:
JLabel clicked = (JLabel)e.getSource();
emptyLabel.setIcon( clicked.getIcon() );
emptyLabel = clicked;
Create a custom JLabel class to hold the position (i):
class MyImageLabel extends JLabel {
private int position;
public MyImageLabel(Icon image,int position) {
super(image);
this.position=position;
}
public int getPosition()
{
return position;
}
}
Adapt createImage to instantiate this class instead of JLabels and in the mouseListener you can call 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();
}
});
}
My advice is not to call .add and .removeAll on the JFrame object but create a new JPanel with the GridLayout and use jframe.getContentPanel().add(labelsPanel). If it doesn't refresh you can then call revalidate() on your JPanel.

Java-Image not drawing to screen

I am trying to draw an image to the screen using Java. The problem is that it does not appear and no errors occur.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class GameClass extends JPanel implements ActionListener, KeyListener{
private BufferedImage image;
public GameClass(){
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
}
public void openImage(){
try {
image = ImageIO.read(this.getClass().getResource("spaceship.png"));
} catch (IOException e) {
System.out.println("An error occurred!");
}
}
public void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, Main.WW, Main.WH);
g.drawImage(image,Main.WW/2,Main.WH/2,null);
}
public void actionPerformed(ActionEvent e){
repaint();
}
public void keyPressed(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){
}
}
You need to call you openImage() method in your constructor.
I renamed this to loadImages() so that this method can handle loading multiple images. I also created a static image loading function.
Note: If you have not already, create a resources/ folder in your projects' src/ folder. This folder will contain your application's assets i.e. text, image, and other data files.
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*
public class GameClass extends JPanel
implements ActionListener, KeyListener {
private static final long serialVersionUID = -2508183917768834794L;
private Image image;
// Added this, because you did not include it.
private class Main {
static final int WW = 256;
static final int WH = 256;
}
public GameClass() {
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
this.loadImages();
}
// Load all required images into instance variables.
public void loadImages() {
image = loadImage("spaceship.png");
}
// Draw the image to the panel.
public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, Main.WW, Main.WH);
// Dimensions of spaceship
int imgW = image.getWidth(null);
int imgH = image.getHeight(null);
// Dimensions of panel
int pnlW = this.getWidth();
int pnlH = this.getHeight();
// Draw the spaceship in the center of the window.
g.drawImage(image, pnlW/2 - imgW/2, pnlH/2 - imgH/2, null);
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
// Static image loader method which utilizes the `ClassLoader`.
public static Image loadImage(String filename) {
try {
return ImageIO.read(GameClass.class.getClassLoader().getResource("resources/" + filename));
} catch (IOException e) {
System.out.println("Error loading image: " + filename);
}
return null;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
Container panel = new GameClass();
frame.setSize(Main.WW, Main.WH);
frame.setTitle("Spaceship Game");
frame.setContentPane(panel);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}

I'm attempting to import a picture into my projecy but does not work

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
public class spriteStore {
public static BufferedImage playerStanding;
public void getImage()
{
try
{
playerStanding = ImageIO.read(new File("Cobalt\\pictures\\playerStanding1.png"));
}
catch(Exception e){System.out.println("Picture not found");}
}
}
I am trying to read an image to save as a BufferedImage object, but when i run the main code,
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Cobalt {
public Boolean movingLeft, movingRight, firstJump, secondJump;
public int jump = 0;
public Dimension screenSize;
public JFrame frame;
public JPanel panel;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run(){
new Cobalt();
}
});
}
public Cobalt()
{
frame = new JFrame("COBALT");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(true);
frame.setSize(500,500); //width and height
panel = new MyPanel();
frame.getContentPane().add(panel);
}
class MyPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public void paint(Graphics g)
{
Graphics g2D = (Graphics2D) g;
super.paint(g);
g2D.drawImage(spriteStore.playerStanding, 100, 100, null);
}
}
}
and the image will not show up. I'm using eclipse, and am relatively a noob, so please inform me of my error.
There is no need to do custom painting to show an image.
You can use a JLabel. Read the section from the Swing tutorial on How to Use Icons.
I assume that you have in your project a structure like this:
Cobalt
|
\---src
| Cobalt.java
|
\---pictures
playerStanding1.png
Try the following:
public static void main(String[] args) throws Exception {
URL url = ClassLoader.getSystemClassLoader().
getResource("pictures/playerStanding1.png");
BufferedImage playerStanding = ImageIO.read(url);
JLabel label = new JLabel(new ImageIcon(playerStanding));
JOptionPane.showMessageDialog(null, label);
}
Try this to create the jlabel
ImageIcon icon = createImageIcon("images/middle.gif",
"a pretty but meaningless splat");
JLabel thumb = new JLabel();
thumb.setIcon(icon);
And load the image like this
/** Returns an ImageIcon, or null if the path was invalid. */
protected ImageIcon createImageIcon(String path,
String description) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
//System.err.println("Couldn't find file: " + path);
return null;
}
}
And if you want it from a url
URL PicURL = new URL("http://...");
ImageIcon imgThisImg = new ImageIcon(PicURL));
jLabel2.setIcon(imgThisImg);

Java JFrame - Doesnt repaint() untill another thread is finished

I'm attempting to create a game and I'm starting with the loading screen, where it will load all the needed files. I want to show a percentage of completion but its not working. The JPanel Loading only repaints() after Loading_files is finished. I don't know whats wrong.
Main.java
package Main;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JFrame{
//-------------- Final Variables --------------
//Screen Related
public final static int JFRAME_WIDTH = 800;
public final static int JFRAME_HEIGHT = 600;
public final static Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
public final static int SCREEN_WIDTH = SCREEN_SIZE.width;
public final static int SCREEN_HEIGHT = SCREEN_SIZE.height;
//Game Related
public final static String NAME = "Xubris";
public final static String IMAGE_DIRECTORY = System.getProperty("user.dir") + "\\images\\";
public static final int FPS = 1000 / 36;
//-------------- Dynamic Variables --------------
//Global
public static JFrame main;
public static void main(String[] args) {
//Start the Loading screen
Loading load = new Loading();
main = new JFrame(NAME);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setSize(JFRAME_WIDTH, JFRAME_HEIGHT);
main.setLocation((SCREEN_WIDTH-JFRAME_WIDTH)/2, (SCREEN_HEIGHT-JFRAME_HEIGHT)/2);
//Add Content
main.getContentPane().add(load);
main.setResizable(false);
main.setUndecorated(false);
main.setVisible(true);
}
}
Loading.java
package Main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Loading extends JPanel implements Runnable{
//Pictures
BufferedImage background;
//-------------- Final Variables --------------
private final int num_of_files = 32;
//-------------- Dynamic Variables --------------
//Global Variables
private double loading_percentage = 0;
private int num_of_loaded_files = 0;
public Loading(){
try {
background = ImageIO.read(new File(Main.IMAGE_DIRECTORY + "Background_Loading.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
//Start the thread
new Thread(new LoadingFiles()).start();
new Thread(this).start();
}
public void paint(Graphics g){
g.drawImage(background, 0, 0, this);
for(int i = 0; i < loading_percentage; i=i+15){
g.setColor(new Color(20,241,47));
g.drawRect(180 + (i/15)*(50+10), 375, 50, 50);
}
}
#Override
public void run(){
while(true){
repaint();
}
}
class LoadingFiles implements Runnable{
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
num_of_loaded_files++;
loading_percentage = (num_of_loaded_files/num_of_files)*100;
if(num_of_loaded_files!=32)
run();
}
}
}
Blocking the EDT and repaint coalescing where my first ideas as well (that's why I upvoted the comments). But got curious - neither is the real problem :-)
it's perfectly valid to call repaint from whatever thread (though doing so in a tight while-loop certainly slows down ui reactivity)
doesn't repaint as expected even after some cleanup (see below). The culprit for that is purely arithmetic
the following line:
loading_percentage = (num_of_loaded_files/num_of_files)*100;
which is 0 until
num_of_loaded_files == num_of_files
that is until everything loaded. We all are guilty of jumping to conclusions :-)
Some cleanup:
following java naming conventions makes code easier to read
don't override paint, instead override paintComponent
always call super in paintComponent (by default a JPanel reports to be opaque, that is, it must fill its area)
no need for intertwined threads, simply let the loading thread call repaint after having loaded the next image
get the arithmetic correct :-)
Code:
public class Loading extends JPanel {
// Pictures
private BufferedImage background;
// -------------- Final Variables --------------
private final int numOfFiles = 32;
// -------------- Dynamic Variables --------------
// Global Variables
private double loadingPercentage = 0;
private int numOfLoadedFiles = 0;
public Loading() {
background = XTestUtils.loadDefaultImage("moon.jpg");
// Start the thread
new Thread(new LoadingFiles()).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, this);
for (int i = 0; i < loadingPercentage; i = i + 15) {
g.setColor(new Color(20, 241, 47));
g.drawRect(180 + (i / 15) * (50 + 10), 375, 50, 50);
}
}
class LoadingFiles implements Runnable {
#Override
public void run() {
while (numOfLoadedFiles < 32) {
numOfLoadedFiles++;
loadingPercentage = (double) numOfLoadedFiles / numOfFiles
* 100;
repaint();
try {
// simulate the loading
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
JFrame frame = new JXFrame("", true);
frame.add(new Loading());
frame.setSize(600, 600);
frame.setVisible(true);
}
}

Categories