Im trying to make a function that receive a image and imageicon as parameter, darken it for 2 secs and turn it back to normal, but i cant make the timer works as planned.
public void blinkImage(Image e, ImageIcon f) {
ActionListener listener = new ActionListener(){
public void actionPerformed(ActionEvent event){
Graphics2D g2 = (Graphics2D) e.getGraphics();
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, f.getIconWidth(), f.getIconHeight());
}
};
Timer displayTimer = new Timer(2000, listener);
displayTimer.start();
displayTimer.stop();
}
OBS: after this call will be a setIcon(f) in the main window, turning it back to normal. My question is: where should I put the start() and stop() calls? There is a better way to do it?
Thanks and sorry for bad english.
public void blinkImage(Image e, ImageIcon f)
Not sure why you have two parameters. Is the Image the Image in the Icon?
Painting onto the Image will be permanent. So if it is the same Image as the Icon you can't restore the Icon to its original state.
displayTimer.start();
displayTimer.stop();
You can't invoke stop() right after you start() the Timer because the Timer will never fire. So all you need is the start().
Since you only want the Timer to fire once you would just use:
timer.setRepeats( false );
then you don't have to worry about stopping the Timer.
One approach is create a custom Icon with two states. Then you can toggle the state of the Icon:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DarkIcon implements Icon
{
private Icon icon;
private Color color;
private boolean dark = false;
public DarkIcon(Icon icon, Color color)
{
this.icon = icon;
this.color = color;
}
public void setDark(boolean dark)
{
this.dark = dark;
}
#Override
public int getIconWidth()
{
return icon.getIconWidth();
}
#Override
public int getIconHeight()
{
return icon.getIconHeight();
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y)
{
icon.paintIcon(c, g, x, y);
if (dark)
{
g.setColor(color);
g.fillRect(x, y, getIconWidth(), getIconHeight());
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
Icon icon = new ImageIcon("mong.jpg");
DarkIcon darkIcon = new DarkIcon(icon, new Color(0, 0, 0, 128));
JLabel label = new JLabel( darkIcon );
Action blink = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e2)
{
darkIcon.setDark( false );
label.repaint();
}
};
Timer timer = new Timer(2000, blink);
timer.setRepeats( false );
JButton button = new JButton("Blink Icon");
button.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
darkIcon.setDark(true);
label.repaint();
timer.restart();
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(label);
f.add(button, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo( null );
f.setVisible(true);
}
}
Related
I'd like to create an animation of a few objects ("Spaceships") on the screen, with a start button. This is what I have so far:
public class SpaceGame extends JPanel implements ActionListener {
//The list of spaceships that should be painted
LinkedList<Spaceship> playingList = new LinkedList<Spaceship>();
Timer t = new Timer(5, this);
#Override
public void actionPerformed(ActionEvent e) {
ListIterator<Spaceship> iter = playingList.listIterator();
while (iter.hasNext()) {
Spaceship s = iter.next();
s.moveSpaceship();
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList)
s.drawSpaceship(g);
t.start();
}
public static void main(String[] args) {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
fr.setSize(990,690);
fr.add(game);
game.playingList .add(new Spaceship(3, 0, 570));
game.playingList .add(new Spaceship(1, 250, 570));
game.playingList .add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(game);
fr.add(start,BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
where:
import java.awt.Graphics;
public class Spaceship {
int initialSpeed;
int locX, locY; //current location
public Spaceship(int initalSpeed, int initX, int initY) {
this.initialSpeed = initalSpeed;
locX = initX;
locY = initY;
}
public void drawSpaceship(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(locX, locY, 100, 40);
}
public void moveSpaceship() {
locY -= initialSpeed;
}
}
Of cousre the idea is that pressing the button would trigger the animation. The problem is that the animation would start automaticaly without the start button being pressed, and then when it ends, the button has no effect. How can I fix this?
Let's start with the glaringly obvious...
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList)
s.drawSpaceship(g);
t.start();
}
Call t.start inside paintComponent is a very, very, very bad idea. You do not control the paint process (ie when paintComponent gets called), so it might be called at any time for any number of reasons, often in quick succession.
You should have a look at Painting in AWT and Swing for more details about how painting works in Swing
Painting should simply paint the current state of the component and nothing else.
The second problem is the fact that both the Timer and the button are calling the same actionPerformed method, which doesn't really make sense. In fact, in a perfect world, you wouldn't implement ActionListener directly like this and instead make use of Anonymous Classes which would guard against outside classes calling the method directly or indirectly.
So, what's the solution? Add a method to your SpaceGame which can be called to start the animation, something like...
public class SpaceGame extends JPanel implements ActionListener {
//The list of spaceships that should be painted
LinkedList<Spaceship> playingList = new LinkedList<Spaceship>();
Timer t = new Timer(5, this);
public void start() {
if (t.isRunning()) {
return;
}
t.start();
}
#Override
public void actionPerformed(ActionEvent e) {
ListIterator<Spaceship> iter = playingList.listIterator();
while (iter.hasNext()) {
Spaceship s = iter.next();
s.moveSpaceship();
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Spaceship s : playingList) {
s.drawSpaceship(g);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
// This is unadvisable :/
fr.setSize(990, 690);
fr.add(game);
game.playingList.add(new Spaceship(3, 0, 570));
game.playingList.add(new Spaceship(1, 250, 570));
game.playingList.add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
game.start();
}
});
fr.add(start, BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
}
Then update your main method to call it...
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SpaceGame game = new SpaceGame();
JFrame fr = new JFrame();
fr.setTitle("SPACE GAME");
// This is unadvisable :/
fr.setSize(990, 690);
fr.add(game);
game.playingList.add(new Spaceship(3, 0, 570));
game.playingList.add(new Spaceship(1, 250, 570));
game.playingList.add(new Spaceship(2, 500, 570));
JButton start = new JButton("START");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
game.start();
}
});
fr.add(start, BorderLayout.SOUTH);
fr.setVisible(true);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
Code: Java Sphere class
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class Sphere extends JPanel {
private boolean flashinglights = false;
private int x = 168;
private int y = 75;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (flashinglights) { //This is the flash option. Here it should change between grey and orange
g2.setColor(Color.ORANGE);
Ellipse2D.Double ball = new Ellipse2D.Double(x, y, 50, 50);
g2.draw(ball);
g2.fill(ball);
} else {
g2.setColor(Color.gray); //This should stay grey as it does now.
Ellipse2D.Double ball = new Ellipse2D.Double(x, y, 50, 50);
g2.draw(ball);
g2.fill(ball);
}
}
public void chooseflashinglights(){ //Ignore these methods
flashinglights = false;
}
public void choosesteady(){
flashinglights = true;
}
public void flickerorange(int d) { y = y + d; }
public void flickergrey(int d) { y = y + d; }
public static void main(String[] args) {
JFrame scFrame = new AnimationViewer();
scFrame.setTitle("Circle");
scFrame.setSize(400, 400);
scFrame.setDefaultCloseOperation((JFrame.EXIT_ON_CLOSE));
scFrame.setVisible(true);
}
}
Animation Viewer Class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AnimationViewer extends JFrame {
JButton jbtFlash = new JButton("Flash");
JButton jbtSteady = new JButton("Steady");
JPanel bPanel = new JPanel();
Sphere sphPanel = new Sphere();
Timer timer;
public AnimationViewer() {
this.add(bPanel, BorderLayout.SOUTH);
bPanel.add(jbtFlash);
bPanel.setLayout(new GridLayout(1,2));
bPanel.add(jbtSteady);
this.add(sphPanel, BorderLayout.CENTER);
jbtSteady.addActionListener(new SteadyLights());
jbtFlash.addActionListener(new FlashingLights());
timer = new Timer(100, new TimerListener());
timer.start();
}
class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
sphPanel.flickerorange(0);
sphPanel.flickergrey(0);
repaint();
}
}
class FlashingLights implements ActionListener{
public void actionPerformed(ActionEvent e){
sphPanel.chooseflashinglights();
}
}
class SteadyLights implements ActionListener{
public void actionPerformed(ActionEvent e){
sphPanel.choosesteady();
}
}
}
So right now there is a sphere that appears on the screen. There are two buttons showed below. Flash and Steady. On the steady button it has to stay one colour (orange) which it does not.
Now on Flash it has to change from Orange to grey every 100 milli seconds.
I know it has to be something to do with Action listeners but how exactly do I implement this?
You have a lot of extra code. I would do it like this. Write flashing logic in paintComponent method. Then create just one timer. On tick call the paintComponent method for every 100ms. On flash button click start the timer, on steady button click stop the timer and call paintComponent once.
Sphere class:
public class Sphere extends JPanel {
private boolean flashinglights = false;
private int x = 168;
private int y = 75;
private Color[] colors = new Color[] {Color.ORANGE, Color.GRAY };
private int colorIndex = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (!flashinglights) {
g2.setColor(Color.ORANGE);
Ellipse2D.Double ball = new Ellipse2D.Double(x, y, 50, 50);
g2.draw(ball);
g2.fill(ball);
} else {
if(colorIndex > colors.length - 1)
colorIndex = 0;
g2.setColor(colors[colorIndex++]);
Ellipse2D.Double ball = new Ellipse2D.Double(x, y, 50, 50);
g2.draw(ball);
g2.fill(ball);
}
}
public void chooseflashinglights(){ //Ignore these methods
flashinglights = true;
}
public void choosesteady(){
flashinglights = false;
}
public static void main(String[] args) {
JFrame scFrame = new AnimationViewer();
scFrame.setTitle("Circle");
scFrame.setSize(400, 400);
scFrame.setDefaultCloseOperation((JFrame.EXIT_ON_CLOSE));
scFrame.setVisible(true);
}
}
AnimationViewer class:
public class AnimationViewer extends JFrame {
JButton jbtFlash = new JButton("Flash");
JButton jbtSteady = new JButton("Steady");
JPanel bPanel = new JPanel();
Sphere sphPanel = new Sphere();
Timer timer;
public AnimationViewer() {
this.add(bPanel, BorderLayout.SOUTH);
bPanel.add(jbtFlash);
bPanel.setLayout(new GridLayout(1,2));
bPanel.add(jbtSteady);
this.add(sphPanel, BorderLayout.CENTER);
timer = new Timer(100, new TimerListener());
jbtSteady.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sphPanel.choosesteady();
timer.stop();
sphPanel.repaint();
}
});
jbtFlash.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sphPanel.chooseflashinglights();
timer.start();
}
});
}
class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
sphPanel.repaint();
}
}
}
I would do things a bit differently.
I'd have a field in my drawing JPanel class that indicates what color should be shown.
For instance, if there are only two colors that are swapped, I'd use a boolean field, and would swap it's value in my timer, and then base the color draw on its value.
The paintComponent method would use that field, the boolean, to decide which Color to use for g.setColor(...).
If many colors are drawn, the field could be a combination of an array of Color together with an int index into the array. Then I'd increment the index as needed, and use the index in paintComponent to decide which color to draw with.
I'd change that field in my Timer's ActionListener -- just a single call to change it, not your strange call to flicker orange and flicker gray.
I'd start the Timer with one button
I'd stop it with the other button. That's all the button's action listener would do, simply start or stop the timer.
I want to have transparent panels in my GUI (if like Windows 7 window headers, it is better).
Before I have used com.sun.awt.AWTUtilities as
AWTUtilities.setWindowOpacity(frame, (float)0.90);
but its parameter is a window like JFrame and couldn't be used for JPanel.
Also I want to have effects on JPanel or JLabel for example luminescence, as is on Windows 7 header buttons. Any other interesting effect is also helpful for me.
Please see the tutorials How to Create Translucent and Shaped Windows and* How to Create Translucent and Shaped Windows*. Follow the links to excellent example depots by #camickr.
For example,
import java.awt.event.*;
import java.awt.Color;
import java.awt.AlphaComposite;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class ButtonTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ButtonTest().createAndShowGUI();
}
});
}
private JFrame frame;
private JButton opaqueButton1;
private JButton opaqueButton2;
private SoftJButton softButton1;
private SoftJButton softButton2;
public void createAndShowGUI() {
opaqueButton1 = new JButton("Opaque Button");
opaqueButton2 = new JButton("Opaque Button");
softButton1 = new SoftJButton("Transparent Button");
softButton2 = new SoftJButton("Transparent Button");
opaqueButton1.setBackground(Color.GREEN);
softButton1.setBackground(Color.GREEN);
frame = new JFrame();
frame.getContentPane().setLayout(new java.awt.GridLayout(2, 2, 10, 10));
frame.add(opaqueButton1);
frame.add(softButton1);
frame.add(opaqueButton2);
frame.add(softButton2);
frame.setSize(567, 350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Timer alphaChanger = new Timer(30, new ActionListener() {
private float incrementer = -.03f;
#Override
public void actionPerformed(ActionEvent e) {
float newAlpha = softButton1.getAlpha() + incrementer;
if (newAlpha < 0) {
newAlpha = 0;
incrementer = -incrementer;
} else if (newAlpha > 1f) {
newAlpha = 1f;
incrementer = -incrementer;
}
softButton1.setAlpha(newAlpha);
softButton2.setAlpha(newAlpha);
}
});
alphaChanger.start();
Timer uiChanger = new Timer(3500, new ActionListener() {
private LookAndFeelInfo[] laf = UIManager.getInstalledLookAndFeels();
private int index = 1;
#Override
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(laf[index].getClassName());
SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception exc) {
exc.printStackTrace();
}
index = (index + 1) % laf.length;
}
});
uiChanger.start();
}
public static class SoftJButton extends JButton {
private static final JButton lafDeterminer = new JButton();
private static final long serialVersionUID = 1L;
private boolean rectangularLAF;
private float alpha = 1f;
public SoftJButton() {
this(null, null);
}
public SoftJButton(String text) {
this(text, null);
}
public SoftJButton(String text, Icon icon) {
super(text, icon);
setOpaque(false);
setFocusPainted(false);
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
repaint();
}
#Override
public void paintComponent(java.awt.Graphics g) {
java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
if (rectangularLAF && isBackgroundSet()) {
Color c = getBackground();
g2.setColor(c);
g.fillRect(0, 0, getWidth(), getHeight());
}
super.paintComponent(g2);
}
#Override
public void updateUI() {
super.updateUI();
lafDeterminer.updateUI();
rectangularLAF = lafDeterminer.isOpaque();
}
}
}
If you have time I recommend you go through this Filty Rich Clients. By using this book you can learn to create stunning visual and animated effects with Swing and Java 2D. Learn graphics and animation fundamentals as well as advanced rendering techniques.
EDIT:
To creat transparent panels call
setOpaque(false)
It'll pass off painting the background to its parent, which may draw its own background.
You can do a screen capture and then use that to paint the background of the panel.
I have the following program which has some very strange and unwanted behavior when it runs. Its supposed to have two buttons, "Start" and "Stop, but when I click "Start" another button shows up right below "Start". Here's a print screen of what I'm talking about:
What am I doing wrong and how do I fix this ugly problem?
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class TwoButtonsTest {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
TwoButtonsTest test = new TwoButtonsTest();
test.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
final DrawPanel myDraw = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, myDraw);
frame.getContentPane().add(BorderLayout.NORTH, startButton);
frame.getContentPane().add(BorderLayout.SOUTH, stopButton);
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
if(!isClicked) {
}
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
int red = (int)(Math.random()*256);
int blue = (int)(Math.random()*256);
int green = (int)(Math.random()*256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth()-wd);
int y = rand.nextInt(getHeight()-ht);
g.fillRect(x,y,wd,ht);
}
} // close inner class
}
Also I'm trying to get the Start button to do two things. One is to of course start the animation but when the Stop button is pressed and I press Start again, I want it to clean the screen so to speak and start the animation again a new. Any tips on that?
You do not call super.paintComponent(Graphics g) in overriden paintComponent(..) method which you should in order to honor the paint chain and thus the painting of other components.
This call should also be the first call within the method:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//do painting here
}
A probem might arise that drawings are not persistent. You must than have a way to store drawings and redraw every time. The most common is an ArrayList which will hold objects to be drawn (thus you cann add to the list remove etc), you would than iterate over the list and redraw each object in paintComponent. See my answer here for an example.
Also please remember to create and manipulate Swing components on Event Dispatch Thread :
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create UI and components here
}
});
Dont call setSize(..) on JFrame rather override getPreferredSize() of JPanel and return an appropriate height which fits all components, than call JFrame#pack() before setting JFrame visible (but after adding all components).
No need for getContentPane().add(..) as of Java 6+ add(..) defaults to contentPane
Do not re declare Random i.e Random r=new Random() each time paintComponent is called as this will make the distributions of the values less random rather initiate it once when class is created and call methods on the instance
Here is the fixed code (with above fixes implemented):
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class TwoButtonsTest {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TwoButtonsTest test = new TwoButtonsTest();
test.go();
}
});
}
final DrawPanel myDraw = new DrawPanel();
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
frame.add(myDraw, BorderLayout.CENTER);
frame.add(startButton, BorderLayout.NORTH);
frame.add(stopButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//needs to be implemented
if (!isClicked) {
}
myDraw.clearRects();
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
private ArrayList<MyRectangle> rects = new ArrayList<>();
private Random rand = new Random();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
addRect();
for (MyRectangle r : rects) {
g.setColor(r.getColor());
g.fillRect(r.x, r.y, r.width, r.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public void clearRects() {
rects.clear();
}
public void addRect() {
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
rects.add(new MyRectangle(x, y, wd, ht, new Color(red, blue, green)));
}
} // close inner class
}
class MyRectangle extends Rectangle {
Color color;
public MyRectangle(int x, int y, int w, int h, Color c) {
super(x, y, w, h);
this.color = c;
}
public Color getColor() {
return color;
}
}
I wish I could offer a solution, but as of yet I haven't found one. I can tell you the root of the "problem" here lies in the way you are drawing the Center section of your BorderLayout. You are overriding the whole paintComponent() function for this program and having whatever it creates put into the Center of your BoarderLayout. In this case, each time you click a button, the program calls the repaint to draw the image of a clicked button, but since you have also added ANY of the drawn objects to the Center panel, it also is drawn there. Since this specific repaint doesn't specify a location, it goes in the upper left corner.
I fixed your button problem on my Windows XP computer by invoking SwingUtilities.
I formatted your Java code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TwoButtonsTest implements Runnable {
JFrame frame;
Timer timer;
boolean isClicked;
public static void main(String[] args) {
SwingUtilities.invokeLater(new TwoButtonsTest());
}
#Override
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JButton startButton = new JButton("Start");
startButton.addActionListener(new StartListener());
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
final DrawPanel myDraw = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, myDraw);
frame.getContentPane().add(BorderLayout.NORTH, startButton);
frame.getContentPane().add(BorderLayout.SOUTH, stopButton);
frame.setVisible(true);
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
myDraw.repaint();
}
});
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// needs to be implemented
if (!isClicked) {
}
isClicked = true;
timer.start();
}
}
class StopListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// needs to be implemented
timer.stop();
isClicked = false;
}
}
class DrawPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
g.fillRect(x, y, wd, ht);
}
} // close inner class
}
To clean the screen when you press the Start button, you're going to have to add some methods to your DrawPanel class.
Here's one way to do it.
class DrawPanel extends JPanel {
protected boolean eraseCanvas;
public void setEraseCanvas(boolean eraseCanvas) {
this.eraseCanvas = eraseCanvas;
}
#Override
public void paintComponent(Graphics g) {
if (eraseCanvas) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
} else {
int red = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
g.setColor(new Color(red, blue, green));
Random rand = new Random();
// following 4 lines make sure the rect stays within the frame
int ht = rand.nextInt(getHeight());
int wd = rand.nextInt(getWidth());
int x = rand.nextInt(getWidth() - wd);
int y = rand.nextInt(getHeight() - ht);
g.fillRect(x, y, wd, ht);
}
}
} // close inner class
I have to use both AWT and Swing component in my application. At displaying the AWT first appear on the screen then come the Swing component (with LAF style)
Is it possible that and make them appear simutaneously ? Like before paint, a kind of buffer ?
Thank you
1) since as of the JDK 6 update 12 and JDK7 build 19 releases, you can seamlessly mix heavyweight (AWT) and lightweight (Swing) components,But I don't suggest mixing AWT with Swing,
2) its hard change Look and Feel for AWT Components, I never saw good one, by default is there Look and Feel that came from Native OS, Look and Feel is about usage Swing JComponents
3) since is possible put JComponents with different Look and Feel, I'd suggest to create something similair
import java.awt.event.*;
import java.awt.Color;
import java.awt.AlphaComposite;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class ButtonTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ButtonTest().createAndShowGUI();
}
});
}
private JFrame frame;
private JButton opaqueButton1;
private JButton opaqueButton2;
private SoftJButton softButton1;
private SoftJButton softButton2;
public void createAndShowGUI() {
opaqueButton1 = new JButton("Opaque Button");
opaqueButton2 = new JButton("Opaque Button");
softButton1 = new SoftJButton("Transparent Button");
softButton2 = new SoftJButton("Transparent Button");
opaqueButton1.setBackground(Color.GREEN);
softButton1.setBackground(Color.GREEN);
frame = new JFrame();
frame.getContentPane().setLayout(new java.awt.GridLayout(2, 2, 10, 10));
frame.add(opaqueButton1);
frame.add(softButton1);
frame.add(opaqueButton2);
frame.add(softButton2);
frame.setSize(567, 350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Timer alphaChanger = new Timer(30, new ActionListener() {
private float incrementer = -.03f;
#Override
public void actionPerformed(ActionEvent e) {
float newAlpha = softButton1.getAlpha() + incrementer;
if (newAlpha < 0) {
newAlpha = 0;
incrementer = -incrementer;
} else if (newAlpha > 1f) {
newAlpha = 1f;
incrementer = -incrementer;
}
softButton1.setAlpha(newAlpha);
softButton2.setAlpha(newAlpha);
}
});
alphaChanger.start();
Timer uiChanger = new Timer(3500, new ActionListener() {
private LookAndFeelInfo[] laf = UIManager.getInstalledLookAndFeels();
private int index = 1;
#Override
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(laf[index].getClassName());
SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception exc) {
exc.printStackTrace();
}
index = (index + 1) % laf.length;
}
});
uiChanger.start();
}
public static class SoftJButton extends JButton {
private static final JButton lafDeterminer = new JButton();
private static final long serialVersionUID = 1L;
private boolean rectangularLAF;
private float alpha = 1f;
public SoftJButton() {
this(null, null);
}
public SoftJButton(String text) {
this(text, null);
}
public SoftJButton(String text, Icon icon) {
super(text, icon);
setOpaque(false);
setFocusPainted(false);
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
repaint();
}
#Override
public void paintComponent(java.awt.Graphics g) {
java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
if (rectangularLAF && isBackgroundSet()) {
Color c = getBackground();
g2.setColor(c);
g.fillRect(0, 0, getWidth(), getHeight());
}
super.paintComponent(g2);
}
#Override
public void updateUI() {
super.updateUI();
lafDeterminer.updateUI();
rectangularLAF = lafDeterminer.isOpaque();
}
}
}