Java Canvas repaint() is flickering - java

So I finally got a Canvas to work the way I want it but it flickers constantly, repaint() is run 20 times a second and the flicking does lessen when I make it run 10 times a second.
package pd.data;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import pd.areas.MainMenu;
#SuppressWarnings("serial")
public class Main extends JFrame implements Runnable {
private JPanel contentPane = new JPanel();
private Thread gameThread = new Thread(this);
public boolean running = false;
#SuppressWarnings("unused")
private int current = PDU.PD_MAIN_MENU;
private MainMenu mainmenu;
public Main() {main.setTitle("PD");
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setLocation(SPU.screenWidth / 2 - SPU.windowSize.width / 2,
SPU.screenHeight / 2 - SPU.windowSize.height / 2);
main.setResizable(false);
main.setVisible(true);
contentPane.setLayout(new BorderLayout(0, 0));
contentPane.setPreferredSize(SPU.windowSize);
main.setContentPane(contentPane);
main.pack();
mainmenu = new MainMenu();
contentPane.add(mainmenu, BorderLayout.CENTER);
this.gameThread.start();
}
#Override
public void run() {
running = true;
while (running) {
{
mainmenu.repaint();
}
try {
Thread.sleep(SPU.TSU);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Main();
}
}
And below is my MainMenu class:
package pd.areas;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
#SuppressWarnings("serial")
public class MainMenu extends Canvas{
BufferedImage img = null;
public MainMenu() {
this.setBackground(Color.BLACK);
}
public void paint(Graphics graphics){
try {
img = ImageIO.read(this.getClass().getResource(
"/image.png"));
} catch (IOException e1) {
e1.printStackTrace();
}
graphics.drawImage(img, this.getWidth() / 2 - img.getWidth()/2, 50, null);
}
}
Although the flicker is actually a nice effect, it's going to effect the whole canvas and not just the image I'm guessing, how can I fix the flicker?

Don't use java.awt.Canvas. Use a JPanel instead.
Draw in the JPanel's paintComponent method.
Don't forget to call your super's painting method which for paintComponent would be super.paintComponent(graphics)
Never try to read in an image from within any painting method. That will slow down painting and make your program seem unresponsive. Why keep reading in the same image over and over again anyway? Read it in once and save it to a variable.

Though this thread was opened 5 years ago, it's still going to be an issue for anyone new to Java SE.
I had the same problem with Canvas myself, but wasn't convinced enough to switch to javax components because I recalled a VLC project called JVLC which used Canvas to render videos flawlessly (granted jvlc uses some native code).
Tip 1: perhaps it's better to try JPanel instead.
Tip 2: in gaming systems, it's better to use a game engine (it'll save you lots of time).
Tip 3: in gaming systems, implement a fps mechanism rather than calling repaint() on every change.
Tip 4: if you have to call more than 10 lines of code in your paint() implementation you're going to slow it down. It's better to draw to a BufferedImage for every graphical change you need to make to your app, then have the paint() implementation itself draw just the image itself. This should play nicely with an fps mechanism and will reduce the chances of any flickering.

Related

paint() can't draw gif but png works fine?

I'm using a JLabel in an attempt to draw an animated gif image onto it. I can use the constructor new JLabel(new ImageIcon(FML.class.getResource("giphy.gif"))); and that will work just fine however when I go override the paint method it just doesn't seem to want to draw it, at all. The image isn't still, it's not there! I should mention that both methods shown below work perfectly fine with a PNG but not a GIF. Am I missing something or is this a java bug?
(Using java 1.8)
Edit: I've been looking around and it seems that I'm not completely off point on what I need to be doing but I'm missing something. I've seen many posts Like this one but that doesn't seem to be working in this case.
I should note that there's literally nothing else going on in the class, it's a simple JPanel.
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FML {
public static void main(String[] args) {
new FML();
}
public FML() {
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) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageIcon animatedGif;
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton(new ImageIcon(FML.class.getResource("FmDxW.png")));
btn.setSize(50, 50);
btn.setRolloverEnabled(true);
animatedGif = new ImageIcon(FML.class.getResource("giphy.gif"));
btn.setRolloverIcon(animatedGif);
add(btn);
btn.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
animatedGif.getImage().flush();
}
});
//I need this
final ImageIcon image = new ImageIcon(FML.class.getResource("giphy.gif"));
//To render over this
final ImageIcon image2 = new ImageIcon(FML.class.getResource("fmDxW.png"));
//I'm not understanding why I can add the gif into the constructor but the paint method fails.
JLabel label = new JLabel(image) {
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image2.getImage(), 64, 64, this);
}
};
//setSize because I want to be 100% sure that it's loading the correct size.
//Removing it doesn't affect the problem at hand.
label.setSize(64, 64);
add(label);
}
}
}
g.drawImage(image2.getImage(), 64, 64, this);
Assuming the size of your image is 64, why are you trying to draw the second image outside the bounds of the label? When I change the location to (0, 0) the gif paints fine for me (but I'm not using an animated gif).
both methods shown below work perfectly fine with a PNG but not a GIF.
I don't see how for the reason I gave above. In any case, did you try it with a normal gif?
This is a reason why you should not be trying to manage the painting yourself since now you need to worry about location and hardcoding a location is not a good practice. Let your layout manager do this for you.
Again, why are you doing this. Why are you trying to override paint method to draw a second image?
Instead you should be doing something like:
Drawing both images in the paintComponent() method
Use a panel with an OverlayLayout, Then you can stack the two labels on top of one another.
You can even set the layout manager of the layout to something like a GridBagLayout and then when you add a JLabel to the label it will automatically be centered.
//setSize because I want to be 100% sure that it's loading the correct size.
You said you know how layout managers work. Well if you do then you know that this statement will do nothing since the layout manager will override any value you set, so using code like this wrong and shows a basic lack of understanding and should not be included in an MCVE since the point of the MCVE` is to simplify the problem as much as possible.

Java Applet, make the background transparent

I watched a tutorial on YouTube on how to display an image in Java, and he used something called "Applet" and "Graphics" to display it, I've got it to work, and I am happy with it. Now what I was planning to make is a chrome logo in the center of my screen, transparent with no background, and then chrome opens. I've called the class CustomChrome cus you know. Custom and stuff. I just want a cool opening whenever I start chrome.
Here is the current code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
public class CustomChrome extends Applet {
/**
*
*/
private static final long serialVersionUID = 1L;
private Image logo = null;
public void paint(Graphics g) {
this.setSize(960, 540);
if (logo == null)
logo = getImage("/chromelgo.png");
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(logo, 0, 0, 960, 540, this);
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL imageURL = CustomChrome.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(imageURL);
} catch (Exception e) {
System.out.println("An error occured - " + e.getMessage());
}
return tempImage;
}
}
What I want to do, however, is the make the background + the window to vanish, Once that's was done I will set the image and window size to 1920x1080. How do I go forward on making the window behind the image disappear? I've heard something about implementing ActionListener, but still I ain't sure what to do.
Keep in mind! I have no experience with java so sorry for upsetting you if you try to help me :P
Okay, let's start with the really obvious issue, applets are effectively deprecated and you should stop using them, see Java Plugin support deprecated and Moving to a Plugin-Free Web for more details.
paintXxx is for painting, you should never change the state of a component from within a paint method (and you should not be calling setSize in an applet anyway). See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works and how you can make use of it
As a general piece of advice, I'd recommend ImageIO.read over Toolkit#getImage or ImageIcon for loading images, apart from throwing an Exception when the image can't be read (instead of failing silently), it's also a blocking call, meaning that when it returns, the image is fully loaded.
See Reading/Loading an Image for more details
A word of warning - What you're trying to do is not difficult per se, but it's involved and requires a certain amount of knowledge about how the API works.
Now what I was planning to make is a chrome logo in the center of my screen, transparent with no background, and then chrome opens.
Okay, well, this was never going to work with applets, as applets are intended to be displayed inside a browser, so you can't control the window, instead, you need something like a JFrame, see How to Make Frames (Main Windows)
What I want to do, however, is the make the background + the window to vanish, Once that's was done I will set the image and window size to 1920x1080. How do I go forward on making the window behind the image disappear?
Now, this is where the real fun begins. You're going to want to start by having a look at How to Create Translucent and Shaped Windows. This will allow you control the opacity of the frame, making it disappear, but allowing the content to remain, there are some tricks you need to do to pull it off, but that's the basic idea
So, this example will make a transparent window and display and image centered within it.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
BufferedImage img = ImageIO.read(getClass().getResource("/Chrome.png"));
ImageIcon icon= new ImageIcon(img);
JLabel label = new JLabel(icon);
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
In this is example, I make use of a JLabel to display the image, in most cases, it's all you really need, see How to Use Labels for more details.
What I want to do, however, is the make the background + the window to vanish
Well, it just comes down to what you mean by vanish. You could just all dispose or setVisible on the window, which would close it, all you could use some animation to make it fade away ... and because I like animation...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
BufferedImage img = ImageIO.read(getClass().getResource("/Chrome.png"));
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
float opacity = 1.0f;
float delta = 0.05f;
#Override
public void actionPerformed(ActionEvent e) {
opacity -= delta;
if (opacity < 0.0f) {
opacity = 0.0f;
((Timer)(e.getSource())).stop();
frame.dispose();
}
frame.setOpacity(opacity);
}
});
timer.setInitialDelay(2000);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
Okay, there is a lot going on here, you'll want to have a read through Concurrency in Swing and How to use Swing Timers for more details, needless to say, it's a little complicated to get started with.
Basically, all this does is, waits 2 seconds and then every 40 milliseconds, decreases the frames opacity by a factor or 0.05 till it reaches 0 and it then disposes of the window.
Now, I might use a mixture of these techniques, for example, I might show the logo frame (maybe set to display on top), I would then show the main frame and then trigger the logo frame to fade out. This could be done from a controller class to simplify the code, but, that's up to you.
A would also suggest having a look at Creating a GUI With JFC/Swing

Cannot put image in Frame

I am a beginner programmer trying to create a Pacman game using Java eclipse. I am at the beginning of the process and I'm simply trying to get my main "Princess Pacman" character on the JFrame screen, but, I have this Override error popping up. I have also tried it with out override but it doesn't seem to be working for me that way either.
Here is my code:
import java.awt.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.awt.event.KeyEvent;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Pacman extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static void main(String args[]){
Pacman gui = new Pacman();
gui.setVisible(true);
}
BufferedImage princess = null;
public Pacman(){
super("Princess Pacman");
//set size of playing space
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try{
princess =ImageIO.read(new File("images/Elsa.jpeg"));
}
catch (IOException e){
System.out.println("image not found");
}
}
#Override
public void draw(Graphics2D g){
g.drawImage(princess.getScaledInstance(100, 100, Image.SCALE_DEFAULT), 0, 0, this);
}
}
draw is not a method defined by JFrame or any of its parent classes, therefore it can't be override
draw is never called by anything that actually paints
You should avoid painting directly to top level containers, there's just to many things been painted onto it.
You can use a JLabel, but there are issues with this. Instead, create a custom class extending from JPanel and override its paintComponent method, making sure you call super.paintComponent before you render the image
Take a closer look at Painting in AWT and Swing, Performing Custom Painting and this for example
You're trying to override a method that does not exist in the JFrame class. Remove the override annotation.

I am trying to set a background image in Eclipse using Java

I am trying to set a background image in Eclipse using Java and I think that I have most of it done.
I am trying to make a 2D game and I want to add a background image to my menuJFrame which you will see below.
I have this code already:
This is my main class JFrames:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class JFrames extends JPanel implements ActionListener {
JFrame menuJFrame,howToPlayJFrame, level1JFrame;
JPanel menuJPanel,howToPlayJPanel;
JButton howToPlayButton,backToMainMenuButton,startGameButton, quitProgramButton;
JLabel howToPlayLabel;
public static void main(String [] args){
JFrames jframes = new JFrames();
}
public JFrames(){
//menuJFrame
menuJFrame = new JFrame("SquareRun/Menu");
menuJFrame.setVisible(true);
menuJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
menuJFrame.setSize(800, 600);
//menuJPanel
menuJPanel = new JPanel();
menuJFrame.add(menuJPanel);
howToPlayButton = new JButton("How To Play");
menuJPanel.add(howToPlayButton);
howToPlayButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == howToPlayButton){
howToPlayJFrame.setVisible(true);
}
}});
startGameButton = new JButton("Start Game");
menuJPanel.add(startGameButton);
startGameButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == startGameButton)
level1JFrame.setVisible(true);
menuJFrame.setVisible(false);
}});
quitProgramButton = new JButton("Quit Game");
menuJPanel.add(quitProgramButton);
quitProgramButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == quitProgramButton){
menuJFrame.dispose();
}
}});
//howToPlayJFrame
howToPlayJFrame = new JFrame("SquareRun/HowToPlay");
howToPlayJFrame.setVisible(false);
howToPlayJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
howToPlayJFrame.setSize(600, 100);
//howToPlayJPanel
howToPlayJPanel = new JPanel();
howToPlayJFrame.add(howToPlayJPanel);
howToPlayLabel = new JLabel("Use the arrow keys to move, Up= jump, Down= down, Right= right, Left= left");
howToPlayJPanel.add(howToPlayLabel);
backToMainMenuButton = new JButton("Close Window");
howToPlayJPanel.add(backToMainMenuButton);
backToMainMenuButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == backToMainMenuButton){
howToPlayJFrame.setVisible(false);
howToPlayJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}}});
//level1JFrame
level1JFrame = new JFrame("Level 1");
level1JFrame.setVisible(false);
level1JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
level1JFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
public void actionPerformed(ActionEvent e) {
}
public Object getCurrentLevel() {
return null;
}
}
This is my background class:
import java.awt.Image;
import javax.swing.ImageIcon;
public class Background extends JFrames {
private JFrames game;
private Image image;
public Background(JFrames game){
this.game = game;
image = (new ImageIcon("Image001.png")).getImage();
}
}
You can get an image using this code
image = (new ImageIcon(this.getClass().getResource("Image001.png"))).getImage();
assumed the file with an image is in the same folder as this class.
Don't create classes starting with J, it's just confusing, especially when there is a JFrame class and you've created a class called JFrames which extends from JPanel...now I'm just confused...
The first problem you're having is the fact that you don't actually use or add your image to anything within your Background class...
The basic solution to your question would be to use a JLabel as the background component, supply it with a layout manager and add your components to it.
public class Background extends JLabel {
public Background() {
setIcon(new ImageIcon("Image001.png")));
// Don't forget to set the layout...
}
}
Then you would just simply set the layout manager to your needs and add the components to it.
The problem with this is, it won't resize the image when the component is resized. To achieve this, you will need to provide a means by which you can take control over the painting of the image.
This will require you to extend you Background class from something like JPanel and override it's paintComponent method, painting the image as you see fit.
Take a look Performing Custom Painting for more details.
This will require to provide some kind of scaling operation to the image. While there are a number of ways to scale an image in Java, there are a number of issues you need to be aware of. Take a look at The Perils of Image.getScaledInstance()
This raises a bunch of new questions, to you want to scale them and preserve the aspect ratio? If so, do you want to fit the image to available area or fill it (so it will always cover the available space)?
Take a look at Java: maintaining aspect ratio of JPanel background image for more details.
I'd also, strongly, recommend that you take a look at The Use of Multiple JFrames: Good or Bad Practice? and http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html which will help you generate a less confusing user experience, IMHO.
You should also take a look at Reading/Loading an Image as an alternative to ImageIcon, as it has the capacity to read more file formats, but will also throw an IOException when it can't read the image, which can be very helpful in diagnosing missing image issues.

repaint function not working ..

i have a problem with the repaint function
when i compile, the error is
pc3#pc3-desktop:~/Desktop$ javac LoadImageApp.java
LoadImageApp.java:17: cannot find symbol
symbol : method repaint(int,int,int,int,int)
location: class java.awt.Graphics
g.repaint(1000,0,0,1440,900)
^
1 error
and this is my code -->
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class LoadImageApp extends Component {
BufferedImage img;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
super.update(g);
g.repaint(1000,0,0,1440,900);
}
public LoadImageApp() {
try{
img = ImageIO.read(new File("screenshot.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 ");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(new LoadImageApp());
f.pack();
f.setVisible(true);
}
}
can anyone tell me what is the problem ? i intend to do a program that is display the image and keep refreshing every 0.1 seconds . the image will be receive from other machine and every 0.1 seconds and the image will be keep override the old image ..
thanks in advance for those who reply .. THANK YOU !!!!!!
I would highly recommend reading the Swing tutorials and understand the methods defined in the Graphics class as well as the Component class. More specifically, what do you expect the statement:
g.repaint(1000, 0, 1440, 900)
to do? If it's repaint one of your components based on some interval, you can do this using a TimerTask. Also from reading the tutorials you'll see why you have a compilation error. The repaint method is not defined on Graphics.
As a side note, don't name your method paint - it's confusing since there is a paint method already defined in Component
I don't actually know where you found that repaint method signature for Graphics since it does not exist.
You should instead call repaint on the component which is the owner of that specified Graphics, which is the LoadImageApp itself.
But first of all you absolutely need to study a little bit better how drawing works with AWT and Swing, take a look here.
In Addition you should use something that schedules your update phase, otherwise your code, as it is, doesn't make any sense. There is nothing that is periodically loading the imagine neither anything that is repainting the frame. I'd suggest a TimerTask like Amir told you.

Categories