I, basically, want to make an image a 'map'. Kind of like google maps, but with my own image. Here are a few of the issues I run into:
1.) Image is too large to fit into applet screen (Solution: click and drag to pan?)
2.) I have no clue how to make it so I can zoom in and out.
3.) I'd like to make it so when a person 'hovers' their mouse over a location, a text box shows up telling them about the area, but disappears when not 'hovering'
Here is my current code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class MapRender extends JApplet {
BufferedImage img;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
public MapRender() {
try {
img = ImageIO.read(new File("Mapv1Resize.PNG"));
} catch (IOException e) {
}
}
public Dimension getPreferredSize() {
if (img == null) {
return new Dimension(100,100);
} else {
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Load Image Sample");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(new MapRender());
f.pack();
f.setVisible(true);
}
}
This code is part of a sample provided by another area, I just changed it to an applet.
Note: I understand whoever helps me can't run the program without the picture, but you can substitute any 2k*2k resolution picture for this.
Related
I'm trying to make an overlay for a HTML-based game running in a browser window and created an JFrame which is opaque. I'd like to be able to still play the game whilst having the overlay above the window. I tried some solutions that I've found but those didn't work for me.
I've thought of catching the click-event on my JFrame and "simulating" the click on the game window. But sadly I don't have an idea how thats possible.
My current code is using the JNA libarys to access the position and scale of the window (in my test code Task-Manager).
I'm fine with using another libary or something like that, if it's even possible.
Thats my code so far:
import com.sun.jna.platform.DesktopWindow;
import com.sun.jna.platform.WindowUtils;
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("title");
frame.setUndecorated(true);
frame.setBackground(new Color(255, 69, 0, 100));
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Rectangle rect = null;
while (true) {
for (DesktopWindow desktopWindow : WindowUtils.getAllWindows(true)) {
if (desktopWindow.getTitle().contains("Task-Manager")) {
rect = desktopWindow.getLocAndSize();
frame.setSize(rect.width - 16, rect.height - 8);
frame.setLocation(rect.x + 8, rect.y);
frame.setVisible(true);
Thread.sleep(10);
}
}
}
}
}
A JFrame is a heavyweight component. There is a window in the host OS GUI system to go with it. The host OS GUI directs mouse events to the window. Perhaps using a lightweight component for your overlay and then disabling mouse events on it would be a better solution.
Your idea of catching the click event and "simulating it" on you game window should be fairly easy. If your JFrame event processing code has a reference to your game engine, it can determine the relative position of the windows and tell your game engine the corresponding point at which it should act as if it received a click. I.e. just call the same method of your game engine for click events that it received normally and also for the simulated ones.
An ugly hack (there is noticeable flicker) would be to hide the window and send the click through with the Robot class... like this:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.SwingUtilities;
public class ClickThrough extends Frame implements MouseListener, MouseMotionListener {
private final Robot robot;
private Color bgColor = new Color(0x80808080, true);
private Point dragPoint;
public ClickThrough() throws AWTException {
setAlwaysOnTop(true);
robot = new Robot();
}
public static void main(String[] args) throws AWTException {
ClickThrough w = new ClickThrough();
w.setUndecorated(true);
w.setSize(200, 100);
w.setOpacity(0.7f);
w.addMouseListener(w);
w.addMouseMotionListener(w);
w.setVisible(true);
}
#Override
public void paint(Graphics g) {
int w = getWidth();
int h = getHeight();
g.setColor(Color.GRAY);
g.fillRect(0, 0, w, 16);
g.setColor(bgColor);
g.fillRect(0, 16, w, h-16);
g.setColor(Color.BLACK);
g.drawString("Go ahead, click on me...", 20, 50);
}
private void makeHole(MouseEvent e) {
// Tried making a shape with a hole where the mouse was clicked,... didn't work (macOS).
//setShape(windowWithHoleShape);
setVisible(false);
}
private void repairHole(MouseEvent e) {
//setShape(windowShape);
setVisible(true);
}
#Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
// give it a draggable area at the top
if (p.y < 16) {
dragPoint = p;
return;
}
dragPoint = null;
SwingUtilities.convertPointToScreen(p,this);
makeHole(e);
robot.mouseMove(p.x, p.y);
robot.mousePress(InputEvent.getMaskForButton(e.getButton()));
repairHole(e);
}
#Override public void mouseReleased(MouseEvent e) { }
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override
public void mouseDragged(MouseEvent e) {
if (dragPoint != null) {
Point p = e.getPoint();
SwingUtilities.convertPointToScreen(p, this);
p.translate(-dragPoint.x, -dragPoint.y);
setLocation(p);
}
}
#Override
public void mouseMoved(MouseEvent e) { }
}
I tried to see if I could cut a hole in the window by setting the window Shape, but at least on macOS the hole does not allow the mouse events through.
I should also point out that if you switch your GUI framework to JAvaFX, then you have the option of running your HTML-based game UI in a JavaFX WebView, so you can integrate your game and overlay into a single coherent application. You could specifically make your overlay "mouse transparent". IMO that would be a much better approach than hacking around with the mouse events.
I've made a JFrame with a canvas on it and I want to draw on that canvas. At a later date the canvas will be updating many times a second so I am using a buffer strategy for this. Here is the code:
package mainPackage;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class TickPainter {
//just some presets for a window.
public static JFrame makeWindow(String title, int width, int height) {
JFrame mainWindow = new JFrame();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(width, height);
mainWindow.setVisible(true);
mainWindow.setLocationRelativeTo(null);
mainWindow.setTitle(title);
return mainWindow;
}
public static void main(String[] args) {
JFrame mainWindow = makeWindow("Practice", 800, 600);
Canvas mainCanvas = new Canvas();
mainWindow.add(mainCanvas);
mainCanvas.setSize(mainWindow.getWidth(), mainWindow.getHeight());
mainCanvas.setBackground(Color.white);
mainCanvas.createBufferStrategy(3);
BufferStrategy bufferStrat = mainCanvas.getBufferStrategy();
Graphics g = bufferStrat.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(250, 250, 250, 250);
g.dispose();
bufferStrat.show();
}
}
The program does not draw the black rectangle as intended, I feel like I've missed something really obvious here and I just can't see it. At the moment the program just makes a blank white canvas. I feel like part of the issue is that the buffer is just passing the frame with the rectangle faster than I can see, but there is no frame to load after that so I don't know why it's doing this.
A BufferStrategy has a number of initial requirements which must be meet before it can be rendered to. Also, because of the nature of how it works, you might need to repeat a paint phases a number of times before it's actually accepted by the hardware layer.
I recommend going through the JavaDocs and tutorial, they provide invaluable examples into how you're suppose to use a BufferStrategy
The following example uses a Canvas as the base component and sets up a rendering loop within a custom Thread. It's very basic, but shows the basic concepts you'd need to implement...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestCanvas canvas = new TestCanvas();
JFrame frame = new JFrame();
frame.add(canvas);
frame.setTitle("Test");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
canvas.start();
}
});
}
public class TestCanvas extends Canvas {
private Thread thread;
private AtomicBoolean keepRendering = new AtomicBoolean(true);
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void stop() {
if (thread != null) {
keepRendering.set(false);
try {
thread.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void start() {
if (thread != null) {
stop();
}
keepRendering.set(true);
thread = new Thread(new Runnable() {
#Override
public void run() {
createBufferStrategy(3);
do {
BufferStrategy bs = getBufferStrategy();
while (bs == null) {
System.out.println("get buffer");
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
System.out.println("draw");
Graphics graphics = bs.getDrawGraphics();
// Render to graphics
// ...
graphics.setColor(Color.RED);
graphics.fillRect(0, 0, 100, 100);
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (bs.contentsRestored());
System.out.println("show");
// Display the buffer
bs.show();
// Repeat the rendering if the drawing buffer was lost
} while (bs.contentsLost());
System.out.println("done");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
} while (keepRendering.get());
}
});
thread.start();
}
}
}
Remember, the point of BufferStrategy is to give you full control over the painting process, so it works outside the normal painting process generally implemented by AWT and Swing
"At a later date the canvas will be updating many times a second so I am using a buffer strategy for this" - Before going down the "direct to hardware" solution, I'd consider using a Swing Timer and the normal painting process to see how well it works
I am working on a simple 2D game. Each tick, I want to check an effects queue that will start a thread for a certain effect(fading transitions, audio fade in and out, etc). For example, pressing "Play" on the menu screen will add a "FadeOut" message to this queue, which will be processed and start a thread to draw a black rectangle with an increasing alpha value over my GamePanel.
I'm overriding paintComponent() and sending my Graphics object to my GameStateManager, which passes along the Graphics object to the current states' draw(). I currently don't have an effects state (which maybe I should) to route the paintComponent() graphics object to, but I do pass my gamepanel to my effects thread, where I can use getGraphics() to draw on it. Drawing a rectangle to the GamePanel directly just causes flickering, as the gameloop is still rendering the game.
I found I can draw a black rectangle with increasing alpha to a BufferedImage, set the composite to AlphaComposite.Src (which causes the new draw to replace the old) then draw the BufferedImage over the game panel. The problem is the BufferedImages drawn to the game panel don't get overridden each draw, so the fade out happens really quickly because these black BufferedImages of various alphas just stack on each other.
I wrote this short program to test composite settings and see what is getting overridden. All drawing is done in the draw(), which would be my run() in the effects thread.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ScratchPad extends JPanel implements Runnable
{
private JFrame oFrame = null;
private Thread oGameThread = null;
private Graphics2D oPanelGraphics = null;
private Graphics2D oImageGraphics = null;
private BufferedImage oImage = null;
public static void main(String args[]) throws Exception
{
new ScratchPad();
}
public ScratchPad()
{
createFrame();
initPanel();
addAndShowComponents();
oGameThread = new Thread(this, "Game_Loop");
oGameThread.start();
}
private void addAndShowComponents()
{
oFrame.add(this);
oFrame.setVisible(true);
}
private void initPanel()
{
this.setOpaque(true);
this.setBackground(Color.cyan);
}
private void createFrame()
{
oFrame = new JFrame("Fade");
oFrame.setSize(700, 300);
oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
oFrame.setLocationRelativeTo(null);
}
public void run()
{
oImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
while(true)
{
try
{
draw();
Thread.sleep(100);
}
catch(InterruptedException e)
{
}
}
}
private void draw()
{
oPanelGraphics = (Graphics2D)this.getGraphics();
oImageGraphics = oImage.createGraphics();
oImageGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,90));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.setColor(new Color(0,0,0,60));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 220, 10, null);
oImageGraphics.setColor(new Color(0,0,0,30));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 430, 10, null);
// Drawing this image over location of first image, should overwrite first
// after setting composite to 'Src'
oPanelGraphics.setComposite(AlphaComposite.Src);
oImageGraphics.setColor(new Color(0,0,0,10));
oImageGraphics.fillRect(0, 0, oImage.getWidth(), oImage.getHeight());
oPanelGraphics.drawImage(oImage, 10, 10, null);
oImageGraphics.dispose();
oPanelGraphics.dispose();
}
} // end class
What's interesting is setting the composite on 'oPanelGraphics' causes any alpha to the BufferedImage to go away, resulting in a fully opaque black image being drawn over the image that was previously there. Even setting the color to something other than black doesn't have an effect.
What's also interesting is setting the composite for the BufferedImage to:
oImageGraphics.setComposite(AlphaComposite.SrcIn);
causes nothing to be shown. The Oracle documentation on compositing graphics in Java2D states this for 'SrcIn':
"If pixels in the source and the destination overlap, only the source pixels in the overlapping area are rendered."
So, I would expect this to have the same behavior I get with AlphaComposite.Src.
Maybe someone out there can shed some light on whats going on with these composites, and how I could achieve my desired effect.
There are a number issues with what you "seem" to be trying to do
Don't call getGraphics on a component. This can return null and only returns a snapshot of what was last painted during a Swing paint cycle. Anything you paint to it will be erased on the next paint cycle
You should also never dispose of Graphics context you did not create, doing so could effect other components that are painted by Swing
Painting is compounding, this means that painting to the same Graphics context (or BufferedImage) over and over again, will continue to apply those changes over the top of what was previously painted
You also don't seem to have a concept of how animation should work. Instead of trying to paint your fade effect in a single pass, where the results can't be applied to the screen, you need to apply a phase on each cycle and allow that to be updated to the screen before the next pass runs.
The following is a really basic example of what I'm talking about. It takes a "base" image (this could be the "base" state of the game, but I've used a static image) and the paints effects over the top.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Engine engine;
private Image frame;
public TestPane() {
engine = new Engine();
engine.setEngineListener(new EngineListener() {
#Override
public void updateDidOccur(Image img) {
frame = img;
repaint();
}
});
engine.start();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
engine.addEffect(new FadeOutEffect(Color.BLACK));
}
});
}
#Override
public Dimension getPreferredSize() {
return engine.getSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (frame != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(frame, 0, 0, null);
g2d.dispose();
}
}
}
public interface EngineListener {
public void updateDidOccur(Image img);
}
public class Engine {
// This is the "base" image, without effects
private BufferedImage base;
private Timer timer;
private EngineListener listener;
private List<Effect> effects = new ArrayList<Effect>(25);
public Engine() {
try {
base = ImageIO.read(new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/megatokyo_omnibus_1_3_cover_by_fredrin-d4oupef 50%.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int width = base.getWidth();
int height = base.getHeight();
BufferedImage frame = new BufferedImage(width, height, base.getType());
Graphics2D g2d = frame.createGraphics();
g2d.drawImage(base, 0, 0, null);
Iterator<Effect> it = effects.iterator();
while (it.hasNext()) {
Effect effect = it.next();
if (!effect.applyEffect(g2d, width, height)) {
it.remove();
}
}
g2d.dispose();
if (listener != null) {
listener.updateDidOccur(frame);
}
}
});
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
public void addEffect(Effect effect) {
effects.add(effect);
}
public void setEngineListener(EngineListener listener) {
this.listener = listener;
}
public Dimension getSize() {
return base == null ? new Dimension(200, 200) : new Dimension(base.getWidth(), base.getHeight());
}
}
public interface Effect {
public boolean applyEffect(Graphics2D context, int width, int height);
}
public class FadeOutEffect implements Effect {
private int tick = 0;
private Color fadeToColor;
public FadeOutEffect(Color fadeToColor) {
this.fadeToColor = fadeToColor;
}
#Override
public boolean applyEffect(Graphics2D context, int width, int height) {
tick++;
float alpha = (float) tick / 100.0f;
if (alpha > 1.0) {
return false;
}
Graphics2D g2d = (Graphics2D) context.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2d.setColor(fadeToColor);
g2d.fillRect(0, 0, width, height);
g2d.dispose();
return true;
}
}
}
Remember, every effect or change should be applied within the same "main loop", this means you shouldn't have multiple threads, in fact, since Swing is not thread safe, you should avoid having any additional threads if possible. This example make use of a Swing Timer to act as the "main loop" because the ActionListers actionPerformed method is called within the context of the EDT, making it safe to update the UI from. It also provides a simple synchronisation method, as the UI can't be painted while the actionPerformed method is been called
My issue is, i'm trying to print using Java and it seems to give a random result each time(Look at the pictures and you will understand). The first time I run it the Image prints fine, but the second time there is a black box covering half of the screen. Here is the First Run
and the Second run
Here is the code:
package test;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.ImageObserver;
import javax.swing.*;
import java.awt.print.*;
import java.net.URL;
public class HelloWorldPrinter implements Printable, ActionListener {
private Image ix = null;
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
if (page > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
/*
* User (0,0) is typically outside the imageable area, so we must
* translate by the X and Y values in the PageFormat to avoid clipping
*/
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
ix = getImage("Capture.JPG");
g.drawImage(ix, 1, 1, null);
return PAGE_EXISTS;
}
public void actionPerformed(ActionEvent e) {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
boolean ok = job.printDialog();
if (ok) {
try {
job.print();
} catch (PrinterException ex) {
/* The job did not successfully complete */
}
}
}
public static void main(String args[]) {
UIManager.put("swing.boldMetal", Boolean.FALSE);
JFrame f = new JFrame("Hello World Printer");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JButton printButton = new JButton("Print Hello World");
printButton.addActionListener(new HelloWorldPrinter());
f.add("Center", printButton);
f.pack();
f.setVisible(true);
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL imageURL = HelloWorldPrinter.class.getResource(path);
imageURL = HelloWorldPrinter.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(imageURL);
} catch (Exception e) {
System.out.println(e);
}
return tempImage;
}
}
Thanks for taking the time to read this and I hope you have a solution.
EDIT: I'm using Microsoft Print To PDF so I can view the print. I don't know if it's relevant but I would add it anyways.
MadProgrammer's solution worked.
Don't use Toolkit#getImage, this could using a thread to load the image an or caching the results in unexpected ways, consider using ImageIO.read instead, it will block until the image is fully realised. It's also possible that your getImage method is triggering an exception and is returning a blank image, but since you ignore the exception result, it's hard to know – MadProgrammer
Im trying to write a very simple program that allows you to control a sprite with arrow keys and move around the screen. From what I understand, to do this I need a keyPressed() KeyListener. I believe Im doing this correctly based on the Java Doc but its not returning the correct output when I press the designated key. Can someone please tell me what is wrong with my code, and if possible, provide a simple example of the usage of this class? Thanks!
(Note, code is unfinished)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Display extends JPanel implements ActionListener, KeyListener {
Display() {
// super();
loadImages();
initTimer();
this.addKeyListener(this);
}
BufferedImage sprite;
Timer timer;
int up = 0;
public void loadImages() {
File spriteImage = new File("Pacman_sprite.png");
try {
sprite = ImageIO.read(spriteImage);
} catch (IOException e) {
System.out.println("Sprite import failed");
}
}
public void initTimer() {
timer = new Timer(100, this);
timer.start();
this.addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
System.out.println("Key press registered"); //does not print this?
if (key == KeyEvent.VK_UP) {
System.out.println("sucess"); // does not print this?
up++;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("release");
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(sprite, 500, 500 + up, null);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
repaint();
}
}
EDIT:
May have found the answer here. I moved the key handling code to a new class called KeyHandler then added these two lines to the constructor:
addKeyListener(new KeyHandler());
setFocusable(true);
It now appears to be working just fine (sort of, at least it is detecting when the up key is hit. My graphics aren't.)
You are not adding the listener to the JPanel.
Note: I would suggest you to change your design. Right now, Display class is both a JPanel and a Listener (which doesn't make sense in my opinion).
But to add the listener in your code do something like,
this.addKeyListener(this); // This looks awkward right. That's why you should change the design.
in your constructor.