How do you make the player fall down and hit the ground? - java

How do you make the Player (Graphics) fall down and hit the border of the window? I do not have the script for the physics but my interpretation of how the code might go is:
//class ProgramGUI
import java.awt.*;
public void actionPerformed(ActionEvent ae) {
posX += vlx;
posY += vly;
}
public void paint(Graphics g) {
Graphics2D player = (Graphics2d) g;
player.fillRect(posX, posY, sizeX, sizeY)
}
public void fallDown() {
posY = posY--; //is this correct? [^-^]
}

A bit of an overly simplified example. When you press Space, the object will begin to fall. A small amount of "gravity" is continuously added to the vertical delta till either you hit the bottom of the view or it reaches a terminal velocity.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private double yDelta = 0;
private double gravityDelta = 0.01;
private double terminalVelocity = 4.0;
private boolean isFalling = false;
private Timer timer;
private Rectangle2D player;
public TestPane() {
player = new Rectangle2D.Double(90, 0, 20, 20);
getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "start");
getActionMap().put("start", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if (isFalling) {
return;
}
yDelta = 0;
isFalling = true;
player = new Rectangle2D.Double(90, 0, 20, 20);
}
});
}
protected void doNextUpdate() {
if (isFalling) {
yDelta += gravityDelta;
if (yDelta > terminalVelocity) {
yDelta = terminalVelocity;
}
player.setRect(player.getX(), player.getY() + yDelta, player.getWidth(), player.getHeight());
if (player.getY() + player.getHeight() > getHeight()) {
yDelta = 0;
isFalling = false;
player.setRect(player.getX(), getHeight() - player.getHeight(), player.getWidth(), player.getHeight());
}
}
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
#Override
public void addNotify() {
super.addNotify();
if (timer != null) {
timer.stop();
}
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
doNextUpdate();
}
});
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
if (timer != null) {
timer.stop();
}
timer = null;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fill(player);
g2d.dispose();
}
}
}
Some thing to keep in mind. A positive vertical delta will move you down, a negative one will move you up

Related

How can I make my swing graphics project have a higher FPS(frames per second for anyone who doesn't know what it means)?

I started remaking my graphics engine and i have a problem with repainting the VolatileImage on the JFrame, i added an FPS counter and when it is in full-screen it only gets to around 250 or 280 FPS even though i have the loop in a new thread and I'm only drawing 2 dots on the screen.
Here is the code for the init and render functions in the Window class, might be a bit unorganized:
`
public int render() {
frame.getGraphics().drawImage(vImg, 0, 0, frame.getWidth(), frame.getHeight(), null);
totalFrames++;
if (System.nanoTime() > lastFPScheck + 1000000000) {
lastFPScheck = System.nanoTime();
currentFPS = totalFrames;
totalFrames = 0;
}
if (vImg.validate(gc) == VolatileImage.IMAGE_OK) {
vImg = gc.createCompatibleVolatileImage(frame.getWidth(), frame.getHeight());
}
if (debugging()) {
frame.setTitle(title + "[FPS: " + currentFPS + "]");
}
graphics = (Graphics2D)vImg.getGraphics();
graphics.setColor(bg_color);
graphics.fillRect(0, 0, frame.getWidth(), frame.getHeight());
return currentFPS;
}
public void repaint_buffer() {
frame.getContentPane().getGraphics().drawImage(vImg, 0, 0, canvasWidth, canvasHeight, null);
}
public void init(int width,
int height,
String title,
Color bg_color,
Consumer<Void> onDestroy) {
this.canvasWidth = width;
this.canvasHeight = height;
this.is_open = true;
this.title = title;
this.bg_color = bg_color;
this.frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
onDestroy.accept(null);
}
});
this.frame.addWindowListener(new WindowAdapter() {
public void windowResized(WindowEvent e) {
vImg = gc.createCompatibleVolatileImage(frame.getWidth(), frame.getHeight());
}
});
this.frame.setLayout(null);
this.frame.setSize(canvasWidth, canvasHeight);
this.frame.addKeyListener(keyInput);
this.frame.setResizable(true);
this.frame.setLocation(-7, 0);
this.frame.setTitle(title);
this.frame.setVisible(true);
gc = this.frame.getGraphicsConfiguration();
vImg = gc.createCompatibleVolatileImage(this.frame.getWidth(), this.frame.getHeight());
this.graphics = (Graphics2D) vImg.getGraphics();
}
`
and here is the code from the Main class, the GraphicsManager object only contains the set_pixel function which sets the color and draws a rectangle at the given position with a size of 1x1 pixels:
package obsidian.core;
import obsidian.core.Window;
import java.awt.*;
public class Main {
private static void on_destroy() {
System.exit(0);
}
public static void main(String[] args) {
Window window = new Window();
window.init(Window.get_max_size().width, Window.get_max_size().height, "title", new Color(0, 0, 0), destroy -> on_destroy());
GraphicsManager gm = new GraphicsManager(window);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(window.is_open()) {
window.render();
gm.draw_pixel(0.5, 0.5, new Color(255, 0, 0));
gm.draw_pixel(0, 0, new Color(255, 255, 255));
System.out.println(window.get_current_fps());
}
}
});
t.start();
}
}
I tried removing the VolatileImage and directly drawing on the frame but the filling of the image makes it glitchy but it got to about 2000 FPS and IntelliJ IDEA couldn't keep up. The only solution I could find to make it run faster is removing the VolatileImage and draw directly to the frame. Didn't work ;-;
Can anyone help me with this? Thank you
Swing "passive" painting
This makes use of a Swing Timer
~170fps
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer timer;
private Instant lastTick;
private int fps = 0;
public TestPane() {
}
#Override
public void addNotify() {
super.addNotify();
if (timer != null) {
timer.stop();
}
timer = new Timer(5, new ActionListener() {
private int frameCount = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (lastTick != null) {
Duration duration = Duration.between(lastTick, Instant.now());
if (duration.toMillis() >= 1000) {
lastTick = Instant.now();
fps = frameCount;
frameCount = 0;
} else {
frameCount++;
}
} else {
lastTick = Instant.now();
}
repaint();
}
});
timer.start();
}
#Override
public void removeNotify() {
if (timer != null) {
timer.stop();
}
timer = null;
super.removeNotify();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fillOval(20, 20, 20, 20);
g2d.fillOval(40, 40, 20, 20);
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(fps);
g2d.drawString(text, 10, fm.getAscent());
g2d.dispose();
}
}
}
"Active" painting via a BufferStrategy
~680fps
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicBoolean;
public class Other {
public static void main(String[] args) {
new Other();
}
public Other() {
Frame frame = new Frame();
MainCanvas canvas = new MainCanvas();
frame.setBackground(Color.BLUE);
frame.add(canvas);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public class MainCanvas extends Canvas {
private Thread thread;
private AtomicBoolean running = new AtomicBoolean(false);
private int fps;
public MainCanvas() {
}
#Override
public void addNotify() {
super.addNotify();
createBufferStrategy(3);
start();
}
#Override
public void removeNotify() {
stop();
super.removeNotify();
}
public void start() {
stop();
run();
}
protected void stop() {
if (running.get()) {
running.set(false);
}
thread = null;
}
protected void run() {
stop();
running.set(true);
thread = new Thread(new Runnable() {
private Instant lastTick;
private int frameCount;
#Override
public void run() {
while (running.get()) {
if (lastTick != null) {
Duration duration = Duration.between(lastTick, Instant.now());
if (duration.toMillis() >= 1000) {
lastTick = Instant.now();
fps = frameCount;
frameCount = 0;
} else {
frameCount++;
}
} else {
lastTick = Instant.now();
}
render();
// Comment out these lines and see where it takes you
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
java.util.logging.Logger.getLogger(Other.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
}
}
});
thread.start();
}
protected void render() {
BufferStrategy bs = getBufferStrategy();
while (bs == null) {
bs = getBufferStrategy();
}
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();
g2d.setColor(Color.GREEN);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Render to graphics
// ...
g2d.setColor(Color.RED);
g2d.fillOval(20, 20, 20, 20);
g2d.fillOval(40, 40, 20, 20);
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(fps);
g2d.drawString(text, 10, fm.getAscent());
// Dispose the graphics
g2d.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (bs.contentsRestored());
// Display the buffer
bs.show();
// Repeat the rendering if the drawing buffer was lost
} while (bs.contentsLost());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
Disclaimer
This is by far a "scientific" example and is intended simply as a demonstration between passive and active rendering workflows

Screen Shake like bug on 2D Grid JPanel

I am trying to create a 2d grid on a JPanel with Zoom functionality. The user will draw on the grid then if desired zoom in and out. Image of Grid
When I currently zoom in there is a screen shake like issue/bug when I move the mouse around, which I would like to remove.
The mouse wheel is used to zoom in and out.
Grid to be drawn at certain scale factor:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class DrawExample extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private double zoom = 1d;
private int tranx;
private int trany;
DrawPanel drawPanel;
int snapmousepositionx, snapmousepositiony;//current snap coords
int currentmousepositionx,currentmousepositiony;
public DrawExample() {
drawPanel = new DrawPanel();
JPanel containerPanel = new JPanel();
JFrame frame = new JFrame(); // Instance of a JFrame
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(800, 800);
//drawPanel.setSize(800, 800);
containerPanel.setLayout(new GridBagLayout());
containerPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(1, 0, 1)));
containerPanel.add(drawPanel);
frame.add(new JScrollPane(containerPanel));
drawPanel.addMouseWheelListener(new MouseAdapter() { //add wheel listener to drawPanel
#Override
public void mouseWheelMoved(MouseWheelEvent e) { //when wheel is moved
if (e.getPreciseWheelRotation() < 0) {
zoom += 0.1;
} else {
zoom -= 0.1;
}
if (zoom < 0.01) {
zoom = 0.01;
}
drawPanel.repaint();
}
});
drawPanel.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent me) {
super.mouseMoved(me);
drawPanel.createSnapGrid(me.getPoint().x, me.getPoint().y);
tranx=me.getPoint().x;
trany=me.getPoint().y;
drawPanel.repaint();
}
});
frame.setVisible(true);
}
public class DrawPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
zoom=Math.round(zoom*10.0)/10.0;
AffineTransform at = g2d.getTransform();
at.translate(tranx, trany);
at.scale(zoom, zoom);
at.translate(-tranx, -trany);
g2d.setTransform(at);
g2d.setColor(Color.lightGray);
drawGrid(g2d);
}
public void createSnapGrid(int x, int y) {
currentmousepositionx = x;
currentmousepositiony = y;
int remainderx = currentmousepositionx % 10, remaindery = currentmousepositiony % 10;
if (remainderx<800/2) setSnapX(currentmousepositionx - remainderx) ;
else setSnapX(currentmousepositionx + (10-remainderx));
if (remaindery<800/2) setSnapY(currentmousepositiony - remaindery);
else setSnapY(currentmousepositiony + (10)-remaindery);
}
}
public void drawGrid(Graphics2D g) {
g.setColor(Color.lightGray);
g.clearRect(0, 0, 800, 800);
System.out.println(getHeight());
//grid vertical lines
for (int i= (10);i<800;i+=10) {
g.drawLine(i, 0, i, 800);
}
//grid horizontal lines
for (int j= (10);j<800;j+=10) {
g.drawLine(0, j, 800, j);
}
//show the snapped point
g.setColor(Color.BLACK);
if ( getSnapX()>=0 && getSnapY()>=0 && getSnapX()<=800 && getSnapY()<=800) {
// result =true;
g.drawOval((int) ( getSnapX())-4, (int) (getSnapY()-4), 8, 8);
}
}
public int getSnapX(){
return (this.snapmousepositionx);
}
public int getSnapY(){
return (this.snapmousepositiony);
}
public void setSnapX(int snap){
this.snapmousepositionx=(int) (snap);
}
public void setSnapY(int snap){
this.snapmousepositiony=(int) (snap);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DrawExample();
}
});
}
}

java simple bouncing ball flickers

This is just a simple red ball going up and down and i see it flickering. I already saw few subjects about that but did not find any answer that helped me.
Thank you :)
The Window class with the go method that makes the ball goes up and down.
The panel that also contains the ball positions and that just repaints.
Window.java
import java.awt.Dimension;
import javax.swing.JFrame;
public class Window extends JFrame
{
public static void main(String[] args)
{
new Window();
}
public Panel pan = new Panel();
public Window()
{
this.setSize(600, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setContentPane(pan);
this.setVisible(true);
go();
}
private void go()
{
int vecY = 1;
while (true)
{
if (pan.y <= 100)
{
vecY = 1;
}
else if (pan.y >= 400)
{
vecY = -1;
}
pan.y += vecY;
pan.repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
Panel.java
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Panel extends JPanel
{
public int x = 300;
public int y = 300;
public void paintComponent(Graphics g)
{
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
}
}
There are a number of possible issues. The primary issue is likely to be a thread race condition between your while-loop and the paintComponent method.
Your while-loop is capable of change the state of the y position before the paintComponent has a chance to paint it's state. Painting is done at the leisure of the paint sub system, so calling repaint simply makes a request to the RepaintManager which decides what and when an actual paint cycle might take place, this means that you could be dropping frames.
For most animations in Swing, a Swing Timer is more the capable. It's safe to update the UI from within, as the ActionListener is called within the context of the EDT but won't block the EDT
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Window extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window();
}
});
}
public Panel pan = new Panel();
public Window() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(pan);
pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
go();
}
private void go() {
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pan.updateAnmationState();
}
});
timer.start();
}
public class Panel extends JPanel {
private int x = 300;
private int y = 300;
private int vecY = 1;
public void updateAnmationState() {
if (y <= 100) {
vecY = 1;
} else if (y >= 400) {
vecY = -1;
}
y += vecY;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
}
}
}
This example worked fine for me on MiniMac

java graphics isn't drawing anything

The program draws a bunch of rectangles for a bar graph. I know the bar class works perfectly fine because I've got it working before adding in the graph panel class. I was drawing straight onto the frame instead of the graph panel. I assume its a problem in the way my set visible methods are called as it was pointed out to me before. I tried looking into it but I've had no luck after playing around and reading documentation.
import java.awt.Color;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.concurrent.Semaphore;
#SuppressWarnings("serial")
public class GraphPanel extends JPanel {
private ArrayList<Bar> graphBars;
private int nBars;
public GraphPanel(int nBars, JFrame mainFrame) {
this.setSize(400, 400);
this.graphBars = new ArrayList<Bar>(nBars);
this.nBars = nBars;
this.initBars(mainFrame.getWidth());
for(Bar b: this.graphBars) {
this.add(b);
}
}
private void initBars(int frameW) {
Random random = new Random();
float hue;
Color color;
int barPadding = frameW/this.nBars;
for(int i = 0; i < this.nBars; i++) {
hue = random.nextFloat();
color = Color.getHSBColor(hue, 0.9f, 1.0f);
this.graphBars.add(new Bar(i*barPadding + 30, 350, color));
}
}
public ArrayList<Bar> getBarList() {
return this.graphBars;
}
}
#SuppressWarnings("serial")
public class Bar extends JPanel implements Runnable {
int height = 0;
Color barColor;
Rectangle bar;
private final int WIDTH = 20;
Thread bartender;
private Semaphore s;
public Bar(int x, int y, Color barColor) {
this.barColor= barColor;
this.bar = new Rectangle(x, y, this.WIDTH, this.height);
this.bartender= new Thread(this);
this.s = new Semaphore(1);
}
public boolean setNewHeight(int h) {
try {
this.s.acquire();
this.height = h;
this.s.release();
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
#SuppressWarnings("deprecation")
public void update() {
if (this.bar.height < this.height) {
bar.reshape(this.bar.x, --this.bar.y, this.bar.width, ++this.bar.height);
} else {
bar.reshape(this.bar.x, ++this.bar.y, this.bar.width, --this.bar.height);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(this.barColor);
g2d.fill(this.bar);
}
#SuppressWarnings("deprecation")
public void callBarTender() {
this.bartender.resume();
}
#SuppressWarnings("deprecation")
#Override
public void run() {
System.out.println("sdf");
while(true) {
if (this.bar.height < this.height) {
for(int i = this.bar.height; i<this.height; i++ ) {
try {
update();
repaint();
Thread.sleep(15);
} catch(Exception e) {
System.out.println(e);
}
}
} else if (this.height < this.bar.height) {
for(int i = this.bar.height; i>this.height; i-- ) {
try {
update();
repaint();
Thread.sleep(15);
} catch(Exception e) {
System.out.println(e);
}
}
}
this.bartender.suspend();
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(400, 400);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphPanel gPane = new GraphPanel(3, frame);
frame.add(gPane);
gPane.getBarList().get(0).setVisible(true);
gPane.getBarList().get(1).setVisible(true);
gPane.getBarList().get(2).setVisible(true);
gPane.setVisible(true);
frame.setVisible(true);
gPane.getBarList().get(0).setNewHeight(100);
gPane.getBarList().get(1).setNewHeight(100);
gPane.getBarList().get(2).setNewHeight(100);
gPane.getBarList().get(0).bartender.start();
gPane.getBarList().get(1).bartender.start();
gPane.getBarList().get(2).bartender.start();
}
You should override getPreferredSize of your GraphPanel to ensure that they are laid out correctly
The x/y positions you are passing to the Bar class are irrelevant, as this is causing your Rectangle to paint outside of the visible context of the Bar pane. Painting is done from within the context of the component (0x0 been the top/left corner of the component)
The use of Rectangle or the way you are using it, is actually causing issues. It's impossible to know exactly how big you component will be until it's layed or painted
There is a reason why resume and suspend are deprecated, this could cause no end of "weird" (and wonderful) issues
Take a look at Laying Out Components Within a Container for why you're bars aren't been updated correctly and why the x/y coordinates are pointless
Take a look at How to use Swing Timers for an alternative to your use of Thread
Possibly, something more like...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
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();
frame.setSize(400, 400);
// frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphPanel gPane = new GraphPanel(3, frame);
frame.add(gPane);
gPane.getBarList().get(1).setFill(false);
gPane.getBarList().get(0).start();
gPane.getBarList().get(1).start();
gPane.getBarList().get(2).start();
frame.setVisible(true);
}
});
}
public class GraphPanel extends JPanel {
private ArrayList<Bar> graphBars;
private int nBars;
public GraphPanel(int nBars, JFrame mainFrame) {
this.graphBars = new ArrayList<Bar>(nBars);
this.nBars = nBars;
this.initBars(mainFrame.getWidth());
for (Bar b : this.graphBars) {
this.add(b);
}
}
private void initBars(int frameW) {
Random random = new Random();
float hue;
Color color;
for (int i = 0; i < this.nBars; i++) {
hue = random.nextFloat();
color = Color.getHSBColor(hue, 0.9f, 1.0f);
this.graphBars.add(new Bar(color));
}
}
public ArrayList<Bar> getBarList() {
return this.graphBars;
}
}
#SuppressWarnings("serial")
public class Bar extends JPanel {
private Color barColor;
private boolean fill = true;
private float fillAmount = 0;
private float delta = 0.01f;
private Timer timer;
private Rectangle bar;
public Bar(Color barColor) {
bar = new Rectangle();
setBorder(new LineBorder(Color.RED));
this.barColor = barColor;
timer = new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fillAmount += isFill() ? delta : -delta;
// System.out.println(fillAmount);
if (fillAmount < 0) {
fillAmount = 0;
((Timer) e.getSource()).stop();
} else if (fillAmount > 1.0f) {
fillAmount = 1f;
((Timer) e.getSource()).stop();
}
repaint();
}
});
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
public void setFill(boolean fill) {
this.fill = fill;
if (!timer.isRunning()) {
if (fill && fillAmount == 1) {
fillAmount = 0;
} else if (!fill && fillAmount == 0) {
fillAmount = 1;
}
}
}
public boolean isFill() {
return fill;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 100);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(this.barColor);
int height = Math.round(getHeight() * fillAmount);
bar.setSize(getWidth(), height);
bar.setLocation(0, getHeight() - height);
g2d.fill(bar);
g2d.dispose();
}
}
}

Object issues in Java

I'm attempting to implement the dragging functionality of shapes on a canvas. My Shape class inherits from JPanel.
Absolutely nothing happens when I click on a shape, drag it and let go of the mouse button. It just remains where it was originally. Any ideas?
You need a few basic things:
A field for the shape itself (you already had)
Fields to keep track of the offset of the click within the shape (already had)
A field to keep track of if you're dragging
Overwrite the paintComponent method to paint your shape
A MouseListener and MouseMotionListener added to the Panel (MouseAdapter does both of these)
Here's a basic working example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawTest extends JPanel{
//Shape doesn't have a location field - you'd have to keep track of
//this yourself if you're set on using the shape interface
private Rectangle shape = new Rectangle(100, 100);
// The location within the shape you clicked
private int xOffset = 0;
private int yOffset = 0;
// To indicate dragging is happening
boolean isDragging = false;
public DrawTest(){
MouseAdapter listener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// Starts dragging and calculates offset
if(shape.contains(e.getPoint())){
isDragging = true;
xOffset = e.getPoint().x - shape.x;
yOffset = e.getPoint().y - shape.y;
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Ends dragging
isDragging = false;
}
#Override
public void mouseDragged(MouseEvent e) {
// Moves the shape - doesn't actually need to be a method
// but is because you had it as one
if(isDragging){
moveShape(e);
}
}
private void moveShape(MouseEvent e) {
Point newLocation = e.getPoint();
newLocation.x -= xOffset;
newLocation.y -= yOffset;
shape.setLocation(newLocation);
repaint();
}
};
//Add a mouse mostion listener (for dragging) and regular listener (for clicking)
addMouseListener(listener);
addMouseMotionListener(listener);
}
// So we have a play area to work with
public Dimension getPreferredSize(){
return new Dimension(400,300);
}
//Paints the shape
public void paintComponent(Graphics g){
super.paintComponent(g);
g.clearRect(0,0,getWidth(), getHeight());
g.fillRect(shape.x, shape.y, shape.width, shape.height);
}
public static void main(String[] args)
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Tried a small simple example
Dragging the rectangle will make it move with the cursor it also checks the bounds so the rectangle cannot be dragged off screen:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapeMover {
public ShapeMover() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Shape Mover");
initComponents(frame);
frame.pack();
frame.setVisible(true);
}
public static void main(String s[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShapeMover();
}
});
}
private void initComponents(JFrame frame) {
frame.getContentPane().add(new DragPanel());
}
}
class DragPanel extends JPanel {
Rectangle rect = new Rectangle(0, 0, 100, 50);
int preX, preY;
boolean isFirstTime = true;
Rectangle area;
boolean pressOut = false;
private Dimension dim = new Dimension(400, 300);
public DragPanel() {
setBackground(Color.white);
addMouseMotionListener(new MyMouseAdapter());
addMouseListener(new MyMouseAdapter());
}
#Override
public Dimension getPreferredSize() {
return dim;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (isFirstTime) {
area = new Rectangle(dim);
rect.setLocation(50, 50);
isFirstTime = false;
}
g2d.setColor(Color.black);
g2d.fill(rect);
}
boolean checkRect() {
if (area == null) {
return false;
}
if (area.contains(rect.x, rect.y, 100, 50)) {
return true;
}
int new_x = rect.x;
int new_y = rect.y;
if ((rect.x + 100) > area.getWidth()) {
new_x = (int) area.getWidth() - 99;
}
if (rect.x < 0) {
new_x = -1;
}
if ((rect.y + 50) > area.getHeight()) {
new_y = (int) area.getHeight() - 49;
}
if (rect.y < 0) {
new_y = -1;
}
rect.setLocation(new_x, new_y);
return false;
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
preX = rect.x - e.getX();
preY = rect.y - e.getY();
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
pressOut = true;
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (!pressOut) {
updateLocation(e);
} else {
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
pressOut = false;
}
}
public void updateLocation(MouseEvent e) {
rect.setLocation(preX + e.getX(), preY + e.getY());
checkRect();
repaint();
}
}
}
Reference:
http://www.java2s.com/Code/Java/Event/MoveShapewithmouse.htm

Categories