Refreshing a JPanel-Moving a JLabel - java

I am having trouble moving this JLabel across this JPanel? I put the code below. Basically what is supposed to happen, is the JLabel called "guy" slowly moves to the right. The only problem is, that the JLabel isn't refreshing it just disappears after the first time I move it.
public class Window extends JFrame{
JPanel panel = new JPanel();
JLabel guy = new JLabel(new ImageIcon("guy.gif"));
int counterVariable = 1;
//Just the constructor that is called once to set up a frame.
Window(){
super("ThisIsAWindow");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(panel);
panel.setLayout(null);
}
//This method is called once and has a while loop to exectue what is inside.
//This is also where "counterVariable" starts at zero, then gradually
//goes up. The variable that goes up is suposed to move the JLabel "guy"...
public void drawWorld(){
while(true){
guy.setBounds(counterVariable,0,50,50);
panel.add(guy);
counterVarialbe++;
setVisible(true);
try{Thread.sleep(100)}catch(Exception e){}
}
}
Any thoughts as to why the JLabel is just disappearing instead of moving to the right after I change the variable "counterVariable".
-Thanks! :)

Your code is causing a long-running process to run on the Swing event thread which is preventing this thread from doing its necessary actions: paint the GUI and respond to user input. This will effectively put your entire GUI to sleep.
Issue & suggestions:
Never call Thread.sleep(...) on the Swing Event Dispatch Thread or EDT.
Never have a while (true) on the EDT.
Instead use a Swing Timer for all of this.
No need to keep adding the JLabel to the JPanel. Once added to the JPanel, it remains there.
Likewise, no need to keep calling setVisible(true) on the JLabel. Once visible, it remains visible.
Call repaint() on the container holding the moving JLabel after you've moved it to request that the container and its children be re-drawn.
e.g.,
public void drawWorld(){
guy.setBounds(counterVariable,0,50,50);
int timerDelay = 100;
new javax.swing.Timer(timerDelay, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
countVariable++;
guy.setBounds(counterVariable,0,50,50);
panel.repaint();
}
}).start;
}
caveat: code not compiled, run, or tested in any way

Related

What is wrong with this method for displaying images?

I am very confused. Why would this method not work for displaying an image:
private void showImage(final BufferedImage image){
SwingUtilities.invokeLater(
new Runnable(){
#Override
public void run(){
ImageIcon icon = new ImageIcon(image);
JLabel label = new JLabel();
label.setIcon(icon);
add(label, BorderLayout.CENTER);
}
}
);
}
My class extends JFrame, so that's why I'm not doing something like:
frame.add(label);
I am very confused. I have tried this without the whole SwingUtilities thing and also I have tried label.setVisible(true)
What the heck am I doing wrong here? When I run it I know this method is being called with a completely okay BufferedImage (I had it output something in the method). I expected a JLabel to come up with my image on it, but just the JFrame came up, no image in sight.
add(label, BorderLayout.CENTER);
When you add (or remove) a component from a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
In your case you would revidate the frame since you are adding the label to the content pane of the frame.
That is you need to invoke the layout manager, otherwise the component has a size of (0, 0) so there is nothing to paint.
However, a better solution would probably be to add the label to the GUI when you create the frame.
Then to change the icon you just do:
label.setIcon(...);
No need to create a new JLabel every time you want to change the image.

Refreshing a JFrame while in an Action Listener

The code snippet below sets text in a JLabel, which is added to a JPanel, which is attached to a JFrame. No matter what I do though (such as repaint(), revalidate(), etc) I cannot get the UI to update the text until the Action Listener is done.
I have never had this problem before, possible because I have never had to have several things happen in a single firing of Action Listener. What am I missing?
TL;DR Why does the following not update the text on the screen until it has finished firing the Action Listener, even if I put in repaint() after each listPanel.add()?
final JFrame guiFrame = new JFrame();
final JPanel listPanel = new JPanel();
listPanel.setVisible(true);
final JLabel listLbl = new JLabel("Welcome");
listPanel.add(listLbl);
startStopButton.addActionListener(new ActionListener(){#Override public void actionPerformed(ActionEvent event){
if(startStopButton.getText()=="Start"){
startStopButton.setVisible(false);
listPanel.remove(0);
JLabel listLbl2 = new JLabel("Could not contact”);
listPanel.add(listLbl2);
JLabel listLbl2 = new JLabel("Success”);
listPanel.add(listLbl2);
}
}
guiFrame.setResizable(false);
guiFrame.add(listPanel, BorderLayout.LINE_START);
guiFrame.add(startStopButton, BorderLayout.PAGE_END);
//make sure the JFrame is visible
guiFrame.setVisible(true);
EDIT:
I attempted to implement SwingWorker, but still the interface is not updating until the action interface finishes firing. Here is my SwingWorker code:
#Override
protected Integer doInBackground() throws Exception{
//Downloads and unzips the first video.
if(cameraBoolean==true)
panel.add(this.downloadRecording(camera, recording));
else
panel.add(new JLabel("Could not contact camera "+camera.getName()));
panel.repaint();
jframe.repaint();
return 1;
}
private JLabel downloadRecording(Camera camera, Recording recording){
//does a bunch of calculations and returns a jLabel, and works correctly
}
protected void done(){
try{
Date currentTime = new Timestamp(Calendar.getInstance().getTime().getTime());
JOptionPane.showMessageDialog(jframe, "Camera "+camera.getName()+" finished downloading at "+currentTime.getTime());
}catch (Exception e){
e.printStackTrace();
}
}
Basically, SwingWorker (as I implemented it) is not properly updating the JPanel and JFrame. If I try to do the repaint in the "done()", they are not updated either. What am I missing?
Additionally, as soon as the JOptionPane displays itself, no more panels can be added to my jframe. I am unsure what is causing that either.
The action listener is being executed on the Event Dispatch Thread. For tasks like that, consider using a SwingWorker.
This would allow you to process your logic without blocking the updates (and thus the repaints) of the JFrame.
At a high level, this is what I mean:
startStopButton.addActionListener(new ActionListener(){#Override public void actionPerformed(ActionEvent event){
if(startStopButton.getText()=="Start"){
// Start SwingWorker to perform whatever is supposed to happen here.
}
You can find some information on how to use SwingWorker here, should you need it.

Killing all processes, force everything to stop

I have a game that runs off of JPanel which has on it many other things which have their own independent timers and such. It seems that when I try to remove the panel from my frame to replace it with another JPanel it refuses to actually end all of its own processes. So even if I am able to remove it from the screen of the panel by removing it and setting it null, its processes are still going off in the background, IE the music and the stuff flying around.
What i need to know is some solution as to how to completely kill this JPanel and terminate its life to its entirety.
Seems not many people have run into this problem.
I remember having that issue in my own game..
Simply create some custom method i.e destroy() which will stop all timers gameloops music etc.
i.e
MyPanel panel=new MyPanel();
...
panel.destory();//stop music, timers etc
frame.remove(panel);
//refresh frame to show changes
frame.revalidate();
frame.repaint();
where panel would be:
class MyPanel extends JPanel {
private Timer t1,t2...;
//this method will terminate the game i.e timers gameloop music etc
void destroy() {
t1.stop();
t2.stop();
}
}
Alternatively you could make your Swing Timers observers of sorts by making it check each time whether the panel is visible and if not it should stop executing. This would though now of course cause you to create a timer which will only start the others once the panel becomes visible:
class MyPanel extends JPanel {
private Timer t1,t2,startingTimer;
MyPanel() {
t1=new Timer(60,new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if(!MyPanel.this.isVisible()) {//if the panel is not visible
((Timer)(ae.getSource())).stop();
}
}
});
startingTimer=new Timer(100,new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if(MyPanel.this.isVisible()) {//if the panel is visible
t1.start();//start the timers
t2.start();
((Timer)(ae.getSource())).stop();//dont forget we must stop this timer now
}
}
});
startingTimer.start();//start the timer which will check when panel becomes visible and start the others as necessary
}
}
now all you would do is:
frame.remove(panel);//JPanel timers should also see panel is no more visible and timer will stop
//refresh frame to show changes
frame.revalidate();
frame.repaint();
Try this:
myFrame.getContentPane().remove(myPanel);
myFrame.validate();
Make sure your music and other components are within the panel so they are removed as well.

How to call a method on a period of time in swing?

I have a frame with a JTextField and a JButton.
When I press I want to call a method that updates the JTextField`s text at every 4/5/8 seconds.
Could anyone help me with the code ?? (thank you)
The code:
import javax.swing.*;
public class Gui{
JFrame frame = new JFrame();
public Gui(){
frame.setLayout(new FlowLayout());
JTextField tf = new JTextField(10);
JButton bu = new JButton("Button");
bu.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
for(int i=0;;i++){
tf.setText("" + i);
}
}
});
}
}
Personally, as #trashgod has pointed out, I'd be using the java.swing.Timer, the main reason is that it supports calling notifications within the EDT, as well as some (generally minor) management methods to help make life easier
You could try to use timers : http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
You might want to start the timer when the actionPerformed method is called.
Though BEST bet with Swing, is the use of javax.swing.Timer, as it allows you to update your GUI on the Event Dispatch Thread.

JFrame reloads initial content on mouse over

I have a JPanel with a GridLayout(1,0) set to a JFrame Borderlayout.SOUTH, there are placed a couple of buttons in here (when pressed they change a variables value to the index of the created button).
Everything is added correctly, but when I try to update the JPanel it does work at first (only when window is maximized). But then when I go over a button (or all the buttons) it goes back to what the original content of the panel.
I've tried invalidate, validate, repaint, jframe.setvisible(true) - none of these seem to work properly.
Any ideas?
private void toonHand(){
JPanel pnlSouth = new JPanel(new GridLayout(1,0));
JButton[] btnArr =new JButton[50];
ArrayList<Kaart> Thand=uno.getSpeler(0).getHand();
for(int i=0;i<Thand.size();i++){
final int T=i;
btnArr[i]=new JButton();
btnArr[i].setIcon(Thand.get(i).getImg());
btnArr[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
iKaart=T;
}
});
pnlSouth.add(btnArr[i]);
}
Hoofdvenster.remove(pnlSouth);
Hoofdvenster.add(pnlSouth, BorderLayout.SOUTH);
}
The problem was that i was just removing the panel, changing the content and adding it again.
Apparently this was giving some issues with displaying the content.
I fixed it by putting the panels as global variables, and splitting up the making and updating of the panels. So in every update i remove the panel, make the panel a new Panel and then i make it again.

Categories

Resources