I have tried to look at other topics with similar question like mine, and most of those solutions appear to point to fixing the classpath for images... so, I tried those by changing the classpath to absolute and using class get resource, but it still won't render the images. I have a suspicion that it has to do with the main method. I don't completely understand how that method works since I copied the source code somewhere online. I am using the Eclipse editor, and I already had put the image files alongside the Flap class file.
package wing;
import java.awt.*;
import javax.swing.*;
public class Flap extends JComponent implements Runnable {
Image[] images = new Image[2];
int frame = 0;
public void paint(Graphics g) {
Image image = images[frame];
if (image != null) {
// Draw the current image
int x = 0;
int y = 0;
g.drawImage(image, x, y, this);
}
}
public void run() {
// Load the array of images
images[0] = new ImageIcon(this.getClass().getResource("/Wing/src/wing/wing1.png"));
images[1] = new ImageIcon(this.getClass().getResource("/Wing/src/wing/wing2.png"));
// Display each image for 1 second
int delay = 10000; // 1 second
try {
while (true) {
// Move to the next image
frame = (frame+1)%images.length;
// Causes the paint() method to be called
repaint();
// Wait
Thread.sleep(delay);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Flap app = new Flap();
// Display the animation in a frame
JFrame frame = new JFrame();
frame.getContentPane().add(app);
frame.setSize(800, 700);
frame.setVisible(true);
(new Thread(app)).start();
}
}
ImageIcon is not an Image :
images[0] = new ImageIcon(this.getClass().getResource("/Wing/src/wing/wing1.png")).getImage();
The application never ends, in main :
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
if isn't there any another JComponent(s) added to the public class Flap extends JComponent implements Runnable {
put Image as Icon to the JLabel
use Swing Timer instead of Runnable#Thread (required basic knowledge about Java and Threads too)
if there is/are another JComponent(s) added to the public class Flap extends JComponent implements Runnable {
don't use paint() use paintComponent() for Swing JComponents
use Swing Timer instead of Runnable#Thread (required basic knowledge about Java and Threads too)
in both cases load image as local variable, don't reload images forever
in both cases you have invoke Swing GUI from InitialThread
The resource name "/Wing/src/wing/wing1.png" looks suspicious: it means to locate a resource in the "/Wing/src/wing/" directory, which is most likely not where the resource actually is. Try "/wing/wing1.png" (similarly for the others)
The reason is that the src folder contains the source, which will be converted to classes. So "src/wing/Flap.java" will have the class path "/wing/Flap.class"; similarly for resources (depending on how you are packaging them).
Also, make sure the resource is indeed where you expect it to be (e.g. next to the Flap.class file in the output directory), otherwise the class loader will not find it.
Related
This is my first time trying to use another thread in java, could someone tell me how to make it work please? I've read others topics about it, but I didn't find a solution.
I'd like to draw a gif in another thread (drawn at at a random position and during the duration of its animation).
The problem is that drawImage() in the second thread just doesn't do anything. My counter works well (it prints 1.. 2.. 3 ...), but no image is drawn (or I can't see it).
The condition is false at the begining, then it is true at one moment (to create only one new thread and no more), then it is false again.
if (condition) {
(new ThreadGif(this,g)).start();
}
However when I remove the condition in paintComponent(), it draws something which means that drawImage() works. So when it creates lots of new threads, every image of the gif is drawn at a random location and it starts the gif again and again (and the counter(s) still work well).
This could be fine, but I don't think creating thousands of new thread is the answer : I just need one. And also, I need just one random position for each gif, not one different for each image of the gif.
I hope I've been clear enough. Please help me understand how to make it work :) Thank you very much.
Here are simplified versions of my two classes :
ThreadGif.java :
public class ThreadGif extends Thread {
Screen screen;
Graphics g;
boolean running = true;
public ThreadGif(Screen screen, Graphics g) {
this.g = g;
this.screen = screen;
}
public void run() {
int aleaX = new Random().nextInt(300)/100;
int aleaY = new Random().nextInt(300)/100;
int compt = 1;
while (running) {
g.drawImage(new ImageIcon("res/feu.gif").getImage(), screen.tailleCase*aleaX, screen.tailleCase*aleaY, screen.tailleCase*2, screen.tailleCase*2, screen);
System.out.println("thread " + compt);
compt++;
try {
Thread.sleep(sleepTime);
} catch(InterruptedException e) {
e.printStackTrace ();
}
}
}
}
Screen.java :
public class Screen extends JPanel implements Runnable {
Thread thread = new Thread(this);
public Screen(Frame frame) {
this.frame = frame;
thread.start();
}
public void paintComponent(Graphics g) {
g.clearRect(0, 0, this.frame.getWidth(), this.frame.getHeight());
if (condition) {
(new ThreadGif(this,g)).start();
}
}
public void run() {
while (running) {
repaint();
try {
Thread.sleep(sleepTime);
} catch(InterruptedException e) {
e.printStackTrace ();
}
}
System.exit(0);
}
}
Pretty simple: you mixed two approaches up.
The paintComponent-method launches a new ThreadGif every time it's called and ThreadGif itself paints within it's thread until it's terminated, but without refreshing the screen.
These two approaches combined might either result in strange behaviour, e.g. two images painted where pieces overlay each other, or the new ThreadGif simply renders the new image every-time you repaint the screen.
Solution: Start by assigning each class specific tasks, without mixing anything up, or splitting tasks between two classes. E.g.:
ThreadGif doesn't paint anything itself, but repaints the Screen. The Screen can request the image that should be displayed from ThreadGif.
Make ThreadGif an own Component that handles it's own rendering and ommit the Screen-class from painting anything.
I am having a error for my GUI. Trying to set title bar icon then be included in a Runnable JAR.
BufferedImage image = null;
try {
image = ImageIO.read(getClass().getClassLoader().getResource("resources/icon.gif"));
}
catch (IOException e) {
e.printStackTrace();
}
frame.setIconImage(image);
Here is the error I am getting:
Exception in thread "main" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at GUI.<init>(GUI.java:39)
at GUI.main(GUI.java:351)
The image is in the correct directory which "resources" folder is the root of the
project file
First of all, change this line :
image = ImageIO.read(getClass().getClassLoader().getResource("resources/icon.gif"));
to this :
image = ImageIO.read(getClass().getResource("/resources/icon.gif"));
More info, on as to where lies the difference between the two approaches, can be found on this thread - Different ways of loading a Resource
For Eclipse:
How to add Images to your Resource Folder in the Project
For NetBeans:
Handling Images in a Java GUI Application
How to add Images to the Project
For IntelliJ IDEA:
Right-Click the src Folder of the Project. Select New -> Package
Under New Package Dialog, type name of the package, say resources. Click OK
Right Click resources package. Select New -> Package
Under New Package Dialog, type name of the package, say images. Click OK
Now select the image that you want to add to the project, copy it. Right click resources.images package, inside the IDE, and select Paste
Use the last link to check how to access this file now in Java code. Though for this example, one would be using
getClass().getResource("/resources/images/myImage.imageExtension");
Press Shift + F10, to make and run the project. The resources and images folders, will be created automatically inside the out folder.
If you are doing it manually :
How to add Images to your Project
How to Use Icons
A Little extra clarification, as given in this answer's first
code example.
QUICK REFERENCE CODE EXAMPLE(though for more detail consider, A little extra clarification link):
package swingtest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
/**
* Created with IntelliJ IDEA.
* User: Gagandeep Bali
* Date: 7/1/14
* Time: 9:44 AM
* To change this template use File | Settings | File Templates.
*/
public class ImageExample {
private MyPanel contentPane;
private void displayGUI() {
JFrame frame = new JFrame("Image Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new MyPanel();
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class MyPanel extends JPanel {
private BufferedImage image;
public MyPanel() {
try {
image = ImageIO.read(MyPanel.class.getResource("/resources/images/planetbackground.jpg"));
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(400, 300): new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ImageExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
There's a much easier way to load and set an image as a frame icon:
frame.setIconImage(
new ImageIcon(getClass().getResource("/resources/icon.gif")).getImage());
And thats all :)! You don't even have to use a try-catch block because ImageIcon does not throw any declared exceptions. And due to getClass().getResource(), it works both from file system and from a jar depending how you run your application.
If you need to check whether the image is available, you can check if the URL returned by getResource() is null:
URL url = getClass().getResource("/resources/icon.gif");
if (url == null)
System.out.println( "Could not find image!" );
else
frame.setIconImage(new ImageIcon(url).getImage());
The image files must be in the directory resources/ in your JAR, as shown in How to Use Icons and this example for the directory named images/.
Question: So I am attempting to understand how threads work with graphics so I created a program that should set the color of the screen to red using a user thread. However, when I run the program, it opens my JFrame window an infinite number of times on top of each other and I have to quit the program for it to stop. How do I prevent this from happening? Thanks in advance.
UPDATE: So a lot of you have explained to me the culprit (commented out now): frame.add(new MWT) that repeatedly calls the constructor and creates a new object. However, How do I simply add the Canvas to the JFrame without any static instances? Thanks
Class Code
public class MWT extends Canvas implements Runnable
{
private Thread fast;
public static void main(String [] args){
MWT draw = new MWT();
}
public MWT(){
JFrame frame = new JFrame("Thread Drawings");
frame.setVisible(true);
frame.setFocusable(true);
frame.setSize(600,500);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
// CULPRIT
//frame.add(new MWT());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start();
}
private void stop() {
if (fast== null){
return;
}
else{
System.exit(0);
}
}
private void start() {
if (fast != null){
return;
}
else{
fast = new Thread(this);
fast.start();
}
}
#Override
public void run() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
Graphics2D g2d = (Graphics2D) g;
render(g2d);
}
public void render(Graphics2D g2d){
g2d.setColor(Color.RED);
g2d.fillRect(0, 0,600,500);
stop();
}
}
The problem is with the constructor for MWT at the line add(new MWT()). So when you construct a new MWT, you create a new JFrame, then you called MWT() again, creating a new JFrame, calling MWT() again, and so on. Eventually you should run into a stack overflow though.
To solve that, you could either extend JFrame, and add components that go inside it in its constructor, or just add the current instance.
public class MWT extends Canvas implements Runnable {
// change the constructor so it doesn't make a new JFrame
// change the constructor so it doesn't add a new instance to the JFrame
// leave the rest unchanged
}
public class ThreadedGraphicsDemo extends JFrame {
private MWT mwt;
public ThreadedGraphicsDemo(MWT mwt) {
this.mwt = mwt;
add(mwt);
// set exit behavior, size, pack, visible etc
}
}
public class Demo {
public static void main(String[] args) {
MWT mwt = new MWT();
ThreadedGraphicsDemo tgd = new tgd(mwt);
}
}
This approach will allow you to easily change the GUI, and behavior in the future.
The quick fix:
instead of add(new MWT()), change it to add(this) to add the instance of MWT that you've instantiated
Well, I tracked down the source of your infinitely spawning windows. You're instantiating the object you're constructing in constructor.
frame.add(new MWT());
The thing with this is that, since the object isn't completely done constructing your instance, it's going to still go off and create an instance of that, which leads to a lot of calls to the MWT object.
If you want to add the current instance of the MWT object you're constructing, you can use this instead:
frame.add(this);
I want to read a file to get some points and then draw these points on an image. Currently, I am able to draw values on the image, but the file is read three times and the rectangles are drawn three times. I don't know where is the problem. Below is the code. The Read() function works fine seperately so I didn't include it in the code.
P.S: I am beginner in JAVA and don't know much about JFrame and Jcomponent.
public class LoadImageApp extends JComponent {
BufferedImage img;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
Read(g);// This is the function in which I read a file.
}
public LoadImageApp() {
try {
img = ImageIO.read(this.getClass().getResource("/New York.jpg"));
} catch (IOException e) {
}
}
public Dimension getPreferredSize() {
if (img == null) {
return new Dimension(100,100);
} else {
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Load Image Sample");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
LoadImageApp img = new LoadImageApp();
f.add(img);
f.pack();
f.setVisible(true);
}
}
Do not, do not, DO NOT read from a file from within any painting method such as paintComponent(...). :)
That method should be for painting only. The more you slow it down, the less responsive your GUI will seem.
You cannot control how many times the method gets called, since it is not under direct control by you, the programmer.
You can't even control fully if the paintComponent method gets called, since the JVM might decide that too many requests for redraw are being stacked up, and it may not honor all of them.
Instead
read in the data once in a constructor or something similar.
I would create a read method that stores my points in an ArrayList<Point>, and then inside of the paintComponent method, iterate through that ArrayList using a for loop and draw them.
If the points don't change during your program's run, you could even draw them directly on to the BufferedImage by getting its Graphics context and using that to paint the points on to the image, and then show the new BufferedImage in your paintComponent method.
Other suggestions:
That empty catch block where you read your image is a dangerous thing to do. It's the coding equivalent of driving a motorcycle with your eyes closed. At least print out a stacktrace.
The WindowListener is not needed. Instead simply set your JFrame's defaultCloseOperation to JFrame.EXIT_ON_CLOSE: f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I would like to write a program in java...
I want to set the shape of the window(a JFrame) to a set of PNG Images(with a transparent background).
(Actually, I would like to make the window change its shape continual, and it look like an animation!)
And, I read images from files,save them to a array, then, I use class GeneralPath to get the area of my animated character(in png images), save it to areaArray.
After all things are done, I start the paint thread. It works well...But sometimes the window would flash(ah...I mean a flicker happened, but the background color I saw when flashing is transparent, I could saw my desktop wallpaper!).
I don't want to see the flicker/flash again, would someone help me? Thanks!
P.S. : Sorry for my poor English!
public class JCustomFrame extends JFrame implements Runnable
{
private final int max_frame=18; //Here is the max numbers of my png images
private BufferedImage[] BufImageArray; //The array to save all the png images
private BufferedImage nowImage; //Save the image to be drawn in this turn
private int counter; //Indicate which png image to be drawn
private Area[] areaArray; //Save the shapes of the animated character in each png image
public void run()// a thread function to paint the frame continual
{
while(true){
if(counter==max_frame)counter=0;
nowImage=BufImageArray[counter];
setShape(areaArray[counter]);
repaint();
try{
Thread.sleep(100);
}catch(InterruptedException e){
System.out.println("Thread.sleep error!");
}
counter++;
}
}
public JCustomFrame()
{
super();
setUndecorated(true);
setBackground(new Color(0,0,0,0));
counter= 0;
//...some codes here
new Thread(this).start();
}
public void paint(Graphics graphic)
{
graphic.drawImage(nowImage,0,0,this);
}
}
Here is a sample code to run the program:
import javax.swing.*;
public class MainFrame
{
public static void main(String[] args)
{
JCustomFrame myFrame = new JCustomFrame();
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(300,400);
myFrame.setVisible(true);
return ;
}
}
I modified 2 lines above, the "png file name" and the "max_frame" to apply the new image files.
I found that if I put the same program on Windows rather than my OpenSuse, it works very well(without the flicker), here I upload all the pack of my source(include the image file).
Here my code is.
Thanks again.
==================================================================================
Thanks Andrew Thompson for suggestions.
This time, I try to delete the codes unrelated to the problem, and paste a gif to show the situation. The codes above isn't runnable, but the source code in the link works well.
P.S. The flicker/flash happened in random frame, isn't completely the same as the gif shows.
('cause I could only add a transparent panel in my gif image at a fixed sequence)
Thanks!!