I am simply making an aquarium. Right now, I have only one fish inside it. It is moving forward and when it hits the frame it again moves back. But the face of the fish is still facing towards right side. When it moves back, I want it's face to change. How can I do that? Here is my code.
package aquarium;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.Timer;
public class Aquarium extends JPanel implements ActionListener{
Random r = new Random();
Timer t = new Timer(5, this);
int x = 0, y= 30;
int velX = 1 ,velY =1;
private ImageIcon fish2image;
private ImageIcon fish1image;
ImageIcon image = new ImageIcon(getClass().getResource("../res/aquarium.gif"));
ImageIcon image1 = new ImageIcon(getClass().getResource("../res/smallFish.gif"));
int numberFish = 12;
Aquarium(){
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
image.paintIcon(this, g, 0, 0);
image1.paintIcon(this, g, x, y);
t.start();
}
#Override
public void actionPerformed(ActionEvent e){
if(x<0 || x>465){
velX = -velX;
}
x += velX;
repaint();
}
public static void main(String[] args) {
Aquarium a = new Aquarium();
JFrame f = new JFrame();
f.setTitle("The Aquarium");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setResizable(false);
f.setBounds(500,200,500,300); //left,top,width,height
f.add(a);
}
}
Related
i created a program that makes a cube randomly move but how do i stop it from just shaking and actually make it move?
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.random.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class AIcivilication{
private static final JPanel island = new JPanel();
private static final JPanel character = new JPanel();
here`import java.awt.Color;
#SuppressWarnings("null")
public static void area(){
int y = 120;
int x = 100;
JFrame frame = new JFrame();
KeyEvent e = null;
movementthinking();
frame.setTitle("civilication");
frame.getContentPane().setLayout(null);
frame.setVisible(true);
frame.setSize(2000,700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.green);
character.setBackground(Color.BLACK);
character.setBounds(x, y, 50, 50);
frame.add(character);
}
public static void movementthinking() {
JFrame frame = new JFrame();
Timer timer = new Timer(5/120,new MyActionListener());
timer.start();
frame.setVisible(true);
}
public static class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent arg0) {
Random r = new Random();
int de = r.nextInt(3);
int y =350;
int x = 750;
if(de == 0) {
character.setLocation(x, y+=10);
}
if(de == 1) {
character.setLocation(x, y-=10);
}
if(de == 2) {
character.setLocation(x+=10, y);
}
if(de == 3) {
character.setLocation(x-=10, y);
}}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
area();
}
});
}
}
it picks number from 0 - 3 then go to a random direction but it looks like a shaking cube. how do i stop it from shaking like that and move to diffrent directions with the correct animations?
I'm trying to animate a rectangle based on a coordinate determined by for-loop, inside a button. Here is my JComponent Class:
public class Rect extends JComponent {
public int x;
public int y;
public int w;
public int h;
public Rect (int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
repaint();
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(Color.green);
g2.drawRect(x+15, y+15, w, h);
}
}
and here is my button and button inside JFrame class:
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
}
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
validate();
repaint();
}
}
});
}
But when I run the code and click the button, nothing happens. What's wrong?
EDIT: I run the frame inside my main class like this:
public class OrImage {
public static void main(String[] args) throws Exception
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
});
}
}
I changed the code of class MainFrame such that when you press the animate button, something happens, but I don't know if that is what you want to happen.
I did not change class Rect and I added main() method to MainFrame just to keep everything in one class.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
lm.add(R);
}
lm.revalidate();
lm.repaint();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
The main change is in method actionPerformed(). You need to add R to the JPanel. You need to call revalidate() on the JPanel because you have changed the number of components that it contains. And after calling revalidate() you should call repaint() (again, on the JPanel) to make it redraw itself.
This is how it looks before pressing animate.
And this is how it looks after pressing animate
EDIT
As requested – with animation.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
private int x;
private int y;
private Timer timer;
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
timer = new Timer(500, event -> {
if (x < 500) {
lm.remove(R);
x += 50;
y += 50;
R = new Rect(x, y, 50, 50);
lm.add(R);
lm.revalidate();
lm.repaint();
}
else {
timer.stop();
}
});
timer.setInitialDelay(0);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
Current state:
I have a JPanel object which contains complex components(3D-canvas written by myself).
Problem:
There is two screen devices now. I want to use one for control, another just for display, just like PowerPoint. How can I display this JPanel on another screen efficiently(static view is enough, but I want it to reflect the change on control screen?
What I have tried:
I have tried to draw the static picture to another JPanel every 200ms.
Graphics2D g2 = (Graphics2D) contentPanel.getGraphics();
g2.translate(x, y);
g2.scale(scale, scale);
displayPanel.paintAll(g2);
Notes: contentPanel is in a JFrame of display screen, displayerPanel is the panel I want to copy
But I get a problem that the display screen flicker so seriously that I can not accept this...Is it the problem of my CPU or graphics card? Or is these any efficient method I can use? Please help, thanks so much!
And here is the MCVE (sorry, this is my first time asking question in stackoverflow, but I am touched by your helps! Thanks again!)
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.Timer;
public class DisplayWindow {
private static JFrame frame = new JFrame();
private static JPanel contentPanel = new JPanel();
private static JPanel displayPanel = null;
private static Timer timerDisplay = null;
static {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(50, 50, 1366, 768);
frame.getContentPane().add(contentPanel);
frame.setVisible(true);
if (timerDisplay == null) {
timerDisplay = new java.util.Timer();
timerDisplay.schedule(new DisplayAtFixedRate(), 1000, 250);
}
}
public static void display(JPanel panel) {
displayPanel = panel;
}
private static class DisplayAtFixedRate extends TimerTask {
#Override
public void run() {
if (displayPanel != null && displayPanel.getWidth() != 0) {
double windowWidth = frame.getWidth();
double windowHeight = frame.getHeight();
double panelWidth = displayPanel.getWidth();
double panelHeight = displayPanel.getHeight();
double scale = Math.min(windowWidth / panelWidth, windowHeight / panelHeight);
int x = (int) (windowWidth - panelWidth * scale) / 2;
int y = (int) (windowHeight - panelHeight * scale) / 2;
Graphics2D g2 = (Graphics2D) contentPanel.getGraphics();
g2.translate(x, y);
g2.scale(scale, scale);
displayPanel.paintAll(g2);
}
}
}
public static void main(String[] args) {
JFrame controlFrame = new JFrame();
controlFrame.setBounds(50, 50, 1366, 768);
JPanel controlPanel = new JPanel();
controlFrame.getContentPane().add(controlPanel, BorderLayout.CENTER);
controlPanel.add(new JLabel("Hello Stackoverflow!"));
controlFrame.setVisible(true);
DisplayWindow.display(controlPanel);
}
}
Here is an example for you:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class PaintImage {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
startUI();
}
});
}
private static void startUI() {
final JFrame mainFrm = new JFrame("Main");
final JFrame paintFrame = new JFrame("Copy");
mainFrm.add(new JScrollPane(new JTree()), BorderLayout.WEST);
mainFrm.add(new JScrollPane(new JTextArea("Write your text here...")), BorderLayout.CENTER);
mainFrm.pack();
mainFrm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrm.setLocationRelativeTo(null);
final JLabel label = new JLabel("");
paintFrame.add(label);
paintFrame.setSize(mainFrm.getSize());
paintFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrm.setVisible(true);
paintFrame.setVisible(true);
final Timer t = new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final Image img = getScreenShot(mainFrm.getContentPane());
label.setIcon(new ImageIcon(img));
}
});
t.start();
}
public static BufferedImage getScreenShot(Component component) {
final BufferedImage image = new BufferedImage(
component.getWidth(),
component.getHeight(),
BufferedImage.TYPE_INT_RGB
);
// call the Component's paint method, using
// the Graphics object of the image.
component.paint( image.getGraphics() ); // alternately use .printAll(..)
return image;
}
}
Origin of method getScreenShot is here
The painting can be done by passing the displayPanel to draw itself.
class DuplicatePanel extends JPanel {
private final JPanel displayPanel;
DuplicatePanel(JPanel displayPanel) {
this.displayPanel = displayPanel;
}
#Override
public void paintComponent(Graphics g) {
displayPanel.paintComponent(g);
}
}
To trigger the repaints, like repaint(50L) either use a SwingTimer or your own manual repaints.
The code for the JPanel
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.Timer;
import java.awt.EventQueue;
import javax.swing.JPanel;
public class Board extends JPanel
implements ActionListener{
private final int B_WIDTH = 500;
private final int B_HEIGHT = 500;
private final int INITIAL_X = 400;
private final int INITIAL_Y = 0;
private final int DELAY = 25;
private Image star;
private Timer timer;
private int x, y;
public Board(){
loadImage();
initBoard();
}
public void loadImage(){
ImageIcon ii = new ImageIcon("star.png");
star = ii.getImage();
}
public void initBoard() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(B_WIDTH,B_HEIGHT));
setDoubleBuffered(true);
x = INITIAL_X;
y = INITIAL_Y;
timer = new Timer(DELAY, this);
timer.start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawStar(g);
}
private void drawStar(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
Here is where I want to call the JFrame to close but I dont know a way how.
I would like to close it from inside the if statement.
#Override
public void actionPerformed(ActionEvent e){
x -= 3;
if(x < -400){
}
repaint();
}
}
And for the JFrame
import javax.swing.JFrame;
java.awt.EventQueue;
public class SwingTimer extends JFrame {
public SwingTimer(){
add(new Board());
setTitle("FIGHT");
pack();
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void FightGraphics(){
EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
JFrame ex = new SwingTimer();
ex.setVisible(true);
}
});
}
}
mb JFrame's dispose() helps. Check this!
I made a simple program that uses drawString() to draw on a JPanel that gets repainted to change the background to a random color. It works fine, other than the ~10 pixel spaces to the right side and bottom side of the JPanel, which remain the default color. I think this problem might be happening because of the way I use pack() or getPrefferedSize(). Any help or suggestions to fix this are appreciated.
Birthday.java
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 Birthday {
DrawString panel = new DrawString();
public Birthday() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.setTitle("Happy Birthday!");
f.setLocation(10, 10);
f.pack();
f.setVisible(true);
f.setResizable(false);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
timer.start();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Birthday();
}
});
}
}
DrawString.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawString extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int x = 350;
int y = 250;
int red = random(0,255);
int green = random(0,255);
int blue = random(0,255);
Color black = new Color(0,0,0);
Color newColor = new Color(red,green,blue);
g.setColor(newColor);
g.fillRect(0,0,1000,500);
g.setColor(black);
g.setFont(new Font(null,Font.BOLD,40));
g.drawString("Happy Birthday!",x,y);
}
public static int random(int min, int max)
{
int range = max - min + 1;
int number = (int) (range * Math.random() + min);
return number;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 500);
}
}
You never want to explicitly call paintComponent. Instead if you want the panel to repaint, you can call panel.repaint(), and the panel with implicitly call its own paintComponent method for you.
Don't do every thing inside the main method, you'll find you're going to run into a lot of problems with static references.
Don't use Thread.sleep(), it will block the Event Dispatch Thread., as that's where you should be running you Swing apps from. Instead use a java.swing.Timer. See this example for Timer usage.
As noted in 3, run your Swing apps from the EDT like this
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new MyApp();
}
});
}
Don't set the size of your frame. Instead override getPreferredSize() of your DrawingPanel and just pack() the frame.
You can center the frame by using setLocationRelativeTo(null)
Should make it a habit to use the #Override annotation to make sure you are override correctly.
Add-on to 2. What you make a habit of doing, is doing your work from the constructor, then just calling the constructor in the main. Here is a refactor of your code with all the above mentioned things fixed. You can run it.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
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 Birthday {
DrawString panel = new DrawString();
public Birthday() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.setTitle("Happy Birthday!");
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setResizable(false);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
timer.start();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Birthday();
}
});
}
}
class DrawString extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int x = 350;
int y = 250;
int red = random(0, 255);
int green = random(0, 255);
int blue = random(0, 255);
Color black = new Color(0, 0, 0);
Color newColor = new Color(red, green, blue);
g.setColor(newColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(black);
g.setFont(new Font(null, Font.BOLD, 40));
g.drawString("Happy Birthday!", x, y);
}
public static int random(int min, int max) {
int range = max - min + 1;
int number = (int) (range * Math.random() + min);
return number;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 500);
}
}