I'm coding a simple card-based game where the player has a hand of cards along the bottom of the screen. When they click on a card, the card moves across the window onto a 'discard pile' location.
I've got the movement animation working to my satisfaction, but the problem is the card button disappears when it moves across other panels. The hand of cards is in the PAGE_END section of a borderlayout for the content pane, and the discard pile is at the top of the screen - so the card has to move across the CENTER section to get to its destination. But it goes behind the CENTER panel, whereas I want it to go in front.
Is this possible? I've tried looking into LayeredPanes but that seems to require all of my components being directly inside one container, which they aren't (because I have another panel inside the bottom section of my content panel).
I've written up the simplest version of the problem that I can, using two classes.
The main class:
package moveButton;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class MoveButton extends JFrame implements ActionListener {
public JPanel view;
public MovingButton mover;
public static MoveButton instance;
public static void main(String[] args) {
instance = new MoveButton();
}
public MoveButton() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500,500);
this.setVisible(true);
view = new JPanel();
view.setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
view.add(buttonPanel, BorderLayout.PAGE_END);
mover = new MovingButton("Move");
mover.addActionListener(this);
buttonPanel.add(mover);
this.setContentPane(view);
this.repaint();
this.revalidate();
}
#Override
public void actionPerformed(ActionEvent e) {
MoveButton.instance.mover.timer.start();
}
}
The button class:
package moveButton;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.Timer;
public class MovingButton extends JButton implements ActionListener {
public Timer timer;
public static final int X_INC = 5;
public static final int Y_INC = -5;
public int xPos;
public int yPos;
public MovingButton(String text) {
super(text);
timer = new Timer(30, this);
}
#Override
public void actionPerformed(ActionEvent e) {
this.move();
MoveButton.instance.repaint();
if(xPos == 100 || yPos == 100) {
timer.stop();
}
}
public void move() {
xPos = xPos + X_INC;
yPos = yPos + Y_INC;
}
public void paint(Graphics g) {
g.translate(xPos, yPos);
super.paint(g);
}
}
Related
I have been creating a 2D camera in Swing. But then I discovered that if I use graphics.translate (to move the origin of coordinates) and set the position of the children using coordinates relative to the start of the world, unexpected behavior occurs:
In my original program, the JComponents don't redraw when they should.
In the published mcve, the image is still drawn where it was initially created, as well as being drawn on the correct side and not updating anymore.
The idea would be that, having the coordinates relative to the start of the "world", that the redraw process automatically converts that into coordinates relative to the JPanel.
What would be the correct way to achieve it without directly using the coordinates relative to the JPanel.
Application.java
package regexlang;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Application extends JFrame{
public Application() {
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Panel());
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Application ex = new Application();
ex.setVisible(true);
});
}
}
Panel.java
package regexlang;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class Panel extends JPanel implements ActionListener, KeyListener{
private int x;
private int y;
private JLabel label;
public Panel() {
setLayout(null);
setBackground(Color.black);
addKeyListener(this);
setFocusable(true);
this.label = new JLabel("hola mundo");
this.label.setBounds(700, 0, 100, 100);
this.label.setOpaque(true);
add(this.label);
Timer timer = new Timer(1000, this);
timer.setRepeats(true);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.translate(-this.x, -this.y);
}
public void paintComponents(Graphics g) {
g.translate(-this.x, -this.y);
super.paintComponents(g);
}
#Override
public void actionPerformed(ActionEvent e) {
Random random = new Random();
Color color = new Color(random.nextInt(256),
random.nextInt(256),
random.nextInt(256));
this.label.setBackground(color);
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
this.x += 1;
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Edit After some more thinking, I have a hypothesis that the coordinates used by swing are calculated before it gets to translate the origin of coordinates with Graphics.translate. I've tried to get around this by overriding the getGraphics method, to no avail (since it doesn't seem to be used much internally).
I made a program to displace a random number of rectangles on the screen with buttons to make fewer or more with either doubles or halves the number of rectangles. Then I was asked to modify the program to add a slider instead of buttons to the program to control the amount of rectangle on the screen. I am having some trouble.
I am getting a few errors. My professor insists on using IntelliJ IDE for the development environment, which I am not too familiar with. It's asking me to move package c16 and also to make public class Random Rectangles to main or not public any help would be good.
package c16;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class RandomRectangles extends JFrame {
private int rectangle_count=1;
private Random random = new Random();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run() {
RandomRectangles r = new RandomRectangles();
r.setTitle("Rectangles");
r.setSize(new Dimension(500, 500));
r.setVisible(true);
}
});
}
public RandomRectangles()
{
super();
setLayout(new BorderLayout());
#SuppressWarnings("unused")
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 500, 1);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent arg0) {
rectangle_count = slider.getValue();
RandomRectangles.this.repaint();
}
});
/*
On clicking SHRINK(FEWER),
half the number of rectangles in the RectangleArea
with different co-ordinates.
*/
JPanel rectangleArea = new JPanel()
{
public void paintComponent(Graphics g) //in-built function.
{
super.paintComponent(g);
g.setColor(Color.BLUE);
/*Get the random co-ordinates for Rectangle.*/
for(int i=0;i<rectangle_count;i++){
int a= (int)Math.floor(random.nextDouble()*getWidth());
int b=(int)Math.floor(random.nextDouble()*getHeight());
int c = (int)Math.floor(random.nextDouble()*(getWidth()-a));
int d = (int)Math.floor(random.nextDouble()*(getHeight()-b));
g.drawRect(a,b,c,d);
}
}
};
/*Add the buttons and the panel to the BorderLayout
so that they are visible for demo.
*/
add(slider,BorderLayout.NORTH);
add(rectangleArea,BorderLayout.CENTER);
}
}
I am very new to JAVA and i am just a hobbyist,Just recently I have been following some tutorials on making UI and all thee looking in to learn about this, any code snippets are welcome but also more what is this function / process called so i can look deeper into different parts of swing from the ORACLE DOCS which is really informative, I am still working my way through the components.
I do not have an overall goal at present and am just finding my feet, but i want to try and make a small top-down 2d maze game to learn.
One part got my attention and it was this demo at the bottom of the page
https://docs.oracle.com/javase/tutorial/uiswing/painting/step3.html
Basically this is the code and I am trying to make it so when I click inside the frame the rectangle moves slowly towards the point of the mouse click rather than jumping to it (and later on if possible to click in another location and it would change its course before reaching its destination.
What kind of area do i need to be looking in to learn about this, any code snippets are welcome but also more what is this function / process called so i can look deeper into it.
WORKING DEMO CODE BELOW
package painting;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseMotionAdapter;
public class SwingPaintDemo3 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() { I am Trying to make it so when I click inside the
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
}
class MyPanel extends JPanel {
private int squareX = 50;
private int squareY = 50;
private int squareW = 20;
private int squareH = 20;
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
}
private void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(250,200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}
Thanks for any advice ;)
In an attempt to make a very simple bullet-hell game to learn about java, I ran into a roadblock: repaint() wasn't calling paintComponent().
Here is the entire program, which for now simply draws an image I created 50 times per second onto a JPanel, which rests on a JFrame.
/*
* Bullet hell, by Nematodes
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class bulletHell extends JFrame
{
private static final long serialVersionUID = 0L;
JPanel gamePanel = new JPanel();
int gameTimerDelay = 20;
int x, y = 0;
BufferedImage lightOrb;
javax.swing.Timer gameTimer;
public static void main(String[] args)
{
bulletHell createFrame = new bulletHell();
createFrame.frameConstructor();
}
public void frameConstructor()
{
// Construct frame and frame components
setTitle("Bullet hell");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout(new GridBagLayout());
setVisible(true);
GridBagConstraints gridConstraints;
gridConstraints = new GridBagConstraints();
gridConstraints.gridx = 0;
gridConstraints.gridy = 0;
gamePanel.setBackground(Color.BLACK);
gamePanel.setPreferredSize(new Dimension(700, 700));
getContentPane().add(gamePanel, gridConstraints);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) (0.5 * (screenSize.width - getWidth())),
(int) (0.5 * (screenSize.height - getHeight())), getWidth(), getHeight());
try
{
lightOrb = ImageIO.read(new File("C:/Users/Owner/Downloads/orb.bmp"));
}
catch(IOException e)
{
System.out.println("An issue occurred while trying to read orb.bmp");
}
// Start timer that draws game objects 50 times per second (50 FPS)
gameTimer = new javax.swing.Timer(gameTimerDelay, gameTimerAction);
gameTimer.setInitialDelay(0);
gameTimer.start();
}
ActionListener gameTimerAction = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
};
class GraphicsPanel extends JPanel
{
public GraphicsPanel()
{
}
// Draw all of the components
#Override
public void paintComponent(Graphics g)
{
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
g2D.drawImage(lightOrb, x, y, this);
g2D.dispose();
}
}
}
After some debugging with breakpoints and println methods, I can confirm that the correct image is being read, the timer in gameTimerAction is being called 50 times per second, and repaint() is not invoking paintComponent() at all.
I am somewhat new to Java programming, and might just be missing something simple.
Edit: Problem has been solved by changing gamePanel to a GraphicsPanel object. Unfortunately, this also means that my much larger pong project (which this project's flawed drawing logic was essentially copied from) only worked by a miracle, and might be unstable with certain code additions.
I can immediately see several problems:
Most Important: You never instantiate a GraphicsPanel object, nor do you add it to anything. The paintComponent(...) method will never be called on a JPanel that is neither rendered nor created. Why not make your gamePanel variable a GraphicsPanel object and not a JPanel object?
You never change x and y in your Timer, and so without change, no animation will occur.
Also you're calling dispose on a Graphics object given to you by the JVM, something you should never do. This breaks the Swing painting chain making the graphics of your GUI unstable.
So keep at it, you'll get there.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class BulletExample extends JPanel {
public static final String IMG_PATH = "http://www.i2clipart.com/cliparts/f/0/5/8/clipart-blue-circle-f058.png";
private static final int PREF_W = 700;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage bullet;
private int bulletX;
private int bulletY;
public BulletExample() throws IOException {
URL imgUrl = new URL(IMG_PATH);
bullet = ImageIO.read(imgUrl);
new Timer(TIMER_DELAY, new BulletListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bullet != null) {
g.drawImage(bullet, bulletX, bulletY, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class BulletListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
bulletX++;
bulletY++;
repaint();
}
}
private static void createAndShowGui() throws IOException {
// create the drawing JPanel
BulletExample mainPanel = new BulletExample();
JFrame frame = new JFrame("BulletExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// add it to the JFrame
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGui();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
I want to make an image that I drew in the paint class move left across my JFrame as a timer ticks. But I don't know how to do that. Also, I am trying to get my program to make the image disappear when the image is clicked upon.
movingball class
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
import javax.swing.Timer;
public class movingball extends JPanel{
private int move=50;
private Timer timer = new Timer(move, new TimerListener());
private int radius = 10;
private int x = 300;
private int y = 0;
public movingball() {
timer.start();
}
private class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
x=x-20;
repaint(); }//trying to get the oval to move left 20
}
protected void paintComponent(Graphics2D g){
super.paintComponent(g);
g.fillOval(x, 100 , radius * 2, radius * 2); }
}
movingControl class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class movingControl extends JPanel {
private movingball ball= new movingball();
public movingControl(){
JPanel panel = new JPanel();
ball.setBorder(new javax.swing.border.LineBorder(Color.red));
panel.addMouseListener(new movingballListener());
setLayout(new BorderLayout());
add(ball, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
}
}
SnniperGameApp class
I know I spelled sniper wrong
import javax.swing.JApplet;
public class SnniperGameApp extends JApplet {
static final long serialVersionUID = 2777718668465204446L;
//i dont know what this serial thing is. But my program wont start without it
public SnniperGameApp(){
add(new movingControl());
}
}
ClickingEvent class
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
class movingballListener extends MouseAdapter{
public void mouseReleased(MouseEvent e) {
if ((e.getModifiers() & InputEvent.BUTTON1_DOWN_MASK) != 0) {
System.out.println( (e.getPoint()));}}
}
You haven't over-ridden paintComponent() properly.
From the javadoc, the signature of paintComponent() is:
protected void paintComponent(Graphics g)
but you have:
protected void paintComponent(Graphics2D g)
The method signatures must match - you can safely cast the Graphics to a Graphics2D inside the method if needed.
Adding the #Override annotation to a method is a good way to get the compiler to check that you really are over-riding a method, not just writing a method that looks the same!
Here's a working SSCCE (I have inlined some of the constants to save space, don't take that as good practice for real code!):
public class MovingBall extends JPanel
{
private Timer timer = new Timer(50, new TimerListener());
private int x = 300;
public MovingBall()
{
timer.start();
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
x -= 20;
repaint();
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x, 100, 20, 20);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new MovingBall());
frame.setSize(500, 500);
frame.setVisible(true);
}
}