How to change image of a JLabel in another thread - java

I want to make a Swing version TimeBomber, which means when time is counted down to 1 the Bomb will blow up! I have two images, images.png for a bomb in normal state, bomber.jpg for a bomb that has blown up. Apparently I need to change the images.png(which is already in an JLabel) to bomber.jpg when i==1; But I have no idea of how to change the pic location content in ImageIcon and as the change happens in anonymous inner class, so change value became difficult as final type var is not modifiable unless you call function.
public class TimeBomber {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
//create Jframe
JFrame app = new JFrame("Time Bomber");
//create JPanel
final JPanel panel = new JPanel();
//JLabel with first Picture
JLabel pic = new JLabel(new ImageIcon("images.png"));
pic.setSize(100, 100);
//Label for displaying time digit
final JLabel label = new JLabel("");
label.setLocation(200, 250);
//create another thread
Thread time = new Thread(){
public void run(){
for(int i=10; i>0; i--){
if(i==1){
JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));
//<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
picSecond.setSize(100, 100);
panel.add(picSecond);
}
label.setText("Time: "+i);
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
//add every component to where it belongs
panel.add(pic);
panel.add(label);
app.add(panel);
app.setSize(300, 400);
app.setVisible(true);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
time.start();
}
}

Wrap the code in SwingUtilities.invokeAndWait() (or SwingUtilities.invokeLater())
if(i==1){
JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));//<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
picSecond.setSize(100, 100);
panel.add(picSecond);
}
label.setText("Time: "+i);
TO avoid recreation of the JLabel make it the class' field and add to panel just once. Then use picSecond.setIcon() to update the image.
BTW it's better to have kind of images cache to avoid image recreation on each step.

Related

How to overlap a JPanel(background) and a JTextField

I am creating a log in application for someones graduation, I need several text fields and a background, I have added the background and now need to add the text fields, the problem is that they won't seem to go on top of each other.
I have tried them each separately and without one another they both work perfectly but i can't get them to stack, I have seen several answers on this site to deal with a similar problem but for this application I need to put several text fields on the background as apposed to just one, here is what I have thus far...
//creates the frame with a title as a parameter
JFrame frame = new JFrame("Sign In Sheet");
//sets the size
frame.setSize(1000, 556);
//makes it so the application stops running when you close it
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//puts it in the center of the screen
frame.setLocationRelativeTo(null);
//makes it so you can't resize it
frame.setResizable(false);
//setting the background by looking for the image
try{
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Users/Gabriel R. Warner/Desktop/clouds.png")))));
}catch(IOException e){
//and prints an error message if it's not found
System.out.println("well it didn't work");
}
//adding text fields with names apropriate to function
JTextField name1 = new JTextField();
name1.setPreferredSize(new Dimension(200, 15));
name1.setBackground(Color.WHITE);
frame.add(name1);
//makes frame visible
frame.setVisible(true);
Simply stated the text field won't show up with the background and all the results only offer answers for a single text field
The problem is in this line: frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Users/Gabriel R. Warner/Desktop/clouds.png")))));
In this line you set a JLabel as the content pane of your JFrame. Then, you frame.add(name1); So you are adding a JTextField to a JLabel...Well this does not seem right, right?
The answer would be to create a new JPanel, add the background image to this panel, set the panel as the content pane of the frame and finally add the textfield to the panel/contentpane.
An example:
#SuppressWarnings("serial")
public class FrameWithBackgroundImage extends JFrame {
public FrameWithBackgroundImage() {
super("Sign In Sheet");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
try {
Image bgImage = loadBackgroundImage();
JPanel backgroundImagePanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bgImage, 0, 0, null);
}
};
setContentPane(backgroundImagePanel);
} catch (IOException e) {
e.printStackTrace();
}
JTextField textField = new JTextField(10);
add(textField);
}
private Image loadBackgroundImage() throws IOException {
File desktop = new File(System.getProperty("user.home"), "Desktop");
File image = new File(desktop, "img.jpg");
return ImageIO.read(image);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new FrameWithBackgroundImage().setVisible(true);
});
}
}
Preview:
Worth to read question: Simplest way to set image as JPanel background

JFrame setContentPane hides other components

So I'm going into GUI's in Java, and am trying to create a simple main menu for a timer. All is well until I've attempted to add a background for the GUI. Adding the background works, however all other components are now gone, (the button). How could I fix this?
EDIT: Here is my new code.
public class MainMenu {
// JFrame = the actual menu / frame.
private JFrame frame;
// JLabel = provides text instructions or information on a GUI —
// display a single line of read-only text, an image or both text and an image.
private JLabel background;
// JButton = button.
private JButton alarmClockButton;
// Constructor to create menu
public MainMenu() {
frame = new JFrame("Alarm Clock");
alarmClockButton = new JButton("Timer");
// Add an event to clicking the button.
alarmClockButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO: CHANGE TO SOMETHING NICER
JOptionPane.showMessageDialog(null, "This feature hasn't been implemented yet.", "We're sorry!",
JOptionPane.ERROR_MESSAGE);
}
});
// Creating the background
try {
background = new JLabel(new ImageIcon(ImageIO.read(getClass()
.getResourceAsStream("/me/devy/alarm/clock/resources/Background.jpg"))));
} catch (IOException e) {
e.printStackTrace();
}
frame.setLayout(new FlowLayout());
frame.setContentPane(background);
frame.add(alarmClockButton);
frame.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
frame.setVisible(true);
frame.setSize(450, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
alarmClockButton.setForeground(Color.RED);
}
}
Thank you!
frame.setContentPane(background);
You use the label as the content pane. The problem is that the label doesn't use a layout manager by default.
You need to add:
background.setLayout( new BorderLayout() ); // or whatever layout you want
frame.setContentPane(background);
Now you can add the button directly to the frame. You don't need the panel.
Or if you want to get fancy you can use the Background Panel which gives you the option to scale or tile the background image.
Instead of making the ContentPane as JLabel, you can wrap the JLabel in a JPanel, then add this JPanel as the ContentPane :
public class MainMenu {
public static void main(String[] args) {
new MainMenu();
}
// JFrame = the actual menu / frame.
private JFrame frame;
private JPanel panel;
private JPanel bkgPanel;
// JLabel = provides text instructions or information on a GUI —
// display a single line of read-only text, an image or both text and an
// image.
private JLabel background;
// JButton = button.
private JButton alarmClockButton;
// Constructor to create menu
public MainMenu() {
frame = new JFrame("Alarm Clock");
panel = new JPanel();
bkgPanel = new JPanel();
alarmClockButton = new JButton("Timer");
// Add an event to clicking the button.
alarmClockButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO: CHANGE TO SOMETHING NICER
JOptionPane.showMessageDialog(null, "This feature hasn't been implemented yet.", "We're sorry!",
JOptionPane.ERROR_MESSAGE);
}
});
// Creating the background
try {
background = new JLabel(new ImageIcon(
ImageIO.read(getClass().getResourceAsStream("/me/devy/alarm/clock/resources/Background.jpg"))));
bkgPanel.add(background);
} catch (IOException e) {
e.printStackTrace();
}
frame.setContentPane(bkgPanel);
frame.add(panel);
panel.add(alarmClockButton);
frame.setVisible(true);
frame.setSize(450, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
alarmClockButton.setForeground(Color.RED);
}
}

Image change when button is pressed Java

Okay I want my background image to change when helpButton is pressed. I can make the button image change when the mouse hovers over it with a Mouse Listener. I did the same steps except with the Action Listener but with no success. Any help would be great!
public class test extends JFrame{
private JLabel label;
private JButton button;
private ImageIcon bgi;
private JLabel bgl;
public static Rectangle gameSquare;
private JButton startButton;
private JButton helpButton;
private final Action action = new SwingAction();
public static void main(String[] args) throws MalformedURLException, IOException {
test gui = new test ();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when click x close program
gui.setSize(902, 305);
gui.setVisible(true);
gui.setTitle("Solid Cloud Inc - Twitter Unfolower");
}
public test() throws MalformedURLException, IOException{
bgi = new ImageIcon(getClass().getResource("tu.png"));
getContentPane().setLayout(null);
BufferedImage img = ImageIO.read(new URL("http://i1344.photobucket.com/albums/p656/SolidCloudInc/start_zpsf3781681.png"));
//ImageIcon start = new ImageIcon(getClass().getResource("start.png"));
startButton = new JButton("");
startButton.setIcon(new ImageIcon(img));
startButton.setBounds(22, 186, 114, 50);
getContentPane().add(startButton);
BufferedImage img2 = ImageIO.read(new URL("http://i1344.photobucket.com/albums/p656/SolidCloudInc/help_zpsc4fad867.png"));
final JButton helpButton = new JButton("");
helpButton.setIcon(new ImageIcon(img2));
helpButton.setBounds(192, 186, 114, 50);
getContentPane().add(helpButton);
bgl = new JLabel (bgi);
bgl.setBounds(0, 0, 886, 272);
getContentPane().add(bgl);
Events e = new Events();
startButton.addActionListener(e);
helpButton.addActionListener(e);
}
public class Events implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == startButton) {
label.setText("Searching");
try {
Unfollow();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if (e.getSource() == helpButton){
System.out.println("gottem");
bgi = new ImageIcon(getClass().getResource("tu2.png"));
bgl = new JLabel (bgi);
}
}
}
bgl = new JLabel (bgi);
Here you're creating a new JLabel, and putting it into the bgl variable but are doing anything with it and make no change to the JLabel object that continues to be shown in the GUI. It's a common newbie trap to think that by changing the reference of a variable you change the state of the original object that the variable previously referred to. That's not how it works. In other words, the original JLabel that was held by the bgl variable still exists and still displays its original content in the GUI despite this code above. What you should do instead is to change the icon shown by the original JLabel, or in other words, change the state of the current JLabel object, not change references held by the bgl variable. i.e.,
bgl.setIcon(bgi);
Also, you'll want to get rid of any and all use of null layout and calls to setBounds(...) as this will lead to buggy hard to maintain and upgrade code. Let the layout managers do the heavy lifting with regards to laying out the GUI.

Changing layout/frame in response to a button press

I'm trying to make a little game on Java using the Swing components (Boggle-type game).
The way I have it set up right now, it basically opens up to the game right away - but I want to have a start up window with two buttons - "Tutorial" and "Play". I already have the functionality (my Tutorial button just opens a new Window with all the things on it) I'm just not sure how to create a second JFrame and then switch to it when I press Play (or rather, create a JFrame, then switch to the one I've already created when the JButton is pressed). I guess I could cause a new JFrame to open on the same location and the old one to become non-visible - but I was hoping for a simpler solution.
I also want to do this on completion of the game, switching again automatically to a little stat page - so any info will be appreciated.
This is what I have so far in case you guys want to see my code (I haven't yet hooked up the Enter key send the userWord to be validated and scored in my other classes, or filled in the tileGrid with Tile Objects, or the timer.... but that will all come later!)
public class Game implements Runnable {
public void run(){
final JFrame frame = new JFrame("Boggle");
frame.setLocation(500,200);
// Input - holds typing box
final JLetterField typingArea = new JLetterField(1);
typingArea.setFocusTraversalKeysEnabled(false);
typingArea.setEditable(true);
typingArea.setFocusable(true);
typingArea.requestFocusInWindow(); //also this request isn't being granted..
//if anyone could explain why i would love you
// I want the focus on the TextField on startup
frame.add(typingArea, BorderLayout.SOUTH);
typingArea.addKeyListener(new KeyAdapter() {
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { // enter key is pressed
String userWord = typingArea.getText().toLowerCase();
typingArea.setText("");
}
}
});
final JLabel status = new JLabel("Running...");
// Main playing area
GridLayout tileGrid = new GridLayout(4,4);
final JPanel grid = new JPanel(tileGrid);
frame.add(grid, BorderLayout.CENTER);
// Reset button
final JPanel control_panel = new JPanel();
frame.add(control_panel, BorderLayout.NORTH);
final ImageIcon img = new ImageIcon("Instructions.png", "My Instructions...");
final JButton info = new JButton("Help");
info.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JFrame infoFrame = new JFrame("Tutorial");
infoFrame.setLocation(500,50);
JLabel tutorialImg = new JLabel(img);
int w = img.getIconWidth();
int h = img.getIconHeight();
infoFrame.setSize(w, h);
infoFrame.add(tutorialImg);
infoFrame.setVisible(true);
}
});
control_panel.add(info);
// Put the frame on the screen
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Game());
}
}
use CardLayout instead of second JFrame, your concept is heading to OutOfMemory
use JFrame.pack(after switch betweens Cards in CardLayout) if you want to change JFrames bounds on runtime,

how to add labels without them overlapping each other

I wanted to add 2 labels in my JDialog; one label will have animated gif ; other will have text. How to add these two so that they dont overlap? I don't want to hardcode their positions. I want the program to make the inherent adjustments.
Thanks in Advance
code:
JLabel l2=new JLabel("");
try {
Image img = ImageIO.read(getClass().getResource("resources/wait_animated.gif"));
ImageIcon imgnew=new ImageIcon("G:\\my java\\DesktopApplication1\\src\\desktopapplication1\\resources\\wait_animated.gif");
l2.setIcon(imgnew);
imgnew.setImageObserver(l2);
}
catch (IOException ex) {
}
l2.setLocation(300,300);
JDialog d=new JDialog();
JLabel l=new JLabel("Please Wait While Processing is Done... ");
JDesktopPane dp=new JDesktopPane();
dp.setPreferredSize(new Dimension(300,50));
l.setPreferredSize(new Dimension(250,50));
l2.setPreferredSize(new Dimension(20,20));
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
d.setTitle("Wait dialog");
d.add(l);
d.add(l2);
Use a LayoutManager (such as FlowLayout) to arrange your labels. It’s hard to say without any more details.
You do realize that one label can have both text and an image, right? E.G.
import javax.swing.*;
import java.net.URL;
class AnimatedGifInLabelWithText {
public static void main(String[] args) throws Exception {
final URL url = new URL("http://pscode.org/media/starzoom-thumb.gif");
Runnable r = new Runnable() {
public void run() {
ImageIcon ii = new ImageIcon(url);
JLabel label = new JLabel("Zoom!", ii, SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, label);
}
};
SwingUtilities.invokeLater(r);
}
}

Categories