4 Replies - 2802 Views - Last Post: 21 June 2012 - 03:42 PM Rate Topic: -----

#1 C++ Programmer  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 20
  • View blog
  • Posts: 548
  • Joined: 12-June 08

Java JFrame Double Buffering Problem

Posted 21 June 2012 - 02:06 AM

Hey guys, my friend is making a minesweeper game in Java using JSwing and his code isn't working. The code compiles correctly but the image isn't displayed correctly. Before he had the double buffering implemented, it displayed fine, but with it, it goes off the screen in the left top corner and the correct tile that is being hovered over isn't being displayed correctly. Its high lighting the tile above the cursor. I don't understand how adding double buffering broke the program but it would be very nice if someone could please tell me what is wrong with the code :/

Thank you for any advice.

GamePanel.java
package com.haxifix.minesweeper;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class GamePanel implements Runnable, MouseListener, MouseMotionListener {
	private JPanel canvas;
	private JFrame frame;
	private Thread thread;

	private MineField field;

	private int mouse_x, mouse_y;

	public boolean gameRunning;

	public GamePanel(JFrame frame) {
		this.frame = frame;
		field = new MineField();
		mouse_x = mouse_y = -1;
	}

	private void render() {
		BufferStrategy bs = frame.getBufferStrategy();
		if (bs == null) {
			frame.createBufferStrategy(2);
			canvas.requestFocus();
			return;
		}
		Graphics g = bs.getDrawGraphics();
		g.setColor(Color.BLACK);
		g.clearRect(0, 0, Constants.WIDTH, Constants.HEIGHT);
		g.fillRect(0, 0, Constants.WIDTH, Constants.HEIGHT);
		for (int i = 0; i < Constants.MAX_MINE_Y; i++) {
			for (int j = 0; j < Constants.MAX_MINE_X; j++) {
				field.getTile(j * Constants.MINE_SIZE, i * Constants.MINE_SIZE)
						.render(g);
			}
		}
		g.setColor(Color.WHITE);
		for (int x = 0, y = 0; x <= Constants.WIDTH; x += Constants.MINE_SIZE) {
			g.drawLine(x, 0, x, Constants.HEIGHT);
			g.drawLine(0, y, Constants.WIDTH, y);
			// field.getTile(x, y).render(g);
			y += Constants.MINE_SIZE;
			if (y > Constants.HEIGHT) {
				y = 0;
			}
		}
		g.dispose();
		bs.show();
		Toolkit.getDefaultToolkit().sync();
	}

	public void run() {
		while (gameRunning) {
			try {
				render();
				//Thread.sleep(100);
			} catch (Exception e) {
				e.getStackTrace();
			}
		}
	}

	public void init() {
		gameRunning = true;
		canvas = new JPanel();
		canvas.setPreferredSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setMinimumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setMaximumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setDoubleBuffered(true);
		canvas.setBackground(Color.BLACK);
		canvas.addMouseListener(this);
		canvas.addMouseMotionListener(this);
		this.frame.add(canvas);
		thread = new Thread(this);
		thread.start();
	}

	public void mouseDragged(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
		int old_x = mouse_x;
		int old_y = mouse_y;
		mouse_x = e.getX();
		mouse_y = e.getY();
		if (field.getTile(old_x, old_y) != field.getTile(mouse_x, mouse_y)) {
			field.getTile(old_x, old_y).setHover(false);
			field.getTile(mouse_x, mouse_y).setHover(true);
		}
	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}
}


MineField.java
package com.haxifix.minesweeper;

public class MineField {
	private Tile field[][];

	public MineField() {
		field = new Tile[Constants.MAX_MINE_Y][Constants.MAX_MINE_X];
		for (int i = 0; i < Constants.MAX_MINE_Y; i++) {
			for (int j = 0; j < Constants.MAX_MINE_X; j++) {
				field[i][j] = new Tile(Constants.EMPTY,
						j * Constants.MINE_SIZE, i * Constants.MINE_SIZE);
			}
		}
	}

	public Tile getTile(int x, int y) {
		return field[y / Constants.MINE_SIZE][x / Constants.MINE_SIZE];
	}
}



Tile.java
package com.haxifix.minesweeper;

import java.awt.Color;
import java.awt.Graphics;

public class Tile {
	private int type;
	private boolean hover;
	private boolean clicked;
	private int x, y;

	public Tile(int type, int x, int y) {
		this.type = type;
		hover = false;
		clicked = false;
		this.x = x;
		this.y = y;
	}

	public void render(Graphics g) {
		if (hover) {
			g.setColor(new Color(0, 255, 0, 100));
		} else {
			g.setColor(Color.GREEN);
		}
		switch (type) {
		case Constants.EMPTY:
			g.fillRect(x, y, Constants.MINE_SIZE, Constants.MINE_SIZE);
			break;
		}
	}
	
	public void setHover(boolean hover) {
		this.hover = hover;
	}
}



Any help is appreciated :)

Is This A Good Question/Topic? 0
  • +

Replies To: Java JFrame Double Buffering Problem

#2 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8343
  • View blog
  • Posts: 31,890
  • Joined: 06-March 08

Re: Java JFrame Double Buffering Problem

Posted 21 June 2012 - 03:56 AM

JPanel are double buffered by default you complicate your life a lot for nothing.
You should only implement double buffering if you play a very intensive application like in:
http://www.dreaminco...way-to-repaint/
but let's assume it is an academical exercise.

That does not require Thread, use a swing.Timer instead. Swing is nt thread safe, without having look at your code to deeply but I guess you hang in a thread and your paint() method is never called.
When you do your own repaint you have to setIgnoreRepaint(true) in your Canvas.
Was This Post Helpful? 1
  • +
  • -

#3 C++ Programmer  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 20
  • View blog
  • Posts: 548
  • Joined: 12-June 08

Re: Java JFrame Double Buffering Problem

Posted 21 June 2012 - 02:07 PM

I switched the Thread to a Timer and setIgnoreRepaint to true but it is still drawing the field incorrectly. Here is the new GamePanel.java

package com.haxifix.minesweeper;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GamePanel extends JFrame implements MouseListener,
		MouseMotionListener, ActionListener {
	private static final long serialVersionUID = 1L;
	private JPanel canvas;
	private Timer timer;

	private MineField field;

	private int mouse_x, mouse_y;

	public boolean gameRunning;

	public GamePanel() {
		field = new MineField();
		mouse_x = mouse_y = -1;
	}

	private void render() {
		BufferStrategy bs = getBufferStrategy();
		if (bs == null) {
			createBufferStrategy(2);
			canvas.requestFocus();
			return;
		}
		Graphics g = bs.getDrawGraphics();
		g.setColor(Color.BLACK);
		g.clearRect(0, 0, Constants.WIDTH, Constants.HEIGHT);
		g.fillRect(0, 0, Constants.WIDTH, Constants.HEIGHT);
		for (int i = 0; i < Constants.MAX_MINE_Y; i++) {
			for (int j = 0; j < Constants.MAX_MINE_X; j++) {
				field.getTile(j * Constants.MINE_SIZE, i * Constants.MINE_SIZE)
						.render(g);
			}
		}
		g.setColor(Color.WHITE);
		for (int x = 0, y = 0; x <= Constants.WIDTH; x += Constants.MINE_SIZE) {
			g.drawLine(x, 0, x, Constants.HEIGHT);
			g.drawLine(0, y, Constants.WIDTH, y);
			y += Constants.MINE_SIZE;
			if (y > Constants.HEIGHT) {
				y = 0;
			}
		}
		g.dispose();
		bs.show();
		Toolkit.getDefaultToolkit().sync();
	}

	public void init() {
		gameRunning = true;
		setSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		setPreferredSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		setMinimumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		setMaximumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		setResizable(true);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		canvas = new JPanel();
		canvas.setPreferredSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setMinimumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setMaximumSize(new Dimension(Constants.WIDTH, Constants.HEIGHT));
		canvas.setDoubleBuffered(true);
		canvas.setBackground(Color.BLACK);
		canvas.addMouseListener(this);
		canvas.addMouseMotionListener(this);
		canvas.setIgnoreRepaint(true);
		add(canvas);
		timer = new Timer(16, this);
		timer.start();
	}

	public void mouseDragged(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
		int old_x = mouse_x;
		int old_y = mouse_y;
		mouse_x = e.getX();
		mouse_y = e.getY();
		if (field.getTile(old_x, old_y) != field.getTile(mouse_x, mouse_y)) {
			field.getTile(old_x, old_y).setHover(false);
			field.getTile(mouse_x, mouse_y).setHover(true);
		}
	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void actionPerformed(ActionEvent e) {
		if (gameRunning) {
			render();
		}
	}
}


Also, if I take the double buffering out of the program, then the program flickers a lot. So, I think that the double buffering is needed. Do you see anything else wrong with the program that would cause it to render like this?
Was This Post Helpful? 0
  • +
  • -

#4 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8343
  • View blog
  • Posts: 31,890
  • Joined: 06-March 08

Re: Java JFrame Double Buffering Problem

Posted 21 June 2012 - 03:08 PM

Post you MineField class so we can test it
Was This Post Helpful? 0
  • +
  • -

#5 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8343
  • View blog
  • Posts: 31,890
  • Joined: 06-March 08

Re: Java JFrame Double Buffering Problem

Posted 21 June 2012 - 03:42 PM

And by the way, a Timer of 16 millisecond is useless.
The hardware that refresh the screen executes every 16.6 milliseconds, so a Timer that calls back at less than 18-20 millis will simply draw for nothing

Ok get MineField and Tile from a previous post, if they haven't changed.
Still need Constant

Also we are playing with milliseconds here and each of them is important
In Title not very good idea to

g.setColor(new Color(0, 255, 0, 100));

create that Color only once, probably as a static variable shared by all instance
No need to create a new Color object every time tile.render() is called :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1