Help with creating a complex Swing GUI with animation - java

This is my first non-school related program. I have a few questions that you guys can hopefully answer with ease. I have 3 questions. How can I add my button to my JFrame even though it's in a different class than the button?
Also, how would I go about making my shape and ten others like it about a quarter second after each other so I had a line of them.
Then, how would I force them to follow a predetermined path that scales to somebody dragging the box around?
Thanks a lot for reading and helping me out guys. Here are my three classes:
gameRunner.java
import javax.swing.JFrame;
public class gameRunner {
public static void main(String args []){
Enemy e = new Enemy();
Buttons b = new Buttons();
JFrame f = new JFrame();
f.add(b);
f.add(e);
f.setVisible(true);
f.setSize(1300, 700);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Tower Defense");
}
}
Enemy.java
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Enemy extends JPanel implements ActionListener {
Timer t = new Timer(5, this);
double x = 0;
double y = 0;
double velX = 3;
double velY = .5;
int health = 10;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle2D square = new Rectangle2D.Double(x, y, 10, 10);
g2.fill(square);
t.start();
}
public double adjustHorizontalSpeed() {
y += velY;
return y;
}
public double adjustVerticalSpeed() {
x += velX;
return x;
}
public void actionPerformed(ActionEvent e) {
adjustHorizontalSpeed();
adjustVerticalSpeed();
repaint();
}
}
Buttons.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Buttons extends JFrame implements ActionListener{
private JButton shoot;
public Buttons(){
shoot = new JButton("Shoot!");
shoot.setBounds(50,60,50,100);
shoot.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}

Buttons shouldn't extend JFrame if all you want to do is use it to create a JButton that you wish to add to another GUI. Instead perhaps give it a public method called getShoot() that returns the button created:
public JButton getShoot() {
return shoot;
}
Next, to do things in a timed fashion, you should use a Swing Timer. The tutorials will tell you how to do this: How to use Swing Timers
Next, you'll want to read the Swing tutorial section on how to use layout managers so you can add a complex mix of components to the GUI and have them all fit well together: Laying out Components in a Container
Finally, as for this:
Then, how would I force them to follow a predetermined path that scales to somebody dragging the box around?
You'll have to describe this better for me to understand what you're trying to do.

For the predetermined path, you should probably have them move/size themselves proportional to the containing pane. With a layout manager, assuming they are inside their own JPanel, the pane should scale automatically, so when the window is resized, the shapes will resize and move properly.

Related

Drawing a rectangle that moves slowly towards the point of the mouse click rather than jumping to it (JAVA)

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 ;)

Fading in an image on top of a jPanel

I want to have an image fade in onto a panel that is part of a card layout. When i'm at a certain place in the program, this panel will show on top and I then want the image to be loaded in with a fade-in effect.
This is a big project so I will only paste the relevant code.
I have a GUI class which contains the jFrame, all the jPanels etc. When a certain event is triggered, this code runs:
cardMain.show(pMain, "cLeprechaun");
FadeIn.run(pLeprechaun);
It loads up the correct panel and then runs a static method in the FadeIn class, that is supposed to add the image onto the panel pLeprechaun.
Here is the FadeIn class:
import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class FadeIn extends JPanel implements ActionListener {
Image imagem;
Timer timer;
private float alpha = 0f;
public FadeIn() {
imagem = new ImageIcon("darkforest.jpg").getImage();
timer = new Timer(100, this);
timer.start();
}
// here you define alpha 0f to 1f
public FadeIn(float alpha) {
imagem = new ImageIcon("darkforest.jpg").getImage();
this.alpha = alpha;
}
#Override
public void paintComponent(Graphics g) {
System.out.println("paint");
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
alpha));
g2d.drawImage(imagem, 0, 0, null);
}
public static void run(JPanel jPanel) {
jPanel.add(new FadeIn());
}
public void actionPerformed(ActionEvent e) {
alpha += 0.05f;
if (alpha >1) {
alpha = 1;
timer.stop();
}
repaint();
}
}
Nothing happens, no image is show on the panel. Just to try it out, instead of jPanel.add(new FadeIn()); I have also tried to create a new jFrame and adding a new FadeIn onto that, and it works then. Of course, instead of an image being painted on the jPanel, a new jFrame pops up ontop of the main one, with the image nicely fading in. But that's not what I want happening.
Is there a way to solve this?
Er go:
assuming you have the following sequence of calls:
JFrame f=new JFrame();
f.setSize(500, 500);
JPanel j=new JPanel();
f.add(j);
f.setVisible(true);
FadeIn.run(j);
you need to change the size as follows:
public FadeIn(Dimension d) {
setSize(d);
.... // the rest of set up
}
then in run:
run(Jpanel jPanel) {
jPanel.add(new FadeIn(jPanel.getSize()));
}

Java screenshot (using Robot and BufferedImage.getRGB)

I discovered the Robot class yesterday, and thought it was pretty cool. Today I wanted to experiment with it and see what was possible; so I decided I wanted to make a program that took a screenshot of the entire screen, and rendered out an image pixel by pixel on a JPanel. I have the program finished (two classes), but it isn't working and I can't find out why (I HAVE looked over the code a few times). Here's the code:
(FIRST CLASS)
import java.awt.AWTException;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class One {
public static void main(String[] args) {
BufferedImage screenCap = null;
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
screenCap = new Robot().createScreenCapture(screenRect);
Two imageRenderer = new Two(screenCap, screenRect);
imageRenderer.doRender();
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(imageRenderer);
frame.pack();
} catch (AWTException e) {
e.printStackTrace();
}
}
}
(SECOND CLASS)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class Two extends JPanel {
private BufferedImage screenCap;
private Rectangle screenRect;
private Color pixelRGB;
//c1 and c2 are the x and y co-ordinates of the selected pixel.
private int c1, c2;
public Two(BufferedImage sC, Rectangle rect) {
screenCap = sC;
screenRect = rect;
setPreferredSize(new Dimension(rect.width, rect.height));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
g.setColor(pixelRGB);
g.drawRect(c1, c2, 1, 1);
}
public void doRender() {
for(int i=0; i<screenRect.width; i++) {
for(int j=0; j<screenRect.height; j++) {
pixelRGB = new Color(screenCap.getRGB(i, j));
c1 = i;
c2 = j;
repaint();
}
}
}
}
I have googled around this problem to no avail.
Can anyone tell me what I'm doing wrong?
In order to make it work, just replace your paintComponent() method in your class Two with the following:
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
g.drawImage(screenCap, 0, 0, getWidth(), getHeight(), null);
}
You can also get rid of the doRender() method.
Two should probably be an instance of a JLabel that is displaying screenCap. E.G.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Screenshot {
public static void main(String[] args) throws Exception {
Rectangle screenRect = new Rectangle(
Toolkit.getDefaultToolkit().getScreenSize());
final BufferedImage screenCap =
new Robot().createScreenCapture(screenRect);
Runnable r = new Runnable() {
#Override
public void run() {
JOptionPane.showMessageDialog(null, new ImageIcon(screenCap));
}
};
SwingUtilities.invokeLater(r);
}
}
Drop it in a scroll pane if you wish to be really neat about it. Batteries not included.
In case it is not obvious: A JOptionPane uses a JLabel to render an ImageIcon.
Each time you repaint, you paint white over the whole panel, then do only a single pixel. So after each one, you'll only get one pixel. It also shouldn't be necessary to call repaint many times. In fact, when you call repaint, it does not immediately actually call paintComponent. It simply submits a request to repaint, which swing will eventually do. And it might not be one-to-one. E.g., many calls to repaint might result in only one call to paintComponent. You should try to write code so that a single call to paintComponent will completely display the component.
To do this, you can use g.drawImage to display a BufferedImage. See this post for more information on displaying an image in a JPanel.

Zooming a JLabel by overriding paintComponent ()

Consider this small runnable example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test2 extends JFrame implements MouseWheelListener{
ArrayList<JLabel> lista = new ArrayList<JLabel>();
JPanel p;
double d = 0.1;
Test2(){
p=new JPanel();
_JLabel j = new _JLabel("Hello");
j.setOpaque(true);
j.setBackground(Color.yellow);
p.add(j);
p.setBackground(Color.blue);
add(p);
this.setVisible(true);
this.setSize(400,400);
addMouseWheelListener(this);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String args[]){
new Test2();
}
private class _JLabel extends JLabel{
_JLabel(String s){
super(s);
}
protected void paintComponent(Graphics g) {
d+=0.01;
Graphics2D g2d = (Graphics2D) g;
g2d.scale(d, d);
setMaximumSize(null);
setPreferredSize(null);
setMinimumSize(null);
super.paintComponent(g2d);
System.out.println("d= " +d);
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
this.repaint();
}
}
When I scroll the mousewheel the JLabel increases in size and the variable d is printed out. However, when it reaches the actual size (d=1) only the text continues zooming. How can I make the background continue to zoom?
You shouldn't be modifying the preferred/min/max sizes in the paint method, this coud have unexpected results (cause another repaint).
The problem is that the parent layout has no reference from which to determine size of the component. That is, the preferred/in/max size is actually calculated based on the font information & this information is not been changed.
So, while it "appears" that the component is being resized, it's actual size has not changed.
Try instead to scale against the original font size.
AffineTransformation af = AffineTranfrmation.getScaleInstance(scale, scale);
Font font = originalFont.deriveFont(af);
setFont(font);
invalidate();
repaint();
Of course you run into the problem of what happens if the user changes the font, but with a little bit of flagging, you should be able to over come that

Tips regarding how to create an Java Solitaire game

I got some question regarding the approach to create an solitaire game in java.
What is the best way of handling the cards in Swing? How can I drag them, and what is the best way to snap them into their right positions?
what is the best way to snap them into
their right positions?
The Overlap Layout might help you with this.
What would be the best approach for dragging multiple images? I've come as far as using Java2D to draw two images to a JPanel, but I'm only able to drag one of them. I'll attach my source code. The problem with my solution is that I need to repaint the entire window even though I'm just manipulating one element. Is it possible to handle objects of cards, instead of images of them? So when I move one card, I'll move the visual presentation of the object, instead of a image (as I do now.)
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Java2d_MainPanel extends JPanel{
private static BufferedImage img = new logic.GetBufferedImage().getImage();
private JButton knapp = new JButton("Nytt bilde");
private JButton knapp2 = new JButton("Nytt bilde2");
private static BufferedImage img2 = new logic.GetBufferedImage().getImage2();
//coordinates for image 1
private int x1 = 0;
private int y1 = 0;
//coordinates for image 2
private int x2 = 50;
private int y2 = 50;
public Java2d_MainPanel(){
add(knapp);
add(knapp2);
knapp.addActionListener(new ButtonHandler());
knapp2.addActionListener(new ButtonHandler2());
addMouseMotionListener(new MouseMotionHandler());
}
public void newImage(ActionEvent e){
if(e.getSource().equals(knapp)){
img = new logic.GetBufferedImage().getImage();
repaint();
}
else if(e.getSource().equals(knapp2)){
img2 = new logic.GetBufferedImage().getImage2();
repaint();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
newPaint(g2d);
}
public void newPaint(Graphics2D g2d){
g2d.drawImage(img, x1, y1, null);
g2d.drawImage(img2, x2, y2,null);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Rabbits");
frame.add(new Java2d_MainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 640);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(MouseEvent e) {
x1 = e.getX()-(img.getWidth()/2);
y1 = e.getY()-(img.getHeight()/2);
repaint();
}
}
class ButtonHandler implements ActionListener{
public void actionPerformed(ActionEvent e) {
newImage(e);
}
}
class ButtonHandler2 implements ActionListener{
public void actionPerformed(ActionEvent e) {
newImage(e);
}
}
}

Categories

Resources