keeping drawn strings on jpanel - java

I am trying to print the contents of an array of ints on the screen one at a time but keep the previous elements on screen, how can i do this? This is what i have so far which prints each element but doesnt keep the previous elements on the screen
import javax.swing.*;
import java.awt.*;
class test extends JFrame
{
JPanel panel;
public static void main(String[] args)
{
test obj = new test();
obj.makeAnim();
}
public void makeAnim() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Animate");
setResizable(false);
setSize(400,400);
Animate arr1 = new Animate();
Animate arr2 = new Animate();
//arr1.add(arr2);
getContentPane().add(arr1);
setVisible(true);
new Thread(arr1).start();
//new Thread(arr2).start();
}
}
class Animate extends JPanel implements Runnable
{
int j = 1;
int [] a = {1,2,3,5,6,7,2,1,10,99};
String temp;
public Animate()
{
setPreferredSize(new Dimension(400,400));
}
public void run()
{
for (int i = 0; i < 10; i++) {
temp = Integer.toString(a[i]);
j++;
repaint();
try {
Thread.sleep(2000);
} catch (Exception ex) {}
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.setFont(new Font("Courier",Font.PLAIN, 20));
g.drawString(temp, (50+(j*10)), 50);
}
}

There a number of problems your are facing.
Painting in Swing is stateless, that means what ever was previously painting during one cycle, will not appear in the next, unless you physically paint it.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details.
Unless you synchronize you threads and paint routines (which is not advisable), you should never change the state of any variable that the paint methods may be reliant on out side of the Event Dispatching Thread.
Instead of using a Thread you should be using a javax.swing.Timer.
You may find Concurrency in Swing and Initial Threads informative
You shouldn't be relying on "magic" numbers (such as the character width offset), you should be relying on the underlying system to provide you with useful hints. In this case, you will want to look at FontMetrics
You should also avoid using setPreferredSize and override getPreferredSize
Below is an example of how I might solve the same problem...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
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.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
class TestPaint02 extends JFrame {
JPanel panel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
TestPaint02 obj = new TestPaint02();
obj.makeAnim();
}
});
}
public void makeAnim() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Animate");
setResizable(false);
setSize(400, 400);
Animate arr1 = new Animate();
getContentPane().add(arr1);
setVisible(true);
}
public class Animate extends JPanel {
int i = 0;
int[] a = {1, 2, 3, 5, 6, 7, 2, 1, 10, 99};
public Animate() {
Timer timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
i++;
repaint();
if (i >= a.length) {
((Timer) e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setInitialDelay(0);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.setFont(new Font("Courier", Font.PLAIN, 20));
FontMetrics fm = g.getFontMetrics();
int x = 50;
int y = 50;
for (int loop = 0; loop < i; loop++) {
g.drawString(String.valueOf(a[loop]), x, y);
x += fm.stringWidth(String.valueOf(a[loop]));
}
}
}
}

Related

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

i can't see circle moving

While using Swing in java, I am trying to move a circle slowly from a starting position to an end position when clicking a button. However, I can't see the circle moving. It just moves from start to end in an instant.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MyApp {
private int x = 10;
private int y = 10;
private JFrame f;
private MyDraw m;
private JButton b;
public void go() {
f = new JFrame("Moving circle");
b = new JButton("click me to move circle");
m = new MyDraw();
f.add(BorderLayout.SOUTH, b);
f.add(BorderLayout.CENTER, m);
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
b.addActionListener(new Bute());
}
public static void main(String[] args) {
MyApp m = new MyApp();
m.go();
}
private class Bute implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 150; i++) {
++x;
++y;
m.repaint();
Thread.sleep(50);
}
}
}
private class MyDraw extends JPanel {
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.red);
g.fillOval(x, y, 40, 40);
}
}
}
I think the problem is with the action listener because when I'm doing it without using button it is working. Any suggestions?
As Andrew Thompson said, calling Thread.sleep() without defining a second thread freezes everything, so the solution is to define and run another thread like so:
class Bute implements ActionListener, Runnable {
//let class implement Runnable interface
Thread t; // define 2nd thread
public void actionPerformed(ActionEvent e) {
t = new Thread(this); //start a new thread
t.start();
}
#Override //override our thread's run() method to do what we want
public void run() { //this is after some java-internal init stuff called by start()
//b.setEnabled(false);
for (int i = 0; i < 150; i++) {
x++;
y++;
m.repaint();
try {
Thread.sleep(50); //let the 2nd thread sleep
} catch (InterruptedException iEx) {
iEx.printStackTrace();
}
}
//b.setEnabled(true);
}
}
The only problem with this solution is that pressing the button multiple times will speed up the circle, but this can be fixed by making the button unclickable during the animation via b.setEnabled(true/false). Not the best solution but it works.
As said in the comments and another answer, don't block the EDT. Thead.sleep(...) will block it, so you have two options:
Create and manage your own (new) thread.
Use a Swing Timer
In this answer I'll be using a Swing Timer, since it's easier to use. I also changed the paintComponent method to use the Shape API and change the button text to start and stop accordingly as well as reusing the same ActionListener for the button and the timer:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MovingCircle {
private JFrame frame;
private CustomCircle circle;
private Timer timer;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MovingCircle()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(this.getClass().getSimpleName());
circle = new CustomCircle(Color.RED);
timer = new Timer(100, listener);
button = new JButton("Start");
button.addActionListener(listener);
circle.setBackground(Color.WHITE);
frame.add(circle);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private ActionListener listener = (e -> {
if (!timer.isRunning()) {
timer.start();
button.setText("Stop");
} else {
if (e.getSource().equals(button)) {
timer.stop();
button.setText("Start");
}
}
circle.move(1, 1);
});
#SuppressWarnings("serial")
class CustomCircle extends JPanel {
private Color color;
private int circleX;
private int circleY;
public CustomCircle(Color color) {
this.color = color;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.fill(new Ellipse2D.Double(circleX, circleY, 50, 50));
}
#Override
public Dimension preferredSize() {
return new Dimension(100, 100);
}
public void move(int xGap, int yGap) {
circleX += xGap;
circleY += yGap;
revalidate();
repaint();
}
public int getCircleX() {
return circleX;
}
public void setCircleX(int circleX) {
this.circleX = circleX;
}
public int getCircleY() {
return circleY;
}
public void setCircleY(int circleY) {
this.circleY = circleY;
}
}
}
I'm sorry, I can't post a GIF as I wanted but this example runs as expected.

Java, animate a still image in a JApplet

I am working on an assignment and I'm essentially done with the assignment, it was just a simple program to create an image map and add some audio to hot spots, I have a couple more days left and was going to try and "animate" the image.
It's a picture of a car dash board and when the user clicked on the ignition I was going to see if there is a way to make the image shake for a second. I've tried looking around here and on google but every time I searched I was getting articles from the 90's for applet's and not JApplet's.
If you could point my in the right direction on how to "animate" the image or even to a place where there may be tutorials I'd appreciate it!
Here is my code if you want to see what I'm talking about and can help me out in anyway.
public class ImageMap extends JApplet implements MouseListener{
private Image pic;
private Container contentPane;
private JLabel directions;
private Rectangle horn;
private Rectangle vent;
private Rectangle doorLocksUpper;
private Rectangle window;
private Rectangle radio;
private Rectangle ignition;
private int x, y;
private AudioClip hornSound, airSound, radioClip, lockSound1, lockSound2, ignitionSound;
public void init() {
pic = getImage(getCodeBase(), "CarDash.jpg");
horn = new Rectangle(250, 142, 105,104);
vent = new Rectangle(514, 159, 204, 72);
doorLocksUpper = new Rectangle(80, 167, 104, 58);
window = new Rectangle(122, 243, 88, 55);
radio = new Rectangle(514, 234, 176, 171);
ignition = new Rectangle(465, 217, 42, 43);
directions = new JLabel("CLICK ON: Horn, Door Locks, Air Vents, Radio & Ignition Push Start");
//Create components
contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(directions, BorderLayout.NORTH);
contentPane.addMouseListener(this);
}
//Display image on applet window
public void paint(Graphics g) {
g.drawImage(pic, 0, 40, this);
}
public void mouseClicked(MouseEvent me) {
//Play horn clip when car horn is clicked.
if(horn.contains(me.getX(), me.getY())) {
play(getCodeBase(), "HornSound.wav");
}
if(vent.contains(me.getX(), me.getY())) {
play(getCodeBase(), "AirVent.wav");
}
if(ignition.contains(me.getX(), me.getY())) {
play(getCodeBase(), "Ignition.wav");
}
if(doorLocksUpper.contains(me.getX(), me.getY())) {
play(getCodeBase(), "DoorLocks.wav");
}
if(radio.contains(me.getX(), me.getY())) {
play(getCodeBase(), "BrownSugar.mid");
}
if(window.contains(me.getX(), me.getY())) {
play(getCodeBase(), "Window.wav");
}
}
public void mouseReleased(MouseEvent me) {}
public void mouseEntered(MouseEvent me) {}
public void mouseExited(MouseEvent me) {}
public void mousePressed(MouseEvent me) {}
}
Here's a really quick and useful tip, don't paint directly to a top level container like a applet. It traps you into a single use case, which doesn't always make it easier to modify or re-use.
Instead, start by using something like a JPanel as your primary container, with this, you can add it to what ever you like, applet, window, some other container.
While there are a number of ways you can do animation in Swing, one of the simplest (and generally safest) is to use a Swing Timer.
This example simply uses a Swing Timer, set to update every 16ms (which is to fast for my capture software :P) which is started when you click the panel. The timer simply updates a offset value which isolates between a positive and negative value. The Timer makes use of LocalTime to calculate the length of time the Timer has been running at stops it after one second
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalTime;
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 ShakeAnimation {
public static void main(String[] args) {
new ShakeAnimation();
}
public ShakeAnimation() {
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 ShakePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ShakePane extends JPanel {
private Timer timer;
private LocalTime startTime;
private int xOffset = 0;
private int delta = 8;
private BufferedImage img;
public ShakePane() {
try {
img = ImageIO.read(getClass().getResource("Duke-Thumbs.jpg"));
} catch (IOException exp) {
exp.printStackTrace();
}
timer = new Timer(16, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration duration = Duration.between(startTime, LocalTime.now());
if (duration.getSeconds() >= 1) {
timer.stop();
xOffset = 0;
} else {
xOffset *= -1;
}
repaint();
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (!timer.isRunning()) {
xOffset = delta;
startTime = LocalTime.now();
timer.start();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = ((getWidth() - img.getWidth()) / 2) + xOffset;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
See How to use Swing Timers for more details

JLabel not showing up no matter what I do

I have tried a ton of different things to try to get the JLabel to show but I don't understand why it is not working. I have tried resizing it, though that is not what i want to do, I have tried other classes, but I would prefer to stick with this one, and it is starting to get really frustrating. If you have any ideas please help. But please try to keep them simple and explain very clearly as I am still quite new to java. I have only been going for about three or four months. Here is my code:
package com.thefallenpaladin;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Created by darkp_000 on 11/4/2015.
*/
#SuppressWarnings("serial")
public class Game extends JPanel implements KeyListener,MouseListener {
public boolean mainMenu = true;
public int winWidth = 700; //Window Stats
public int winHeight = 600;
public int buttonOneX = 60; // Button Stats
public int buttonOneY = 240;
public int buttonOneW = 100;
public int buttonOneH = 75;
public boolean buttonOne = false;
public int mouseX; // not set because it is set in mouseClicked
public int mouseY;
public static void main(String[] args) {
Game game = new Game();
JFrame window = new JFrame("I hate this");
JLabel onePlayer = new JLabel();
onePlayer.setLocation(0,0/*game.buttonOneX + game.buttonOneX/2,game.buttonOneY + game.buttonOneY/2*/);
window.add(game);
window.setFocusable(true);
window.setResizable(false);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setSize(700,600); //TODO
window.setVisible(true);
game.requestFocusInWindow();
game.add(onePlayer);
game.addKeyListener(game);
game.addMouseListener(game);
window.setLocationRelativeTo(null);
while(true) { // Main Game loop
onePlayer.setText("One Player");
game.repaint();
game.customUpdate();
}
}
public void customUpdate() {
if(mouseX > buttonOneX && mouseX < buttonOneX+buttonOneX && mouseY > buttonOneY && mouseY < buttonOneY+buttonOneY && mainMenu) {
buttonOne = true;
System.out.print("Starting Game");
}
}
public void paint(Graphics g) {
if(mainMenu) {
g.setColor(Color.CYAN); // Set main menu
g.fillRect(0,0,winWidth,winHeight);
g.setColor(Color.GREEN);
g.fillRect(buttonOneX,buttonOneY,buttonOneW,buttonOneH);
}
if(buttonOne) {
mainMenu = false;
g.setColor(Color.GREEN);
g.fillRect(0,0,winWidth,winHeight);
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
System.out.println(e);
}
public void keyReleased(KeyEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
// System.out.println(e);
mouseX = e.getX();
mouseY = e.getY();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
Okay so you've made a couple of basic mistakes...
First, JLabel onePlayer = new JLabel(); creates an empty label, with no size (0x0) and since labels are transparent by default, you'd not see it
Next, you've overridden paint of a top level container (JFrame), but failed to honor the paint chain effectively preventing any of the child components from ever getting painted
public void paint(Graphics g) {
if (mainMenu) {
g.setColor(Color.CYAN); // Set main menu
g.fillRect(0, 0, winWidth, winHeight);
g.setColor(Color.GREEN);
g.fillRect(buttonOneX, buttonOneY, buttonOneW, buttonOneH);
}
if (buttonOne) {
mainMenu = false;
g.setColor(Color.GREEN);
g.fillRect(0, 0, winWidth, winHeight);
}
}
So, if I remove your paint method and change JLabel onePlayer = new JLabel(); to JLabel onePlayer = new JLabel("I'm a label"); I get this output...
Also...
while (true) { // Main Game loop
onePlayer.setText("One Player");
game.repaint();
game.customUpdate();
}
has the potential to try screw up your program, you have no guarantee's in what thread your main method is been called and you should not make assumptions.
Start by creating a custom component, extending from something like JPanel and override it's paintComponent method, place your custom painting there. In fact, you should have a panel for each state of your game (menu, running, settings, etc).
Add these to your frame (probably using a CardLayout to enable you to easily switch between them)
Use either a Thread or Swing Timer as a main game loop, one which you create explicitly.
Have a look at Painting in AWT and Swing, Performing Custom Painting, How to Use CardLayout and How to use Swing Timers for some more details
As a "conceptual" example...
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class AwesomeGame {
public static void main(String[] args) {
new AwesomeGame();
}
public AwesomeGame() {
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 ContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface NavigationController {
public void letsPlay();
}
public class ContentPane extends JPanel implements NavigationController {
private CardLayout cardLayout;
private GamePane gamePane;
public ContentPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
add(new MenuPane(this), "TheMenu");
add((gamePane = new GamePane()), "TheGame");
cardLayout.show(this, "TheMenu");
}
#Override
public void letsPlay() {
cardLayout.show(this, "TheGame");
gamePane.play();
}
}
public class MenuPane extends JPanel {
public MenuPane(NavigationController navigationController) {
JLabel label = new JLabel("My Super Dupa Awesome Game!");
label.setFont(label.getFont().deriveFont(Font.BOLD, 48));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
JButton play = new JButton("Play Now!");
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
navigationController.letsPlay();
}
});
add(play, gbc);
setBackground(Color.GREEN);
}
}
public class GamePane extends JPanel {
public GamePane() {
setBackground(Color.BLUE);
}
public void play() {
Timer timer = new Timer(500, new ActionListener() {
int count;
#Override
public void actionPerformed(ActionEvent e) {
count++;
if (count % 2 == 0) {
setForeground(Color.BLACK);
} else {
setForeground(Color.RED);
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text = "I bet you're blowen away by it's awesomness!";
FontMetrics fm = g2d.getFontMetrics();
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}

Change the background color on a custom Button?

I want my button to change color on the mod == 0 of i % 3. The paintComponent(...) is called when the form is re-sized and index is passed in so I would think that this should change the color of my button ever time I start moving the form around the screen.
I have two components on the screen but both will not show up this might be a factor.
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testform {
public static void main (String[] p) {
testBall3 j1 = new testBall3();
myButton b1 = new myButton("test");
JPanel testPane = new JPanel();
testPane.setBackground(Color.green);
testPane.setLayout(new BorderLayout());
j1.setPreferredSize(new Dimension(10,10));
//testPane.add(b1);
testPane.add(j1);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//j1.setColorBall(Color.BLACK);
//j1.repaint();
}
}
class myButton extends JButton {
private static final long serialVersionUID = 1L;
public myButton(String s) {
super(s);
}
public void setPrefferedSize(Dimension d) {
//this.setBounds(x, y, width, height)
setPreferredSize(d);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
index += i;
System.out.println(i);
if (index % 3 == 0) {
setBackground(Color.RED);
}
else {
setBackground(Color.BLACK);
}
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
class testBall3 extends JComponent
{
private static final long serialVersionUID = 1L;
private Color colorBall = Color.red;
private int x1, y1;
int index = 0;
public void setColorBall(Color c)
{
this.colorBall = c;
}
public testBall3()
{
super();
System.out.println("MyBall (0)");
}
public testBall3(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
System.out.println("MyBall (1)");
x1 = x;
y1 = y;
}
public void paintBorder(Graphics g)
{
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorBall);
g.fillOval(x1, y1, 10, 10);
System.out.println("paintComponent");
}
public void paint(Graphics g)
{
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
System.out.println("Paint");
}
}
But paintComponent doesn't take a second parameter, how are you passing it? I would think that instead of trying to pass i, you would want make i an attribute of class myButton instead and initialize it to 0 upon instantiation. That is, if you want each button to have its own counter. That sounds like the better plan.
You've got a lot of strange stuff going on...
You've got a component where you override all four major painting methods for no good reason.
In this component, your paint method override calls the super method, and calls the other 3 methods, which in essence will make those 3 methods be called twice.
You've got program logic (advancement of i) inside of your myButton's paintComponent method -- something that should never be done. You do not have full control over when or even if this method is called.
You are calling setBackground(...) from within paintComponent, something which shouldn't be done.
Your class names do not begin with an upper case letter, going against coding conventions, and potentially confusing anyone who tries to read your code.
If you want to change the state of a component on resize, use a ComponentListener.
e.g.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo2 extends JPanel {
protected static final Color MAGIC_BACKGROUND = Color.red;
protected static final int MAGIC_NUMBER = 3;
private static final int TIMER_DELAY = 20;
private int index = 0;
private JButton myButton = new JButton("My Button");
protected int DELTA_SIZE = 2;
public Foo2() {
add(myButton);
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
index++;
if (index % MAGIC_NUMBER == 0) {
myButton.setBackground(MAGIC_BACKGROUND);
} else {
myButton.setBackground(null);
}
}
});
new Timer(TIMER_DELAY, new ActionListener() {
private Toolkit toolkit = Toolkit.getDefaultToolkit();
private int screenWidth = toolkit.getScreenSize().width;
private int screenHeight = toolkit.getScreenSize().height;
#Override
public void actionPerformed(ActionEvent e) {
if (getWidth() >= screenWidth || getHeight() >= screenHeight) {
((Timer)e.getSource()).stop();
} else {
int width = getWidth() + DELTA_SIZE;
int height = getHeight() + DELTA_SIZE;
setPreferredSize(new Dimension(width, height));
Window win = SwingUtilities.getWindowAncestor(Foo2.this);
win.pack();
win.setLocationRelativeTo(null);
}
}
}).start();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories