Intellij IDEA threading issue - java

I have a problem with IDEA 2016.2.2
I wrote a threading demo with flying ball
import javax.swing.*;
import java.awt.*;
public class Ball extends JFrame implements Runnable{
private DrawPanel drawPanel = new DrawPanel();
private int b_x; // ball's x
private int b_y; // ball's y
private int b_d; // ball's diameter
private Thread thread = null;
private JButton button;
private boolean flag = false;
private Ball(){
initGUI();
b_x = b_y = b_d = 50;
thread = new Thread(this);
thread.start();
}
private void initGUI(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Ball Thread Demo");
this.setSize(500, 500);
this.setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
this.add(drawPanel, BorderLayout.CENTER);
button = new JButton("Start");
this.add(button, BorderLayout.NORTH);
button.addActionListener(e -> {
button.setText(flag ? "Start" : "Stop");
flag = !flag;
});
}
#Override
public void run() {
while(true){
//System.out.println();
if(flag) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
b_x += 1;
b_y += 1;
drawPanel.repaint();
}
}
}
class DrawPanel extends JPanel{
#Override
protected void paintBorder(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
#Override
protected void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(new Color(247, 123, 40));
g2d.fillOval(b_x, b_y, b_d, b_d);
}
}
public static void main(String[] args){
new Ball().setVisible(true);
}
}
So, the problem is - if I launch this code via cmd - it works good.
But in IDEA it works only with System.out.println that comment out in run method, another way nothing is happened. Is that an issue of this IDE or I am missing smth important?

b_x, b_y and flag need to be made volatile, since they are updated and read in different threads.

Related

super.paintComponent() isn't working as expected

I'm trying to draw a shape multiple times inside a JPanel to mimic an animation (a moving shape across it). The problem is that the shape is being redrawn and thus appearing on the screen multiple times on different places, when all i pretend is that only one shape is visible at a time when it's being redrawn.
The method super.paintComponent() should be responsible for repainting JPanel's background and thus, only one shape should be visible when the redrawing is being performed.
I have the following code (it has been reduced/simplified for the sake of simplicity and better understanding):
public class Animated_Shape_Test extends JFrame
{
public static void main(String args[]) throws IOException
{
new Animated_Shape_Test();
}
public Animated_Shape_Test() throws IOException
{
this.setSize(500, 500);
this.setPreferredSize(new Dimension(500, 500));
this.setLocation(new Point(430, 150));
this.setTitle("Database Launcher v1.0");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setVisible(true);
DBPanel panel = new DBPanel();
getContentPane().add(panel, BorderLayout.CENTER);
}
}
final class DBPanel extends JPanel implements Runnable
{
int musicShapePosX = 85;
int musicShapePosY = 100;
int SEGMENT_SHAPE_LENGTH = 50;
int SHAPE_HEIGHT = 10;
float SHAPE_SPEED = 7.5f;
CustomShapeButton musicShapeButton = new CustomShapeButton(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
private ArrayList<Shape> shapes = null;
protected DBPanel() throws IOException
{
shapes = new ArrayList();
shapes.add(musicShapeButton);
this.setOpaque(true);
this.setFocusable(true);
startThread();
}
public void startThread()
{
Thread t = new Thread(this);
t.start();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground().darker());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.BLACK);
g2.draw(musicShapeButton);
}
public void delay(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
}
}
#Override
public void run()
{
while (true)
{
delay(35);
animateButtonShapeMusic();
repaint();
}
}
public void animateButtonShapeMusic()
{
if (musicShapePosY < 228)
{
musicShapePosY = (int)(musicShapePosY + SHAPE_SPEED);
musicShapeButton.drawShape(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
}
}
}
I'm getting several shapes being redrawn across the screen (animation).
I expect a single shape being redrawn across the screen (animation).
Thank you in advance.

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.

MouseListener on a drawString() Method

How can I detect if the text ("Resume", "Restart", "Quit") that I drew with a drawString() method is being clicked?
My code so far:
public class Pause {
public Pause() {
}
public void draw(Graphics2D g) {
g.setFont(new Font("Arial", Font.BOLD, 14));
int intValue = Integer.parseInt( "ff5030",16);
g.setColor(new Color(intValue));
g.drawString("Resume", 200, 156);
g.drawString("Restart", 200, 172);
g.drawString("Quit", 200, 188);
}
}
I hope you can help me. Thanks
#aioobe I tried to write it simple as possible. Here the SSCCE:
GameFrame.java
public class GameFrame extends JFrame implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
// dimensions
public static final int WIDTH = 448;
public static final int HEIGHT = 288;
public static final double SCALE = 2.5;
// game thread
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
// image
private BufferedImage image;
private Graphics2D g;
//displays
private Pause pauseDisplay;
public GameFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.pack();
this.setLocationRelativeTo(null);
this.setPreferredSize(new Dimension((int)(WIDTH * SCALE), (int)(HEIGHT * SCALE)));
this.setBounds(100, 100, (int)(WIDTH * SCALE), (int)(HEIGHT * SCALE));
this.setLocationRelativeTo(null);
this.setFocusable(true);
this.requestFocus();
this.setVisible(true);
}
public void addNotify() {
super.addNotify();
if(thread == null) {
thread = new Thread(this);
thread.start();
}
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
}
public void run() {
init();
long start;
long elapsed;
long wait;
// game loop
while(running) {
start = System.nanoTime();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if(wait < 0) wait = 5;
try {
Thread.sleep(wait);
}
catch(Exception e) {
e.printStackTrace();
}
pauseDisplay = new Pause(this);
drawToScreen();
draw();
}
}
private void draw() {
pauseDisplay.draw(g);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, (int)(WIDTH * SCALE), (int)(HEIGHT * SCALE), null);
g2.dispose();
}
public static void main(String[] args) {
GameFrame game = new GameFrame();
}
}
Pause.java
public class Pause implements MouseListener{
private Rectangle2D resumeRect;
private Rectangle2D restartRect;
public Pause(GameFrame GameFrame) {
GameFrame.addMouseListener(this);
}
public void draw(Graphics2D g) {
g.setFont(new Font("Arial", Font.BOLD, 14));
int intValue = Integer.parseInt( "ff5030",16);
g.setColor(new Color(intValue));
g.drawString("Resume", 200, 156);
resumeRect= g.getFontMetrics().getStringBounds("Resume", g);
g.drawString("Restart", 200, 172);
restartRect = g.getFontMetrics().getStringBounds("Restart", g);
g.drawString("Quit", 200, 188);
}
public void mouseClicked(MouseEvent e) {
if (resumeRect.contains(e.getPoint())) {
System.out.println("clicked");
}
System.out.println(resumeRect);
System.out.println(restartRect);
System.out.println(e.getPoint());
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
You would have to remember the position at which you drew the string. You could have one Rectangle2D for each string.
The rectangle of the String can be computed as follows:
Rectangle2D r = g.getFontMetrics().getStringBounds(str, g);
(You need to adjust the rect position according to where you draw the string.)
You would then register a mouse listener that checks click coordinates against these rectangles:
if (resumeRect.contains(mouseEvent.getPoint())) {
...
}
That being said, I'd recommend you to reconsider your GUI code and see if you can't use JLabel or JButton for this purpose.
Regarding your edit:
Your NullPointerException is due to the fact that you can click on the frame before the image is rendered (i.e. before the rectangles have been initialized).
Apart from that you need to do two edits:
You need to take the SCALE into account.
if (resumeRect.contains(e.getPoint().getX() / GameFrame.SCALE,
e.getPoint().getY() / GameFrame.SCALE)) {
and
you need to compensate for the fact that drawString draws the string on the base line, so the rectangle should be lifted up from the base line to the top left corner of the text:
g.drawString("Resume", 200, 156);
resumeRect= g.getFontMetrics().getStringBounds("Resume", g);
// Add this:
resumeRect.setRect(200,
156 - g.getFontMetrics().getAscent(),
resumeRect.getWidth(),
resumeRect.getHeight());
Don't use drawString() for that, put the text in a JLabel instead. Then you can attach the listener to the label which is much easier.
A JLabel also has the advantages that you can use html for formatting and that it allows the layoutmanager to position the text.

JlayeredPane Transparency setOpaque not working

I am creating a simulation type application, I want one background layer and another layer on top for all of the animations. Im currently using JlayeredPanes but i cannot get the background on the top layer to show as transparent so I can see the background, any help is much appreciated, heres the code:
Background layer
public class SimBackground extends JLayeredPane{
private Model theModel;
private SimulationArea simulationArea;
public SimBackground(Model theModel){
this.theModel=theModel;
setBackground(new Color(0, 230, 0));
setOpaque(true);
setPreferredSize(new Dimension(500,500));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(int x=0;x<50;x++){
for(int y=0;y<50;y++){
g.drawRect((x*10), (y*10), 10, 10);
}
}
}
Top layer
public class SimulationArea extends JLayeredPane {
private int SPEED = 100;
private Model theModel;
Timer timer;
public SimulationArea(Model theModel){
this.theModel = theModel;
setPreferredSize(new Dimension(500,500));
setLocation(0,0);
setOpaque(false);
setBackground(new Color(0,0,0,0));
setVisible(true);
//Swing Timer
timer = new Timer(SPEED,new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
revalidate();
}
});
}
private void update() {
theModel.update();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
//test get 1 active object
ArrayList<ActiveObject> activeObjects = theModel.getActiveObjects();
//System.out.println(activeObjects.size());
for(int i=0; i<activeObjects.size(); i++){
ActiveObject activeObject = theModel.getActiveObjects().get(i);
int x = activeObject.getCoordinates().getX();
int y = activeObject.getCoordinates().getY();
int size = activeObject.getSize();
g2d.fillRect (x ,y , size, size);
}
}
Can someone please tell me what i'm missing here?
Don't use a JLayeredPane, but if you do need to use JLayeredPane in the future, you will want to read the tutorial here since as per my comment you're not using them correctly at all. Instead I recommend that you simplify by doing all drawing in a single JPanel, drawing your background into a BufferedImage perhaps in the constructor, and then drawing that image and your sprites within the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SimExample extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color BKGD_COLOR = new Color(0, 230, 0);
private BufferedImage bkgrnd = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
public SimExample() {
Graphics2D g = bkgrnd.createGraphics();
g.setBackground(BKGD_COLOR);
g.clearRect(0, 0, PREF_W, PREF_H);
g.setColor(Color.black);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
g.drawRect((x * 10), (y * 10), 10, 10);
}
}
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (bkgrnd != null) {
g.drawImage(bkgrnd, 0, 0, null);
}
// draw sprites here
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SimExample mainPanel = new SimExample();
JFrame frame = new JFrame("SimExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java drawimage in gameloop

I'm trying to learn to program my first game and I would like to understand correctly every step I make. I'll face double buffering and other things later.
I'm just trying to load an image in the game loop.
I have two classes. The first it's just a jframe calling the start method.
I wonder if there is some ugly code, in here (I think so).
So, why are my images not showing up?
public class myPanel extends JPanel implements Runnable{
//FIELDS
public static int WIDTH = 1024;
public static int HEIGHT = WIDTH / 16 * 9;
private BufferedImage bg;
private BufferedImage charac;
private boolean running;
private Thread t1;
private int startposX = WIDTH / 2;
private int startposY = HEIGHT / 2;
private int cordX = startposX;
private int cordY = startposY;
int speed = 50;
//METHODS
public synchronized void start (){
running = true;
t1 = new Thread (this);
t1.start();
}
public synchronized void stop (){
running = false;
try {
t1.join();
System.out.println("The game stopped");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//INIT
public myPanel(){
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
requestFocus();
addKeyListener(this);
}
//MAIN RUN METHOD
public void run(){
while (running){
load();
System.out.println("The game runs");
repaint();
}
}
//PAINT WITH GRAPHICS METHOD
public void paint (Graphics g){
super.paint(g);
g.drawImage(bg, 0, 0, this);
g.drawImage(charac, 110, 280, this);
}
//LOAD IMAGES IN MEMORY
public void load (){
try {
String path1 = "res/bg.png";
bg = ImageIO.read(new File (path1));
String path2 = "res/charac.png";
charac = ImageIO.read(new File (path2));
} catch (IOException e) {
e.printStackTrace();
}
}
So, I did some testing about paint vs paintcomponent and I just saw that the first draws on top of the jpanel background. Anyway, I can't still see anything changing the lines to
public void run(){
while (running){
load();
System.out.println("The game runs");
}
}
//PAINT WITH GRAPHICS METHOD
public void paintComponent (Graphics g){
super.paint(g);
g.drawImage(bg, 0, 0, null);
g.drawImage(charac, 110, 280, null);
}
//LOAD IMAGES METHOD AS ABOVE
And yes, I've added the panel to the frame, here is the other class
public class Game {
public static void main (String [] args){
JFrame frame = new JFrame();
frame.setIgnoreRepaint(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new myPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
myPanel game = new myPanel();
game.start();
}

Categories

Resources