Java Animate JLabel - java

So I am creating a basic application that I want to have a JLabel at the bottom of the screen that starts at the left bottom corner and moves, animation style, to the right bottom corner in a set time, and a static image in the center. To do this, I created a JFrame with a JPanel using BorderLayout. There is a JLabel with an ImageIcon added to BorderLayout.CENTER and a JPanel at BorderLayout.SOUTH. My code, while hastily written and far from pretty, is:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.BorderFactory;
public class GameWindow extends JPanel{
private static JLabel mainWindow, arrowLabel, arrowBox;
protected static JFrame frame;
protected static JPanel arrows;
public static int x = 600;
public GameWindow(){
mainWindow = new JLabel("Center");
arrowLabel = new JLabel("Moving");
arrows = new JPanel();
arrows.setSize(600, 100);
arrows.setLayout(null);
arrowBox = new JLabel("");
arrowBox.setBounds(0, 0, 150, 100);
arrowBox.setPreferredSize(new Dimension(150, 100));
arrowBox.setBorder(BorderFactory.createLineBorder(Color.black));
arrows.add(arrowBox);
this.setSize(600,600);
this.setLayout(new BorderLayout());
this.add(mainWindow, BorderLayout.CENTER);
this.add(arrows, BorderLayout.SOUTH);
}
public static void main(String[] args)
{
GameWindow g = new GameWindow();
frame = new JFrame("Sword Sword Revolution");
frame.add(g);
frame.setSize(600,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Timer t = new Timer(1000, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
arrows.add(arrowLabel);
arrowLabel.setBounds(x, 100, 100, 100);
x-=50;
arrows.repaint();
frame.repaint();
}
});
t.start();
}
}
The ImageIcon in the center JLabel appears fine, and the empty JLabel with a border appears at the bottom, but I cannot get the second JLabel with the arrow image to show up on screen. Eventually I will change to scheduleAtFixedRate to continuously move the JLabel, but right now I can't even get the image to appear on screen.
I also understand that I will most likely not be able to use FlowLayout for this, as I understand it does not allow you to set the location of your components. I tried using null layout, but with null layout the empty JLabel with a border does not appear. I can barely make out the top of the border at the bottom edge of the frame, but even with setLocation I cannot get it to appear where I want it to.
Obviously, my thought process is flawed, so any help would be appreciated.

Your use of threading is all wrong for Swing applications. You should not be trying to add or remove components in a background thread but instead should use a Swing Timer to do this on the Swing event thread.
Also, what do you mean by:
I want to have a scrolling JLabel at the bottom of the screen
Please clarify the effect you're trying to achieve.
Also regarding,
I also understand that I will most likely not be able to use FlowLayout for this, as I understand it does not allow you to set the location of your components. I tried using null layout, but with null layout the empty JLabel with a border does not appear. I can barely make out the top of the border at the bottom edge of the frame, but even with setLocation I cannot get it to appear where I want it to.
No, don't use null layout for this situation. There are much better layout managers that can help you build your application in a cleaner more platform-independent manner.
Edit 3
Regarding:
To clarify, at the bottom of the screen I want a JLabel at the far right corner, then in the swing timer, the JLabel will gradually move to the left until it leaves the screen. If I could get setLocation to work, the basic premise would be to have a variable x set to 600, and then every second decrement x by say 50 and then redraw the JLabel at the new location on the screen. Basic animation.
I would create a JPanel for the bottom of the screen for the purposes of either holding your JLabel or displaying the image without a JLabel by overriding its paintComponent(...) method. If you use it as a container, then yes, its layout should be null, but the rest of the GUI should not be using null layout. The Swing Timer would simply change the JLabel's location and then call repaint() on its JPanel/container. If you go the latter route, you would draw the image in the JPanel's paintComponent(...) method using g.drawImage(myImage, x, y), and your timer would change x and/or y and call repaint() on the drawing JPanel.
Also, you likely do not want to keep adding a JLabel in your timer but rather simply moving the JLabel that's already displayed in the GUI.
Also, to avoid focus issues, don't use a KeyListener to capture keystroke input but rather use Key Bindings. Google will direct you to a great tutorial on this construct.
Edit 4
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.EnumMap;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class AnimateExample extends JPanel {
public static final String DUKE_IMG_PATH =
"https://duke.kenai.com/iconSized/duke.gif";
private static final int PREF_W = 800;
private static final int PREF_H = 800;
private static final int TIMER_DELAY = 20;
private static final String KEY_DOWN = "key down";
private static final String KEY_RELEASE = "key release";
public static final int TRANSLATE_SCALE = 3;
private static final String BACKGROUND_STRING = "Use Arrow Keys to Move Image";
private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF,
Font.BOLD, 32);
private EnumMap<Direction, Boolean> dirMap =
new EnumMap<AnimateExample.Direction, Boolean>(Direction.class);
private BufferedImage image = null;
private int imgX = 0;
private int imgY = 0;
private int bgStringX;
private int bgStringY;
public AnimateExample() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
try {
URL imgUrl = new URL(DUKE_IMG_PATH);
image = ImageIO.read(imgUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
new Timer(TIMER_DELAY, new TimerListener()).start();
// here we set up our key bindings
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (final Direction dir : Direction.values()) {
// for the key down key stroke
KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0,
false);
inputMap.put(keyStroke, dir.name() + KEY_DOWN);
actionMap.put(dir.name() + KEY_DOWN, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, true);
}
});
// for the key release key stroke
keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);
inputMap.put(keyStroke, dir.name() + KEY_RELEASE);
actionMap.put(dir.name() + KEY_RELEASE, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, false);
}
});
}
FontMetrics fontMetrics = getFontMetrics(BG_STRING_FONT);
int w = fontMetrics.stringWidth(BACKGROUND_STRING);
int h = fontMetrics.getHeight();
bgStringX = (PREF_W - w) / 2;
bgStringY = (PREF_H - h) / 2;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setFont(BG_STRING_FONT);
g.setColor(Color.LIGHT_GRAY);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString(BACKGROUND_STRING, bgStringX, bgStringY);
if (image != null) {
g.drawImage(image, imgX, imgY, this);
}
}
private class TimerListener implements ActionListener {
public void actionPerformed(java.awt.event.ActionEvent e) {
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
imgX += dir.getX() * TRANSLATE_SCALE;
imgY += dir.getY() * TRANSLATE_SCALE;
}
}
repaint();
};
}
enum Direction {
Up(KeyEvent.VK_UP, 0, -1), Down(KeyEvent.VK_DOWN, 0, 1), Left(
KeyEvent.VK_LEFT, -1, 0), Right(KeyEvent.VK_RIGHT, 1, 0);
private int keyCode;
private int x;
private int y;
private Direction(int keyCode, int x, int y) {
this.keyCode = keyCode;
this.x = x;
this.y = y;
}
public int getKeyCode() {
return keyCode;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private static void createAndShowGui() {
AnimateExample mainPanel = new AnimateExample();
JFrame frame = new JFrame("Animate Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which will create this GUI:

Three possibilities:
You can either use a library like SlidingLayout to create such transition with very few lines of code. You won't be able to tweak the animation but your life will be easier.
You can use an animation engine like the Universal Tween Engine to configure everything by hand and tweak the animation as much as you want (the first lib uses this one under the hood). Using such engine, you can animate what you want: positions, colors, font size, ...
You can code everything by hand and embrace the hell that is the animation world :)
In the end, you'll be able to quickly create animations like these (it's a tool I'm currently working on, used to configure eclipse projects for android dev using the LibGDX game framework):
I made these libraries to ease the pain that is UI animation (I love UI design :p). I released them open-source (free to use, license apache-2), hoping they may help some people too.
If you need help, there is a dedicated help forum for each library.

Very simple, look at this:
javax.swing.JLabel lb = new javax.swing.JLabel();
Image image = Toolkit.getDefaultToolkit().createImage("Your animated GIF");
ImageIcon xIcon = new ImageIcon(image);
xIcon.setImageObserver(this);
lb.setIcon(xIcon);

Related

When i interchange the commented lines , i receive different output.

I am learning java abstract window toolkit and i am stuck in this code.When i interchange the commented line, the output changes.Any Explanation for both the cases will be appreciated.
import java.awt.*;
public class guibutton
{
public guibutton()
{
Frame f = new Frame("Panel Example");
Panel panel = new Panel();
panel.setBounds(40,80,200,200);
panel.setBackground(Color.gray);
f.add(panel);
f.setVisible(true); ////////////////this line
f.setLayout(null); /////////////////this line
f.setResizable(true);
f.setSize(400,400);
}
public static void main(String args[])
{
new guibutton();
}
}
This line:
f.setVisible(true);
renders your GUI in its current state, one where the JFrame's default BorderLayout is in force. Note that BorderLayout ignores the setBounds(...) method.
This line:
f.setLayout(null);
removes the JFrame contentPane's BorderLayout, and so your GUI is rendered without the layout, changing the positioning of the added JPanel -- the setBounds(...) method call here is respected.
If you call this after the GUI has been rendered, it won't have an effect, unless you do something that triggers the layout managers to re-layout the components, such as re-size the GUI.
Myself, I wouldn't use AWT but would use Swing, I'd draw the rectangle within the paintComponent method of a JPanel, using a Rectangle object. This way, I could monitor the mouse in relation to the rectangle, and change its state. For instance, try out this program, and see what happens to the rectangle when the mouse hovers over it:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class GuiButton2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int RECT_X = 40;
private static final int RECT_Y = 80;
private static final int RECT_W = 200;
private static final Color DEFAULT_RECT_COLOR = Color.GRAY;
private static final Color HOVER_RECT_COLOR = Color.PINK;
private Rectangle rectangle = new Rectangle(RECT_X, RECT_Y, RECT_W, RECT_W);
private boolean hover = false;
public GuiButton2() {
setPreferredSize(new Dimension(PREF_W, PREF_H));
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// hover true if mouse is hovering over the rectangle
hover = rectangle.contains(e.getPoint());
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// if hover true -- use hover color, otherwise use default color
Color c = hover ? HOVER_RECT_COLOR : DEFAULT_RECT_COLOR;
g2.setColor(c);
g2.fill(rectangle); // draw rectangle
}
private static void createAndShowGui() {
GuiButton2 mainPanel = new GuiButton2();
JFrame frame = new JFrame("GUI Button");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Side note 1:
While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Side note 2:
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.

Action listener, to change images on click.

I have some images that i need to change on click, right now there is only three images of each category, 3 noses, 3 eyes and 3 mouths. So i took this approach to my solution, however i realize this is not the best way to go about it because the number of images is hard coded i would like it to change dinamically. Im in need of some ideas, or suggestions.
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class ImagePanel extends JPanel {
/**
* Create the panel.
*/
private int nose = 1;
private int mouth = 1;
private int eyes = 1;
Color[] color ={Color.BLUE, Color.RED, Color.PINK,Color.CYAN,Color.WHITE};
static int colorCounter =1 ;
public ImagePanel() {
}
public void changeNose(){
nose = ++nose % 3;
nose++;
}
public void changeMouth(){
mouth = ++mouth % 3;
mouth++;
}
public void changeEyes(){
eyes = ++ eyes % 3;
eyes++;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.green);
g.setColor(color[colorCounter]);
g.fillOval(40, 120, 400, 400);
ImageIcon hat = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/santa.png"));
hat.paintIcon(this, g, 160, 3);
ImageIcon eyes1 = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/eyes"+eyes+".png"));
eyes1.paintIcon(this, g,180, 200);
ImageIcon nose1 = new ImageIcon(ImagePanel.class.getResource("/a06Face/Images/nose"+nose+".png"));
nose1.paintIcon(this, g, 180, 300);
ImageIcon mouth1 = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/mouth"+mouth+".png"));
mouth1.paintIcon(this, g, 170, 400);
repaint();
}
}
You could use a MouseListener.
How to do this:
//in your Class constructor
public XYZ()
{
.....
Timer t = new Timer(0,new Listener());
t.start();
addMouseListener(new Mouse());
// later in program
private class Mouse extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
<object>.doMethod(e.<otherMethod>);
}
}
This is just how to use a generic MouseListener. Modify this to fit your program.
Well, let's try this out. Let's define an instance field which holds all the image items in our system. This may be something like,
private List<ImageIcon> imgIcons = new ArrayList<ImageIcon>;
Then write a method to add image icons to this list. It may look like this.
private void addImageIcon(ImageIcon imgIcon){
this.imgIcons.add(imgIcon);
}
Call this method from anywhere you need to add the images. Then you can get the size of the array when you need to count the number of images in this panel. Hope this helps. Happy Coding !

How do I add a button to Canvas without letting the button resize?

I'm working on a login screen for my game. I have a total of two images on it. One is a splash screenshot and the other is the background image. I'm using BufferedImages to render the images to the screen.
The problem I get is that when I add a standard button to the Canvas, the button takes up the whole window, and evidently, I don't want that.
I would post a picture, but alas, I do not have "enough reputation" to do that. Here's a look at my code though:
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.TextField;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Login extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 495;
private static final int HEIGHT = 307;
private static final int SCALE = 2;
private final Dimension size = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
public int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
private BufferedImage splash = new BufferedImage(315, 177, BufferedImage.TYPE_INT_RGB);
public int[] splashPixels = ((DataBufferInt) splash.getRaster().getDataBuffer()).getData();
private Thread thread;
public static boolean isRunning = false;
JFrame frame;
MainMenu menu;
Splash splashscreen;
Button login;
Button register;
TextField username;
private Login() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception exc) {
exc.printStackTrace();
}
frame = new JFrame("Game Login");
menu = new MainMenu(WIDTH, HEIGHT, "/login/login_screen.png");
splashscreen = new Splash(315, 177, "/login/splash.png");
frame.setSize(size);
frame.setVisible(true);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
setPreferredSize(size);
frame.add(this);
login = new Button("Login");
login.setBounds(0, 0, getWidth(), getHeight());
frame.add(login);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void begin() {
createBufferStrategy(2);
thread = new Thread(this);
thread.start();
isRunning = true;
}
private void finish() throws InterruptedException {
isRunning = false;
thread.join();
}
private void updateLogin() {
for (int a = 0; a < pixels.length; a++) {
pixels[a] = menu.pixels[a];
}
}
private void renderLogin() {
BufferStrategy buffer = getBufferStrategy();
Graphics gfx = buffer.getDrawGraphics();
for (int a = 0; a < splashPixels.length; a++) {
splashPixels[a] = splashscreen.splashPixels[a];
}
gfx.drawImage(image, 0, 0, getWidth(), getHeight(), null);
gfx.drawImage(splash, 320, 37, 625, 340, null);
gfx.setColor(Color.WHITE);
gfx.drawString("Game Co © 2013", 3, (getHeight() - 4));
gfx.drawString("\"Game\" is a trademark of Blah-Blah-Blah.", (getWidth() - 268), (getHeight() - 3));
gfx.dispose();
buffer.show();
}
public void run() {
while (isRunning == true) {
updateLogin();
renderLogin();
}
try {
finish();
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) {
Login login = new Login();
login.begin();
}
}
Once again, my only problem is that I keep getting a enlarged button.
Thanks in advance, I know you guys are busy and whatnot and I appreciate taking the time to look over and help answer my questions.
P.S. Does anyone know how to make a password field with AWT? I'll also need that too. ;)
Solution: add your JButton (again use Swing components) First to a JPanel (which uses FlowLayout by default), and then add that to the top level window.
You could just change the layout manager for your frame to a FlowLayout so it will behave like a JPanel.
frame.setLayout(new FlowLayout());
You state:
The problem I get is that when I add a standard button to the Canvas, the button takes up the whole window, and evidently, I don't want that.
You're trying to add a component directly to a container that is using BorderLayout, likely the contentPane of a top-level window, and so by default it is added BorderLayout.CENTER and fills the container.
Solution: add your JButton (again use Swing components) First to a JPanel (which uses FlowLayout by default), and then add that to the top level window.
Again, there's no need to mix AWT and Swing components and there are in fact strong arguments not to do so. I suggest that you stick with all Swing components for your GUI.
Does anyone know how to make a password field with AWT? I'll also need that too. ;)
Again, don't use AWT but instead use a Swing JPasswordField.

Dynamically change Background Image of a JPanel

Trying ti change the BG image of a jpanel but i cant call poaint on any normal method, it works great when i'm building the constructor but i don't want to rebuild the constructor.
....
Sort of found a solution by putting a label in my center frame and calling setIcon but i need to be able to pull the relelevant info so i need to find a way to store a value into my Jtoggle button (the id of the Race or class so i can fetch it's picture and change the icon)
thoughts? Everything compiles outside the iff statement which is my sticking point
RaceButtons_lft[i] = new JToggleButton();
RaceButtons_lft[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JToggleButton cb = (JToggleButton)ae.getSource();
for (int j=0; j<MyRaceArray.size(); j++)
{
if (MyRaceArray.get(j).getraceID() == combo_contents.getIndex()){//here is my sticking point, i need to find a way to match MyRaceArray's getRaceID to some value saved withthe Toggle button
final ImageIcon BGCSMs = ScaledImageIcon("Fantasy_Landscape_01.jpg", "Profile Pic", (468-(60*2)), 285);
picLabel.setIcon(BGCSMs);
}//if
}//for
}//action performed;
});//button add action listener
Calling
super.paintComponent(..)
will probably - depending on the super class - fill the component with the background color.
public void paintComponent(Graphics g) {
// Let UI Delegate paint first, which
// includes background filling since
// this component is opaque.
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
redSquare.paintSquare(g);
}
(see A Closer Look at the Paint Mechanism). You don't need repaint(..) in this case.
You could be suffering from a number of problems, which we can't see because we don't have enough context...
You could have a reference issue, instead of trying to repaint the component on the screen, you've inadvertently gotten the wrong reference...
You could be shadowing your variables...
You could be painting to a opaque component...
Assuming that the code you have posted is linear (ie, it appears in you code in this exact order or close enough to it), I can see one possible problem...
ImageIcon RCicon = createImageIcon(temp_race.getActiveHeadshot(), temp_race.getRaceNameString(race.getraceID()));
Image RCimg = RCicon.getImage();
RCimg = RCimg.getScaledInstance((468-(60*2)), 285, java.awt.Image.SCALE_SMOOTH);
portraitCenterOptions.setBackground(Color.White){
protected void paintComponent(Graphics h)
{
//...//
// There is no way that this reference can be valid...
// The image created above will only have a local reference unto itself
// suggestion that you're shadowing your variables...
final ImageIcon bodypicSM = new ImageIcon(RCimg);
//...//
}
};
But without a working example, it's impossible to know...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ChangeBackground {
public static void main(String[] args) {
new ChangeBackground();
}
public ChangeBackground() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final PaintPane pane = new PaintPane();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(pane);
JButton change = new JButton("Change");
change.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pane.changeBackground();
pane.repaint();
}
});
frame.add(change, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private BufferedImage bg;
private int changes = 0;
public PaintPane() {
changeBackground();
}
public void changeBackground() {
bg = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bg.createGraphics();
FontMetrics fm = g.getFontMetrics();
g.setColor(getForeground());
String[] text = {
"I've been changed " + changes + " times",
"Last changed at " + DateFormat.getDateTimeInstance().format(new Date())};
int y = (200 - (fm.getHeight() * 2)) / 2;
for (String value : text) {
int x = (200 - fm.stringWidth(value)) / 2;
g.drawString(value, x, y + fm.getAscent());
y += fm.getHeight();
}
g.dispose();
changes++;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - bg.getWidth()) / 2;
int y = (getHeight() - bg.getHeight()) / 2;
g.drawImage(bg, x, y, this);
}
}
}
Call repaint() on the component after you have finished your changes to the background
so ultimately tried a few thing and just got lazy, added a label in the center and called "SetIcon, does what I need it to do, thanks for the ideas though.

How do I order two components in a JFrame in order for transparency and ActionListeners to work?

When adding two components to a JFrame, where one sits inside another, If I add them in the order, Fullscreen Object, then JPanel, the JPanel displays correctly, but is essentially invisible, i.e it's action listener won't work and the clicks register on the fullscreen object. If I add them the other way round The JPanel works as it should, but doesn't display correctly (It has transparent areas).
This is the code for the Frame I am adding the components to.
gameOBJ = new gameClass(width, height);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(0);
frame.add(gameOBJ.UIPanel);
frame.add(gameOBJ);
frame.validate();
frame.setUndecorated(true);
frame.setBounds(0, 0, width, height);
frame.setResizable(false);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
new exitWindow("Don't forget to save your game! \n Are you sure you want to Exit?", true);
}
});
frame.setVisible(true);
gameOBJ.start();
Here is the code for the JPanel (Stripped down for simplicity's sake)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class UserInterface extends JPanel implements ActionListener
{
private static final long serialVersionUID = 1L;
private Image image;
private int xBound = 800;
private int yBound = 177;
private JButton mainMenuButton = new JButton(new ImageIcon("res/images/MainMenuButton.gif"));
private int buttonWidth = 179;
private int buttonHeight = 52;
public UserInterface()
{
this.setLayout(null);
this.image = new ImageIcon("res/images/UIPanelImage.gif").getImage();
this.setOpaque(false);
this.setSize(this.xBound, this.yBound);
mainThreeButtons(); //ONLY ONE SHOWN FOR SIMPLICITY
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, this); //IMAGE CONTAINS TRANSPARENCY
}
#Override
public void actionPerformed(ActionEvent event)
{
else if (event.getSource() == mainMenuButton)
{
new mainMenuWindow();
}
}
private void mainThreeButtons()
{
this.add(mainMenuButton);
mainMenuButton.addActionListener(this);
//mainMenuButton.setOpaque(false);
mainMenuButton.setBorderPainted(false);
mainMenuButton.setContentAreaFilled(false);
mainMenuButton.setBounds(617, 6, buttonWidth, buttonHeight);
}
}
I would show an image but I'm not allowed to, The area which is meant to be transparent isn't showing the frame, because it is grey, whatever I set as the Frame's background, OR the panel's background, as again it is grey whatever I set the panel's background colour as.
You probably want to use JLabel instead of JPanel. I know it sounds a bit unintuitive, but I'm not sure JPanel is suited to the purpose you are using it for. Also, JLabel can have a native ImageIcon set, so try using that.
public UserInterface() { // extends JLabel
this.setImageIcon(new ImageIcon("res/images/UIPanelImage.gif"));
// or super(~imageicon~)
}
Unlikely, but it could be that the image is not yet loaded when it gets drawn. You should use MediaTracker to manage that more carefully (although I'm not sure ImageIcon if takes care of this for you).
final static protected MediaTracker mediatracker = new MediaTracker(new Canvas());
static protected void checkImageIsReady(Image i) {
mediatracker.addImage(i, 1);
try {
mediatracker.waitForAll();
} catch (InterruptedException e) { }
mediatracker.removeImage(i);
}

Categories

Resources