1.The window is flashing while repainting. How can I eliminate that? Using the update method doesn't work either.
2. How do I update all the not-up-to-date classes in netbeans? It looks like my netbeans uses some old classes (before jdk 7).
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JWindow;
public class Splash extends JWindow {
private boolean mIsRunning;
private boolean mIsFadingOut;
volatile static boolean s = true;
private int mAngle;
private int mFadeCount;
private int mFadeLimit = 15;
Splash(Frame f) {
super(f);
}
public void startt() {
while (s) {
repaint();
mAngle += 3;
if (mAngle >= 360) {
mAngle = 0;
}
if (mIsFadingOut) {
if (--mFadeCount == 0) {
mIsRunning = false;
}
} else if (mFadeCount < mFadeLimit) {
mFadeCount++;
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Splash.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
// Paint the view.
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g.create();
float fade = (float) mFadeCount / (float) mFadeLimit;
// Gray it out.
Composite urComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f * fade));
g2.fillRect(0, 0, w, h);
g2.setComposite(urComposite);
// Paint the wait indicator.
int s = Math.min(w, h) / 5;
int cx = w / 2;
int cy = h / 2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(
new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.setPaint(Color.white);
g2.rotate(Math.PI * mAngle / 180, cx, cy);
for (int i = 0; i < 12; i++) {
float scale = (11.0f - (float) i) / 11.0f;
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI / 6, cx, cy);
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, scale * fade));
}
g2.dispose();
}
}
public void showSplash(){
final JFrame p = this; //parent
final Rectangle s = this.getBounds(); //parent size
new Thread(){
public void run(){
splash = new Splash(p);
splash.setBounds(s);
splash.setVisible(true);
splash.startt();
}
}.start();
}
}
Don't call Thread.sleep(...) on the EDT but rather, use a Swing Timer like the example shows. Also, you'll want to draw in the paintComponent(...) method of a JPanel that the JWindow holds to use Swing's default double buffering.
The problem comes from the fact that you override the paint method of JWindow. Override the paintComponent() of a JPanel instead, it has double buffering:
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
public class Test extends JFrame {
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JWindow window = new JWindow();
final Splash splash = new Splash();
window.add(splash);
window.setSize(100, 30);
window.setVisible(true);
new Thread() {
#Override
public void run() {
splash.startt();
}
}.start();
}
});
}
public static class Splash extends JPanel {
private boolean mIsRunning;
private boolean mIsFadingOut;
volatile static boolean s = true;
private int mAngle;
private int mFadeCount;
private int mFadeLimit = 30;
Splash() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
// Paint the view.
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g.create();
float fade = (float) mFadeCount / (float) mFadeLimit;
// Gray it out.
Composite urComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f * fade));
g2.fillRect(0, 0, w, h);
g2.setComposite(urComposite);
// Paint the wait indicator.
int s = Math.min(w, h) / 5;
int cx = w / 2;
int cy = h / 2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.setPaint(Color.white);
g2.rotate(Math.PI * mAngle / 180, cx, cy);
for (int i = 0; i < 12; i++) {
float scale = (11.0f - i) / 11.0f;
g2.drawLine(cx + s, cy, cx + s * 2, cy);
g2.rotate(-Math.PI / 6, cx, cy);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade));
}
g2.dispose();
}
public void startt() {
while (s) {
mAngle += 3;
if (mAngle >= 360) {
mAngle = 0;
}
if (mIsFadingOut) {
if (--mFadeCount == 0) {
mIsRunning = false;
}
} else if (mFadeCount < mFadeLimit) {
mFadeCount++;
}
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Splash.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
Related
I am working on an app to control Parrot Ar.Drone 2.0 using Javadrone API and library.
I am able to connect into drone and make it take off/land successfully. There are 2 java files : DroneTestVideo.java, VideoPanel.java.
The DroneTestVideo.java file is responsible for connecting into drone and get data, while VideoPanel.java file serves as set images.
Javadrone API can be download here.
However, I have no idea why I'failing to get live images from drone. It just show me a black screen with the words:
"No video connection"
Here is my code:
DroneTestVideo.java
package dronetest;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.ARDrone.VideoChannel;
import com.codeminders.ardrone.DroneStatusChangeListener;
import com.codeminders.ardrone.NavData;
import com.codeminders.ardrone.NavDataListener;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DroneTestVideo extends javax.swing.JFrame implements DroneStatusChangeListener, NavDataListener{
private static final long CONNECT_TIMEOUT = 10000L;
private ARDrone drone;
private final VideoPanel video = new VideoPanel();
public DroneTestVideo() {
initComponents();
initDrone();
videoPanel.add(video);
takeoff();
}
private void initDrone() {
try{
drone = new ARDrone();
drone.addStatusChangeListener(this);
drone.addStatusChangeListener(new DroneStatusChangeListener() {
public void ready() {
org.apache.log4j.Logger.getLogger(getClass().getName()).debug("updateLoop::ready()");
}
});
System.err.println("Configure");
drone.selectVideoChannel(ARDrone.VideoChannel.HORIZONTAL_ONLY);
drone.setCombinedYawMode(true);
drone.enableAutomaticVideoBitrate();
System.err.println("Connecting to the drone");
drone.connect();
drone.waitForReady(CONNECT_TIMEOUT);
drone.clearEmergencySignal();
System.err.println("Connected to the drone");
} catch (IOException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null,ex);
}
drone.addNavDataListener(this);
video.setDrone(drone);
}
private void takeoff()
{
try {
System.err.println("**********\nTRIM\n**********");
drone.trim();
Thread.sleep(2000);
System.err.println("**********\nTAKEOFF\n**********");
drone.takeOff();
Thread.sleep(7000);
drone.land();
} catch (IOException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(DroneTestVideo.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DroneTestVideo().setVisible(true);
}
});
}
}
VideoPanel.java
package dronetest;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.DroneVideoListener;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class VideoPanel extends javax.swing.JPanel implements DroneVideoListener{
private AtomicReference<BufferedImage> image = new AtomicReference<BufferedImage>();
private AtomicBoolean preserveAspect = new AtomicBoolean(true);
private BufferedImage noConnection = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
public VideoPanel() {
initComponents();
Graphics2D g2d = (Graphics2D) noConnection.getGraphics();
Font f = g2d.getFont().deriveFont(24.0f);
g2d.setFont(f);
g2d.drawString("No video connection", 40, 110);
image.set(noConnection);
}
public void setDrone(ARDrone drone) {
drone.addImageListener(this);
System.err.println("setDrone function here!");
}
public void setPreserveAspect(boolean preserve) {
preserveAspect.set(preserve);
}
public void frameReceived(BufferedImage im) {
image.set(im);
repaint();
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
drawDroneImage(g2d, width, height);
}
private void drawDroneImage(Graphics2D g2d, int width, int height) {
BufferedImage im = image.get();
if (im == null) {
return;
}
int xPos = 0;
int yPos = 0;
if (preserveAspect.get()) {
g2d.setColor(Color.BLACK);
g2d.fill3DRect(0, 0, width, height, false);
float widthUnit = ((float) width / 4.0f);
float heightAspect = (float) height / widthUnit;
float heightUnit = ((float) height / 3.0f);
float widthAspect = (float) width / heightUnit;
if (widthAspect > 4) {
xPos = (int) (width - (heightUnit * 4)) / 2;
width = (int) (heightUnit * 4);
} else if (heightAspect > 3) {
yPos = (int) (height - (widthUnit * 3)) / 2;
height = (int) (widthUnit * 3);
}
}
if (im != null) {
g2d.drawImage(im, xPos, yPos, width, height, null);
}
}
}
You are not updating your screen, so no new calls to drawDroneImage will be called into the VideoPanel.
You should set a loop to refresh the JPanel (call it repaint()).
And more, you need to implement DoubleBuffering Strategies to get a smoother image transaction.
Trying the exercise in lesson2 of the Udacity course. Despite importing the classes (I'm at java.awt.* now, but I also tried java.awt.Color and java.awt.Canvas separately (also need Shape))..
package com.jul.udacity.lesson2;
public class TestRectangle {
public static void main(String[] args) {
// TODO Auto-generated method stub
Rectangle rect1 = new Rectangle(100.0, 100.0, 200.0, 100.0);
rect1.draw();
}
}
And the class is copied from there and java.awt import added. Any help will be great. Thanks!
package com.jul.udacity.lesson2;
//HIDE
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
//import java.awt.Color;
//import java.awt.Shape;
//import java.awt.Canvas;
import java.awt.*;
public class Rectangle implements Shape
{
private Color color = Color.BLACK;
private boolean filled = false;
private double x;
private double y;
private double width;
private double height;
/**
Constructs an empty rectangle.
*/
public Rectangle()
{
x = 0;
y = 0;
width = 0;
height = 0;
}
/**
Constructs a rectangle.
#param x the leftmost x-coordinate
#param y the topmost y-coordinate
#param width the width
#param height the height
*/
public Rectangle(double x, double y, double width, double height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
Gets the leftmost x-position of this rectangle.
#return the leftmost x-position
*/
public int getX()
{
return (int) Math.round(x);
}
/**
Gets the topmost y-position of this rectangle.
#return the topmost y-position
*/
public int getY()
{
return (int) Math.round(y);
}
/**
Gets the width of this rectangle.
#return the width
*/
public int getWidth()
{
return (int) Math.round(width);
}
/**
Gets the height of this rectangle.
#return the height
*/
public int getHeight()
{
return (int) Math.round(height);
}
/**
Moves this rectangle by a given amount.
#param dx the amount by which to move in x-direction
#param dy the amount by which to move in y-direction
*/
public void translate(double dx, double dy)
{
x += dx;
y += dy;
Canvas.getInstance().repaint();
}
/**
Resizes this rectangle both horizontally and vertically.
#param dw the amount by which to resize the width on each side
#param dw the amount by which to resize the height on each side
*/
public void grow(double dw, double dh)
{
width += 2 * dw;
height += 2 * dh;
x -= dw;
y -= dh;
Canvas.getInstance().repaint();
}
/**
Sets the color of this rectangle.
#param newColor the new color
*/
public void setColor(Color newColor)
{
color = newColor;
Canvas.getInstance().repaint();
}
/**
Draws this rectangle.
*/
public void draw()
{
filled = false;
Canvas.getInstance().show(this);
}
/**
Fills this rectangle.
*/
public void fill()
{
filled = true;
Canvas.getInstance().show(this);
}
public String toString()
{
return "Rectangle[x=" + getX() + ",y=" + getY() + ",width=" + getWidth() + ",height=" + getHeight() + "]";
}
public void paintShape(Graphics2D g2)
{
Rectangle2D.Double rect = new Rectangle2D.Double(getX(), getY(),
getWidth(), getHeight());
g2.setColor(new java.awt.Color((int) color.getRed(), (int) color.getGreen(), (int) color.getBlue()));
if (filled)
{
g2.fill(rect);
}
else
{
g2.draw(rect);
}
}
}
You might want to check the lesson directions carefully. java.awt.Canvas has no getInstance() method. You just use new to make a Canvas. So you either didn't read carefully and are using the wrong Canvas, or there's something else going on.
Also the show() methods are deprecated, so I'm leaning towards you are supposed to be using a different Canvas class.
Also, Swing is not thread safe. Read up on how to use Swing objects
markspace is correct: Canvas here is not the class from java.awt - the Udacity instructors are using their own class called Canvas. I suggest grabbing the lesson files and using those. Here's the Canvas class from that Intro To Java Course:
import java.awt.image.BufferedImage;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.RescaleOp;
import java.io.IOException;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Canvas
{
private static Canvas canvas = new Canvas();
private ArrayList<Shape> shapes = new ArrayList<Shape>();
private BufferedImage background;
private JFrame frame;
private CanvasComponent component;
private static final int MIN_SIZE = 100;
private static final int MARGIN = 10;
private static final int LOCATION_OFFSET = 120;
class CanvasComponent extends JComponent
{
public void paintComponent(Graphics g)
{
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(java.awt.Color.BLACK);
if (background != null)
{
g.drawImage(background, 0, 0, null);
}
for (Shape s : new ArrayList<Shape>(shapes))
{
Graphics2D g2 = (Graphics2D) g.create();
s.paintShape(g2);
g2.dispose();
}
}
public Dimension getPreferredSize()
{
int maxx = MIN_SIZE;
int maxy = MIN_SIZE;
if (background != null)
{
maxx = Math.max(maxx, background.getWidth());
maxy = Math.max(maxx, background.getHeight());
}
for (Shape s : shapes)
{
maxx = (int) Math.max(maxx, s.getX() + s.getWidth());
maxy = (int) Math.max(maxy, s.getY() + s.getHeight());
}
return new Dimension(maxx + MARGIN, maxy + MARGIN);
}
}
private Canvas()
{
component = new CanvasComponent();
if (System.getProperty("com.horstmann.codecheck") == null)
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(component);
frame.pack();
frame.setLocation(LOCATION_OFFSET, LOCATION_OFFSET);
frame.setVisible(true);
}
else
{
final String SAVEFILE ="canvas.png";
final Thread currentThread = Thread.currentThread();
Thread watcherThread = new Thread()
{
public void run()
{
try
{
final int DELAY = 10;
while (currentThread.getState() != Thread.State.TERMINATED)
{
Thread.sleep(DELAY);
}
saveToDisk(SAVEFILE);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
};
watcherThread.start();
}
}
public static Canvas getInstance()
{
return canvas;
}
public void show(Shape s)
{
if (!shapes.contains(s))
{
shapes.add(s);
}
repaint();
}
public void repaint()
{
if (frame == null) return;
Dimension dim = component.getPreferredSize();
if (dim.getWidth() > component.getWidth()
|| dim.getHeight() > component.getHeight())
{
frame.pack();
}
else
{
frame.repaint();
}
}
/**
* Pauses so that the user can see the picture before it is transformed.
*/
public void pause()
{
if (frame == null) return;
JOptionPane.showMessageDialog(frame, "Click Ok to continue");
}
/**
* Takes a snapshot of the screen, fades it, and sets it as the background.
*/
public static void snapshot()
{
Dimension dim = getInstance().component.getPreferredSize();
java.awt.Rectangle rect = new java.awt.Rectangle(0, 0, dim.width, dim.height);
BufferedImage image = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, rect.width, rect.height);
g.setColor(java.awt.Color.BLACK);
getInstance().component.paintComponent(g);
float factor = 0.8f;
float base = 255f * (1f - factor);
RescaleOp op = new RescaleOp(factor, base, null);
BufferedImage filteredImage
= new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
op.filter(image, filteredImage);
getInstance().background = filteredImage;
getInstance().component.repaint();
}
public void saveToDisk(String fileName)
{
Dimension dim = component.getPreferredSize();
java.awt.Rectangle rect = new java.awt.Rectangle(0, 0, dim.width, dim.height);
BufferedImage image = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(java.awt.Color.WHITE);
g.fill(rect);
g.setColor(java.awt.Color.BLACK);
component.paintComponent(g);
String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
try
{
ImageIO.write(image, extension, new File(fileName));
}
catch(IOException e)
{
System.err.println("Was unable to save the image to " + fileName);
}
g.dispose();
}
}
I am creating simple animation of ball moving from one side of the screen to the other with different speed. The problem is that with higher speeds of the ball I can see noticeable flickering of the ball, actually it is hard to explain but something like I could see repaints when part of ball is still in previous step.
I have tried number of things including:
native swing animation using first thread/sleep/repain, then moved to timers
switched to javafx canvas/pane inside swing jframe. Tried both transitions and AnimationTimer
tinkering with CreateBufferStrategy, for 1,2,3 - to be honest haven't seen any difference (maybe I was doing something wrong...)
My question how can I improve smoothness and whether what I want to achieve is possible with native java or maybe it is better to use some external libraries ? and if so could you recommend something ?
below shown my example code for 2nd/3rd attempt.
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import javax.swing.JFrame;
public class FXTrackerPanel extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public int crSize = 30;
public double xPos = crSize;
public double yPos = 100;
public int xSize = 100;
public int ySize = 100;
public Circle r;
int dir = 1;
public void updateScreenSize() {
int screen = 0;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
if( screen > -1 && screen < gs.length )
{
xSize = gs[screen].getDisplayMode().getWidth();
ySize = gs[screen].getDisplayMode().getHeight();
}
else if( gs.length > 0 )
{
xSize = gs[0].getDisplayMode().getWidth();
ySize = gs[0].getDisplayMode().getHeight();
}
else
{
throw new RuntimeException( "No Screens Found" );
}
yPos = ySize / 2;
}
private void initFXPanel(JFXPanel fxPanel) {
updateScreenSize();
xPos = crSize;
Group root = new Group();
double speed = 5;
int repeats = Timeline.INDEFINITE;
r = new javafx.scene.shape.Circle(xPos, yPos, crSize / 2, Color.RED);
TranslateTransition tt = new TranslateTransition(Duration.seconds(speed), r);
tt.setFromX(xPos);
tt.setToX(xSize - crSize * 3);
tt.setCycleCount(repeats);
tt.setAutoReverse(true);
tt.setInterpolator(Interpolator.EASE_BOTH);
tt.play();
root.getChildren().add(r);
// new AnimationTimer() {
//
// #Override
// public void handle(long now) {
// double speed = 20;
// try {
// speed = Double.valueOf(TETSimple.mp.speedSinus.getText());
// }
// catch (Exception ex) {
// speed = 20;
// }
// double xMov = (speed * 4 * Math.sin( xPos * Math.PI / xSize ) );
// if (xMov <= 0) {
// xMov = 1;
// }
// if (dir == 1) {
// if (xPos >= xSize - crSize)
// dir = 0;
// xPos += xMov;
// } else {
// if (xPos <= 1)
// dir = 1;
// xPos -= xMov;
// }
//
// r.setTranslateX(xPos);
// }
// }.start();
fxPanel.setScene(new Scene(root));
}
public FXTrackerPanel() {
updateScreenSize();
this.setSize(new Dimension(xSize, ySize));
this.setPreferredSize(new Dimension(xSize, ySize));
this.setVisible(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JFXPanel fxPanel = new JFXPanel();
this.add(fxPanel);
this.createBufferStrategy(3);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFXPanel(fxPanel);
}
});
}
public static void main(String[] args)
{
new FXTrackerPanel();
}
}
And here example for swing code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.lang.Math;
import java.util.Random;
public class TrackerPanel extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
Shape cr;
Color c;
public int crSize = 30;
public double xPos = crSize;
public double yPos = 100;
public double xPosPrev = crSize;
public double yPosPrev = 100;
public int xSize = 100;
public int ySize = 100;
int dir = 1; // left
int timer = 50; // 50 - sins, 1500 - linear
int method = 1; // 1 - jump, 2 - sinus
int timeToChange = 1000;
int passes = 0;
Timer tt;
boolean clickedClose = false;
private int repeats = 0;
// t - timer interval, m - method of ball movement: 1 - jump, 2 - sinus
public TrackerPanel(int t, int m) {
this.setPreferredSize(new Dimension(300, 200));
this.timer = t;
this.method = m;
c = Color.red;
repaint();
this.updateScreenSize();
tt = new Timer(t, null);
tt.addActionListener(this);
tt.start();
}
public void updateScreenSize() {
int screen = TETSimple.suppMonitor;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
if (screen > -1 && screen < gs.length) {
xSize = gs[screen].getDisplayMode().getWidth();
ySize = gs[screen].getDisplayMode().getHeight();
} else if (gs.length > 0) {
xSize = gs[0].getDisplayMode().getWidth();
ySize = gs[0].getDisplayMode().getHeight();
} else {
throw new RuntimeException("No Screens Found");
}
yPos = ySize / 2;
yPosPrev = ySize / 2;
}
public void actionPerformed(ActionEvent arg0) {
if (method == 1)
lineMovement();
else
sinusMovement();
repaint(0, ySize / 2, xSize, crSize);
}
private Double parseText2Int(String literal) {
try {
return Double.valueOf(literal);
} catch (Exception ex) {
ex.printStackTrace();
}
return 10.0;
}
private void checkFinishCondition() {
if (passes + 1 > repeats && repeats != 0) {
if (!clickedClose) {
TETSimple.mp.bStop.doClick();
clickedClose = true;
}
return;
}
}
private void sinusMovement() {
this.updateScreenSize();
this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText()).intValue();
checkFinishCondition();
double speed = parseText2Int(TETSimple.mp.speedSinus.getText());
double xMov = (speed * Math.sin(xPos * Math.PI / xSize));
if (xMov <= 0) {
xMov = 1;
}
if (dir == 1) {
if (xPos >= xSize - crSize)
dir = 0;
xPosPrev = xPos;
xPos += xMov;
} else {
if (xPos <= 1 + crSize) {
dir = 1;
passes++;
}
xPosPrev = xPos;
xPos -= xMov;
}
}
private void lineMovement() {
this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText()).intValue();
checkFinishCondition();
double left = crSize;
double center = xSize / 2 - crSize * 1.5;
double right = xSize - crSize * 2;
Random r = new Random();
if (timeToChange <= 0) {
passes++;
if (xPos == left || xPos == right) {
timeToChange = 300 + r.nextInt(12) * 100;
xPos = center;
} else if (xPos == center) {
timeToChange = 300 + r.nextInt(7) * 100;
if (r.nextBoolean())
xPos = left;
else
xPos = right;
}
} else {
timeToChange -= 100;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setColor(Color.green);
g2d.fill(new Ellipse2D.Double(xPos, yPos, crSize, crSize));
g2d.dispose();
}
}
It's difficult to know exactly what might be going wrong without a runnable example, but I would, where you can, avoid mixing JavaFX and Swing, as they have different rendering mechanisms.
The following is a VERY simple example, which simply increases the speed of the balls been animated by simply changing the amount by which they are moved on each update...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class BouncyBall {
public static void main(String[] args) {
new BouncyBall();
}
public BouncyBall() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ControlPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ControlPane extends JPanel {
private JSlider speed;
private JSlider quanity;
private BallPitPane ballPitPane;
public ControlPane() {
setLayout(new BorderLayout());
ballPitPane = new BallPitPane();
add(ballPitPane);
JPanel controls = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
speed = new JSlider(1, 100, 4);
quanity = new JSlider(1, 100, 1);
controls.add(new JLabel("Speed:"), gbc);
gbc.gridy++;
controls.add(new JLabel("Quanity:"), gbc);
gbc.gridx++;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
controls.add(speed, gbc);
gbc.gridy++;
controls.add(quanity, gbc);
add(controls, BorderLayout.SOUTH);
speed.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ballPitPane.setSpeed(speed.getValue());
}
});
quanity.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ballPitPane.setQuanity(quanity.getValue());
}
});
}
}
public class BallPitPane extends JPanel {
private List<Ball> balls;
private int speed;
public BallPitPane() {
balls = new ArrayList<>(25);
setSpeed(2);
setQuanity(1);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Ball ball : balls) {
ball.update(getWidth(), speed);
}
repaint();
}
});
timer.start();
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void setQuanity(int quanity) {
while (balls.size() > quanity) {
balls.remove(0);
}
while (balls.size() < quanity) {
int radius = 4 + (int) (Math.random() * 48);
Ball ball = new Ball(
randomColor(),
(int) Math.abs(Math.random() * getWidth() - radius),
(int) Math.abs(Math.random() * getHeight() - radius),
radius
);
balls.add(ball);
}
}
protected Color randomColor() {
int red = (int) Math.abs(Math.random() * 255);
int green = (int) Math.abs(Math.random() * 255);
int blue = (int) Math.abs(Math.random() * 255);
return new Color(red, green, blue);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
for (Ball ball : balls) {
ball.paint(g2d);
}
g2d.dispose();
}
public class Ball {
private Color color;
private int x;
private int y;
private int radius;
private int delta;
public Ball(Color color, int x, int y, int radius) {
this.color = color;
this.x = x;
this.y = y;
this.radius = radius;
delta = Math.random() > 0.5 ? 1 : -1;
}
public void update(int width, int speed) {
x += speed * delta;
if (x + radius >= width) {
x = width - radius;
delta *= -1;
} else if (x < 0) {
x = 0;
delta *= -1;
}
}
public void paint(Graphics g) {
g.setColor(color);
g.fillOval(x, y, radius, radius);
}
}
}
}
This example works within the confines of Swing's painting process, if you need more control over the painting process you will need to use a BufferStrategy (to work within Swing)
I think the issue is caused by the rendering of the JFXPanel in AWT: there is some complex stuff happening behind the scenes to synchronize between the two different system threads (the AWT event dispatch thread and the FX Application Thread).
If you can write this as a "pure" JavaFX application (i.e. with no Swing/AWT code), it runs more smoothly:
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
public class FXAnimationTest extends Application {
#Override
public void start(Stage primaryStage) {
Group root = new Group();
double speed = 5;
int repeats = Timeline.INDEFINITE;
Screen screen = Screen.getPrimary();
Rectangle2D screenBounds = screen.getBounds();
double xSize = screenBounds.getWidth();
double ySize = screenBounds.getHeight();
double crSize = 30 ;
double xPos = crSize ;
double yPos = ySize / 2 ;
Circle r = new Circle(xPos, yPos, crSize / 2, Color.RED);
TranslateTransition tt = new TranslateTransition(Duration.seconds(speed), r);
tt.setFromX(xPos);
tt.setToX(xSize - crSize * 3);
tt.setCycleCount(repeats);
tt.setAutoReverse(true);
tt.setInterpolator(Interpolator.EASE_BOTH);
tt.play();
root.getChildren().add(r);
Scene scene = new Scene(root, xSize, ySize);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you have to have JavaFX embedded in a Swing application, and you're using Java 8 (I tested this on 8u20), then there is a system property that runs both UI toolkits on the same thread. I think this is still currently experimental, so use at your own risk, but try
java -Djavafx.embed.singleThread=true FXTrackerPanel
This improves things a bit, but it's still pretty flickery and not as good as the "pure JavaFX" version.
I have a JPictureBox extends from a java.awt.Component see code here http://pastebin.com/SAJc6Sht. But it only works well when there is no image stretching. Especially for the big picture, it slows program dramatically. How to increase drawing speed of JPictureBox for large image?
#Override
public void paint(Graphics g) {
super.paint(g);
int x = 0;
int y = 0;
int w = 0;
int h = 0;
if (image != null) {
switch (sizeMode) {
case AUTO_SIZE:
case NORMAL:
w = image.getWidth();
h = image.getHeight();
break;
case CENTER_IMAGE:
w = image.getWidth();
h = image.getHeight();
x = (getWidth() - w) / 2;
y = (getHeight() - h) / 2;
break;
case STRETCH_IMAGE:
w = getWidth();
h = getHeight();
break;
case ZOOM:
w = (int) Math.round(image.getWidth() * zoomFactor);
h = (int) Math.round(image.getHeight() * zoomFactor);
break;
case FIT_BOTH:
if (image.getWidth() > image.getHeight()) {
w = getWidth();
h = (int) (w / getAR());
if (h > getHeight()) {
h = getHeight();
w = (int) (h * getAR());
}
} else {
h = getHeight();
w = (int) (h * getAR());
if (w > getWidth()) {
w = getWidth();
h = (int) (w / getAR());
}
}
break;
case FIT_WIDTH:
w = getWidth();
h = (int) (w / getAR());
break;
case FIT_HEIGHT:
h = getHeight();
w = (int) (h * getAR());
break;
}
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(image, x, y, w, h, this);
} else if (errorIcon != null) {
w = errorIcon.getIconWidth();
h = errorIcon.getIconHeight();
x = (getWidth() - w) / 2;
y = (getHeight() - h) / 2;
errorIcon.paintIcon(this, g, x, y);
}
}
Basically, you want to off load the scaling of the image to a background thread, scaling is time consuming and you don't want to do within the context of the Event Dispatching Thread.
This then raises a few more issues. You don't want to scale the image until you really have to to and you really only want the latest result.
Instead of trying to scale the image on EVERY change, you can setup a small, single repeat timer which you reset each time you want to make a change. This will consolidate the multiple resize requests down to as few requests as possible. This example uses a javax.swing.Timer set to a short 125 millisecond delay. So it will wait at least 125 milliseconds between requests for a change before actually triggering the update.
Next, it uses a ExecutorService set up with a single thread. This provides us with the means to "attempt" to cancel any pre-existing operations, as we don't want there result and start our latest request.
Next, the actual scaling operation employs a two step scale, first, it tries to do a fast, low quality scale which can be put on the screen quickly and then performs a slower, high quality scale which is updated at some time in the future...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
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 {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Scrollable {
private BufferedImage master;
private Image scaled;
private double zoom = 1d;
private ExecutorService service;
private List<Future> scaleTasks;
private final Timer zoomTimer;
public TestPane() {
scaleTasks = new ArrayList<>(5);
service = Executors.newSingleThreadExecutor();
try {
master = ImageIO.read(new File("Some image some where"));
scaled = master;
} catch (IOException ex) {
ex.printStackTrace();
}
zoomTimer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Update Zoom to " + getZoom());
updateToZoomFactor(getZoom());
}
});
zoomTimer.setRepeats(false);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "plus");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "minus");
am.put("plus", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
double zoom = getZoom() + 0.1;
setZoom(zoom);
}
});
am.put("minus", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
double zoom = getZoom() - 0.1;
setZoom(zoom);
}
});
}
#Override
public Dimension getPreferredSize() {
return scaled == null
? new Dimension(master.getWidth(), master.getHeight())
: new Dimension(scaled.getWidth(this), scaled.getHeight(this));
}
public BufferedImage getMaster() {
return master;
}
public void setZoom(double value) {
if (value < 0.1) {
value = 0.1;
} else if (value > 2) {
value = 2d;
}
if (value != zoom) {
zoom = value;
zoomTimer.restart();
}
}
public double getZoom() {
return zoom;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
}
protected void setScaledResult(final Image image) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
scaled = image;
invalidate();
revalidate();
repaint();
}
});
}
protected void updateToZoomFactor(double zoom) {
Future[] tasks = scaleTasks.toArray(new Future[scaleTasks.size()]);
for (Future task : tasks) {
if (!task.isCancelled()) {
task.cancel(true);
} else {
scaleTasks.remove(task);
}
}
service.submit(new RescaleTask(zoom));
}
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(400, 400);
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
#Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
protected class RescaleTask implements Callable<Image> {
private double zoom;
protected RescaleTask(double zoom) {
this.zoom = zoom;
}
#Override
public Image call() throws Exception {
if (zoom == 1) {
scaled = getMaster();
} else {
int width = (int) (getMaster().getWidth() * zoom);
int height = (int) (getMaster().getHeight() * zoom);
Image scaled = getMaster().getScaledInstance((int) width, (int) height, Image.SCALE_FAST);
if (!Thread.currentThread().isInterrupted()) {
setScaledResult(scaled);
if (zoom < 1) {
scaled = getScaledDownInstance(getMaster(), (int) width, (int) height);
} else {
scaled = getScaledUpInstance(getMaster(), (int) width, (int) height);
}
if (!Thread.currentThread().isInterrupted()) {
setScaledResult(scaled);
} else {
System.out.println("Was interrupted during quality scale");
}
} else {
System.out.println("Was interrupted during fast scale");
}
}
return scaled;
}
protected BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w = img.getWidth();
int h = img.getHeight();
do {
System.out.println(w + "x" + h + " -> " + targetWidth + "x" + targetHeight);
if (w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w = img.getWidth();
int h = img.getHeight();
do {
if (w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
// createCompatibleImage(w, h, type)
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
}
}
nb: This is little over kill, but demonstrates some key ideas
One of the other things that might help is to convert the image to a compatible color model for the GraphicsDevice, for example...
master = ImageIO.read(new File("Some image some where"));
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage compatible = gc.createCompatibleImage(master.getWidth(), master.getHeight(), Transparency.TRANSLUCENT);
Graphics2D g2d = compatiable.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
master = compatible;
I'm trying to make a tiled background for an RPG using 2D arrays of one drawImage. But for some reason, Java automatically puts the background overlapping the player, I try painting the player before the background, but no difference, Code:
Map code:
Tiles[][] t;
public Map()
{
t = new Tiles[640 / 32][480 / 32];
for (int x = 0; x < 640 / 32; x++)
{
for (int y = 0; y < 480 / 32; y++)
{
t[x][y] = new Tiles(x, y, 32, 32, "./res/grass.png");
}
}
}
public void paint(Graphics g)
{
super.paint(g);
for (int x = 0; x < 640 / 32; x++)
{
for (int y = 0; y < 480 / 32; y++)
{
t[x][y].paint(g);
}
}
this.repaint();
}
Paint code(Which is in other class that extends JPanel):
public void paint(Graphics g)
{
super.paint(g);
p.paint(g);
m.paint(g);
this.repaint();
}
Note: The class which the code above is in extends JPanel, so I made aother class called Window that would add it to the JFrame and then in the static void main, I did all the initializing.
It's hard to tell what you're ding wrong without complete code. I can point somethings out though
Looks like you Map is a JPanel also, since you're calling super.paint. You shouldn't need to make Map a JPanel just make it a regular model class with a drawTiles method that you pass the Graphics context to.
Don't explicitly call the paint method from a component class.
Don't call repaint() from inside the paint method.
Override paintComponent instead for a JPanel
Here's an example I came up with, using some of your code principles while fixing the above mentioned
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PaintTiles extends JPanel {
BufferedImage playerImg;
BufferedImage tileImg;
Map map;
Player player;
int playerX, playerY;
public PaintTiles() throws MalformedURLException, IOException {
playerImg = ImageIO.read(new URL("http://th05.deviantart.net/fs71/PRE/f/2013/055/0/d/super_mario_by_tachin-d5w51ob.png"));
tileImg = ImageIO.read(new URL("https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTc0ep9G8CyvdJSpBbn8AFdZDlimas7Hcc6jqiVVxBe4nfWJYQy7A"));
map = new Map(tileImg);
playerX = 250;
playerY = 250;
player = new Player(playerX, playerY, 100, 100, playerImg);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (map != null && player != null) {
map.paintTiles(g);
player.paintPlayer(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
try {
frame.add(new PaintTiles());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(PaintTiles.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
class Map {
Image img;
Tile[][] tiles;
int tileSize = 32;
private static final int SCREEN_W = 640;
private static final int SCREEN_H = 480;
int xInc = SCREEN_W / tileSize;
int yInc = SCREEN_H / tileSize;
public Map(Image img) {
this.img = img;
tiles = new Tile[xInc][yInc];
for (int x = 0; x < xInc; x++) {
for (int y = 0; y < yInc; y++) {
tiles[x][y] = new Tile(x * tileSize, y * tileSize, tileSize, tileSize, img);
}
}
}
public void paintTiles(Graphics g) {
if (tiles != null) {
for (Tile[] tile : tiles) {
for (Tile t : tile) {
t.drawTile(g);
}
}
}
}
}
class Player {
int x, y, w, h;
Image player;
public Player(int x, int y, int w, int h, Image player) {
this.x = x;
this.y = y;
this.h = h;
this.w = w;
this.player = player;
}
public void paintPlayer(Graphics g) {
g.drawImage(player, x, y, w, h, null);
}
}
class Tile {
int x, y, w, h;
Image img;
public Tile(int x, int y, int w, int h, Image img) {
this.x = x;
this.y = y;
this.h = h;
this.w = w;
this.img = img;
}
public void drawTile(Graphics g) {
g.drawImage(img, x, y, w, h, null);
}
}