image is drawn half second later then other paint compontents - java

After I start my applet every component is drawn alright, besides my background image that is drawn with about a half second delay. I deleted my thread thinking it's maybe the cause of my problem, but it's not, so i didn't include it here.... I use Double Buffering, because I would have flickering of my components that are repainted by thread. I tried to provide as little code as possible....
public class balg extends Applet implements Runnable {
private Image i;
private Graphics doubleG;
URL url;
Image city; //background image
public void init(){
setSize(800, 600);
try{
url = getDocumentBase();
}catch(Exception e){
}
city = getImage(url , "multiplen/images/SPACE.png");
}
public void start(){
Thread thread = new Thread(this);
thread.start();
}
public void run(){
// here goes the repiant();
}
public void stop(){
}
public void destroy(){
}
#Override
public void update(Graphics g) {
if(i == null){
i = createImage(this.getSize().width, this.getSize().height);
doubleG = i.getGraphics();
}
doubleG.setColor(getBackground());
doubleG.fillRect(0, 0, this.getSize().width, this.getSize().height);
doubleG.setColor(getForeground());
paint(doubleG);
g.drawImage(i, 0,0, this);
}
public void paint(Graphics g){
g.drawImage(city,(int) 800 , 0 , this); // it's drawn here
String s = "15";
g.setColor(Color.BLACK);
g.drawString(s, getWidth() - 150, 50);
}
}

It takes that much time to read the image, about 100-200 ms.

Related

How to add a JPanel on top of a canvas placing the mouse on the top of a Graphic element?

I am building the test application to improve later. I have a Java Graphic Element drawn on a canvas using a Game Loop (update,render). It is a red ball that changes its color when the mouse is placed on top of it.
I am trying to figure out a method to create a JPanel when the mouse is on top of the ball,to show some sort of "Hidden Information" inside the ball. My original idea is to display a histogram made with JFreeChart API as the "Hiden information, so I believe that if I create this JPanel I can later add the histogram to the JPanel created. Similar to this http://www.bitjuice.com.au/research/#hierarchicalclassificationexample. In the link, whenever you put the mouse on top of the rectangles, you display extra information.
So far I've got this code:
*Window.java * (The JFrame)
public class Window extends JFrame {
JLabel title_label = new JLabel();
public Window(int width, int height, String title, Animation animation){
setTitle(title);
setPreferredSize(new Dimension(width,height));
setMaximumSize(new Dimension(width,height));
setMinimumSize(new Dimension(width,height));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
add(animation);
add(title_label, BorderLayout.SOUTH);
setVisible(true);
animation.start();
}
public void update(){
title_label.setText(Animation.mouseX + " " + Animation.mouseY);
}
}
Animation.java(The game Loop)
public class Animation extends Canvas implements Runnable {
public static final int WIDTH = 1024, HEIGHT = WIDTH/12*9 ;
private Thread thread;
private boolean running = false;
public static int mouseX,mouseY;
public Window window;
Button button = new Button();
public Animation(){
window = new Window(WIDTH, HEIGHT,"Test", this);
addMouseMotionListener(new Handler(window));
addMouseListener(new Handler(window));
}
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000/amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now-lastTime) / ns;
lastTime = now;
while(delta >= 1){
update();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer >1000){
//System.out.println(frames);
timer += 1000;
frames = 0;
}
}
stop();
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
public static int getMouseX(){
return mouseX;
}
public static int getMouseY(){
return mouseY;
}
public static void setMouseX(int x){
mouseX = x;
}
public static void setMouseY(int y){
mouseY = y;
}
private void update(){
window.update();
button.update();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(4);
return;
}
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Graphics g = bs.getDrawGraphics();
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHints(rh);
g2d.setColor(Color.white);
g2d.fillRect(0, 0, WIDTH, HEIGHT);
button.render(g);
g.dispose();
g2d.dispose();
bs.show();
}
public static void main(String args[]){
new Animation();
}
}
Handler.java
public class Handler extends MouseAdapter {
int x,y;
private Window window;
public Handler(Window window){
this.window = window;
}
public void mouseMoved(MouseEvent e){
Animation.setMouseX(e.getX());
Animation.setMouseY(e.getY());
}
}
Button.java
public class Button {
Ellipse2D mask;
boolean mouseIsOn = false;
public Button(){
mask = new Ellipse2D.Double(500,350,50,50);
}
public void update(){
if(mask.contains(Animation.mouseX,Animation.mouseY)){
mouseIsOn = true;
}else
mouseIsOn = false;
}
public void render(Graphics g){
if(mouseIsOn)
g.setColor(Color.green);
else
g.setColor(Color.red);
g.fillOval(500,350, 50, 50);
}
}
I appreciate the help.
Heavy weight and light weight components don't mix. JPanel is a lightweight component and Canvas is heavyweight. Heavyweight components always get drawn on top of lightweight ones.
What you may want to do instead is just draw the mouseover portion directly to your canvas. You can use FontMetrics for drawing Strings if that is what you need.

How to draw an image over another?

So I am working on a project for a class. And I've been struggling with this issue for a while now. The code below is a start screen, and when the enter key is pressed (when atTitle turns to false) I would like it to draw the next image. The problem with that is I can not think of a way for it to draw the next image when it turns to false. I've tried using ifs and whiles. Mainly the problem is that you obviously put another public void paintComponent in an if statement. And I can't carry the Graphics g variable to the KeyPressed method.
I'm stuck.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
AffineTransform at = new AffineTransform();
g2.setTransform(at);
if (atTitle == true) {
g.drawImage(titlescreen, 0, 0, this);
if (start_visible == true) {
g.drawImage(start_symbol, -70, 30, this);
jf.addKeyListener(this);
}
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
//int keyCode = e.getKeyCode();
if (atTitle == true) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
atTitle = false;
System.out.println("It Works.");
}
}
}
you need to call repaint and wait system calls to paint function. you should not keep graphic object and use it in a function is not child function of paint
as a simple canvas component, you can use this one
class Game extends Canvas implements Runnable {
private Thread thread;
public Game(){
thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics g) {
// paint your game
}
public void stop(){
thread = null;
}
#Override
public void run() {
while (thread == Thread.currentThread()){
long ti = System.currentTimeMillis();
repaint();
long ti2 = System.currentTimeMillis();
long waitTime = 60 - (ti2-ti);
if (waitTime > 0){
try {
Thread.sleep(waitTime);
} catch (Exception e){
}
}
}
}
}
If you are using JPanel you should:
panel.setFocusable(true);
panel.requestFocusInWindow();
Referenced here
Also you can call panel.revalidate() and/or panel.repaint() in the key press.
Maybe try to stay away from JPanel and Swing altogether (not suited for gaming, but for forms) and just use the graphics2D functionality with a Window, Frame and Canvas, as suggested in previous comment.

Drawing on BufferedImage in thread

I'm trying to draw on a BufferedImage from a thread, then displaying said image on a canvas.
Everything works fine when I alter the BufferedImage from within the paintComponent-method of the Canvas, but as soon as I try to alter it from a running thread - nothing happens.
In other words; If I copy the Graphics2D-code from the thread to the paintComponent-method, everything works fine.
A snippet of my code (some of the variables/values are temporary):
class DrawThread implements Runnable
{
#Override
public void run()
{
while(true)
{
Graphics2D g2d = canvas.getImage().createGraphics();
g2d.setColor(Color.GREEN);
Rectangle rect2 = new Rectangle(10, 0, 20, 20);
g2d.draw(rect2);
g2d.dispose();
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
class RectangleCanvas extends Canvas
{
public BufferedImage image;
public RectangleCanvas()
{
this.setPreferredSize(new Dimension(280, 280));
image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
}
public synchronized BufferedImage getImage()
{
return this.image;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(getImage(), 0, 0, this);
}
}

how to draw multiple rectangles

so I am trying to make a simple program where you click on the screen and it creates a block that falls and collides with a larger block beneath and sticks to it. Kind of like a simple collision program. The problem is when I create one block it deletes the block previously. I made an array, but it still does this. Do any of you know what Im doing wrong? Im sure its a simple fix.
public class Screen extends JPanel implements Runnable {
public static JLabel statusbar; //displays a status bar showing what mouse movements are taking place
private Image cat; //image of the cat
public int xCoord ; //get the coordinates of the mouse pressed
public int yCoord ;
public int xCreate;
public int yCreate;
public Rectangle Ground;
public Rectangle Block;
public boolean isClicked = false;
public int clickCount = 0;
Rectangle blocks[] = new Rectangle[10];
int blocknum = 0;
public Screen(Frame frame) {
loadPic(); //calls the loadPic method above
Handlerclass handler = new Handlerclass(); //creates a new class to use the mouse motion listener
System.out.println("mouse works!");
addMouseListener(handler);
addMouseMotionListener(handler);
statusbar = new JLabel("default");
add(statusbar);
}
public void run(){ //this is the game run loop
System.out.println("this is running");
try{
} catch(Exception e) {} //exception handling
}
public void loadPic(){ //loads the picture from the other project but its the same pic
cat = new ImageIcon("C:\\Users\\Camtronius\\Documents\\NetBeansProjects\\Moving Block Proj\\src\\MovingBlock\\catIcon1.png").getImage(); //gets the image
System.out.println("Image Loaded!");
}
#Override public void paintComponent(Graphics g){
super.paintComponent(g); //paints the component, the picture, on top
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(cat, xCoord, yCoord, null);
g2d.setColor(Color.BLUE);
Ground = new Rectangle(0,450,550,50);
g2d.fillRect(0,450, 550, 50);
for(Rectangle blocknum : blocks){
if (blocks != null) {
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
}
}
//move();
}
public void move(){
if(yCreate<400){
yCreate+=1;
}else{
}
if(Ground.intersects(blocks[blocknum])){
yCreate=400;
System.out.println("contains!");
}
}
private class Handlerclass implements MouseListener, MouseMotionListener{
public void mouseClicked(MouseEvent event){
}
public void mousePressed(MouseEvent event){
}
public void mouseReleased(MouseEvent event){
if(blocknum<blocks.length){
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
repaint();
}
blocknum=blocknum+1;
}
public void mouseEntered(MouseEvent event){
}
public void mouseExited(MouseEvent event){
}
public void mouseDragged(MouseEvent event){
}
public void mouseMoved(MouseEvent event){
statusbar.setText(String.format("Coordinates are: %d, %d", event.getX(),event.getY()));
xCoord=event.getX();
yCoord=event.getY();
}
}
}
Painting is a destructive process. That is, when a new paint cycle runs, the previous contents of the Graphics context should be cleared...
So, in you paintComponent method you are only painting the last block...
if(isClicked = true){
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
repaint(); // THIS IS A BAD IDEA
}
DO NOT call any method that might cause repaint to be called. This will put you in a potential cycle of death that will consume your CPU.
Instead, you should loop through the blocks array and paint each one...
for (Rectangle block : blocks) {
if (block != null) {
g2d.setColor(Color.RED);
g2d.fill(block);
}
}
And in you mouseReleased method, you should be adding the new rectangles...
public void mouseReleased(MouseEvent event){
blocknum=blocknum+1;
if (blocknum < blocks.length) {
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(xCreate, yCreate, 50, 50);
}
}
I'd suggest you take a look at Custom Painting, Painting in AWT and Swing and Concurrency in Swing for more details

Images in applets

i wrote this code for showing some simple picture on the applet screen, but the picture doesnt show untill i resize the applet window, what can i do to overcome it?
public class Test extends JApplet {
public void init () {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
}
});
}
public void start() {
}
public void createGUI() {
getContentPane().add(new GUIThing(getImage(getCodeBase(), "gladiator.gif")));
}
}
public class GUIThing extends JPanel {
Image image;
public GUIThing(Image i2) {
image=i2;
}
public void paintComponent(Graphics g) {
Graphics2D g2=(Graphics2D) g;
g2.drawImage(image,100,100,100, 100, null);
}
}
Try passing the applet context to the drawImage method, this allows the appet to be notified when the image is loaded and it will repaint itself
g2.drawImage(image,100,100,100, 100, this);
And, if you're really desperate, call invalidate() repaint() in the start method
UPDATE WITH EXAMPLE
This is the code that I used. I had no issue with loading the image:
public class TestApplet extends JApplet {
public void init() {
System.out.println("Init..." + EventQueue.isDispatchThread());
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createGUI();
}
});
}
public void start() {
System.out.println("Start..." + EventQueue.isDispatchThread());
}
public void createGUI() {
URL documentBase = getDocumentBase();
System.out.println(documentBase);
System.out.println(getCodeBase());
// file:.../build/TestApplet.html
// file:.../build/classes/
Image image = getImage(documentBase, "MT-vol-6-STOP-image-Kogumiko-megatokyo-11434773-1559-1852.jpg");
System.out.println("image = " + image);
getContentPane().add(new GUIThing(image));
}
public class GUIThing extends JPanel {
Image image;
public GUIThing(Image i2) {
image = i2;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0, 0, this);
g2.setColor(Color.RED);
g2.drawLine(0, 0, getWidth(), getHeight());
}
}
}
Wow, it's been a long time since I played with applets. I changed your code from using the code base to the document base it seems to have worked. I was loading an image of 1559x1852 pixels with little to no delay (locally)
Double check your applet tag in you HTML file as well. I was using
<APPLET codebase="classes" code="stack/TestApplet.class" width=350 height=200></APPLET>
Through the applet viewer. Note the code base is different from the document base!!
My image was in the same location as the HTML file

Categories

Resources