JList custom Cell Renderer refresh

I have a JList with a custom cell renderer (the background color changes).  How do you refresh a JList, applying this renderer automatically?  I have the JList on a tab in a JFrame.  If I select another tab, and come back to the tab the JList is on, it refreshes.  But I need to have the JList's background color refresh without having me change tabs.  (Or, at least have it refresh every 5 seconds or so).  I need this to happen without strange GUI glitches (which would probably happen if I have to clear/repopulate the JList)  Thanks.
MarkLoveExExAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
krakatoaConnect With a Mentor Commented:
This is an appalling hack, and requires not only considerable questioning, but more oop-ness all 'round. Nevertheless, it may help point you in some direction you are seeking, given that, as zzynx says, we don't really know the full context of what you are doing, nor why.

import javax.swing.*;
import java.util.*;
import java.awt.*;


class Cellular extends JFrame{

static JList jlist;
static DefaultListCellRenderer dlcr;
static JTabbedPane tabs;
static Cellular cell;

public static void main(String[] args){

	jlist = new JList();
		
	cell = new Cellular();
	
	//.......
	tabs = new JTabbedPane();
         
        tabs.addTab("Main",new JLabel());
        tabs.addTab("Advanced",new JLabel());
        tabs.addTab("Privacy",new JLabel());
        tabs.addTab("eMail",new JLabel());
        tabs.addTab("Security",new JLabel());
        tabs.setSize(300, 100);
        tabs.setVisible(true);

	
	//.......
	
	dlcr = (DefaultListCellRenderer)jlist.getCellRenderer();
	
	
	tabs.add(new JLabel("1"));
	tabs.add(jlist);
	jlist.setVisible(true);
	
	cell.add(tabs);
	cell.setSize(new Dimension(400,175));
	cell.setVisible(true);
	new Thread(new Timing()).start();

}

  static class Timing extends TimerTask{

		public Timing(){
			
			java.util.Timer t = new java.util.Timer();
            t.scheduleAtFixedRate(this, 10, 5000);
			tabs.setSelectedComponent(jlist);
		}
			
   public void run(){
   
	 
					jlist.setBackground(new java.awt.Color((int)(Math.random()*100),(int)(Math.random()*100),(int)(Math.random()*100)));
					
					if(!cell.isVisible()){System.exit(0);}
					dlcr.update(jlist.getGraphics());
					
			     
	}

  }

}

Open in new window

0
 
MarkLoveExExAuthor Commented:
I added a ListDataListener, but I still need to "click" the List for it to update.  Still looking for a solution to have it update with no user interaction.
0
 
MarkLoveExExAuthor Commented:
Would the solution involve a swing worker?
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
zzynxConnect With a Mentor Software engineerCommented:
But I need to have the JList's background color refresh without having me change tabs.
I assume that the background color is determined somehow by the data.
So, there's no need to refresh eg. every 5 seconds (if the data isn't changed)
You only need to refresh when the data has changed. In that light, adding a ListDataListener was defintely a good step.

...but I still need to "click" the List for it to update.
How do you mean?

You know, helping you without having a single piece of code is nearly impossible. Could you please post your code?

Did you already try something like this:

in your ListDataListener's method

void contentsChanged(ListDataEvent e) {
     JList theList = (JList)e.getSource();
     theList.invalidate();
     theList.doLayout();
}

Open in new window

0
 
MarkLoveExExAuthor Commented:
Thank you for the input. I will be back working on this problem on Monday, where I will try your suggestions. I will see what I can do about posting some code. My programs average 6000 lines and 30 classes which all interact, so sometimes it is difficult to know exactly what to post.  For this particular problem, I don't think I'm doing anything strange. It is just a basic JList with its model. You're right, the data is changing, and the custom cell renderer accesses that data, but the background color of the JList just won't change unless I have some GUI interaction, such as a change of tab or simply clicking on the JList. Again, thank you for your suggestions so far, but I have to put this on hold until Monday.
0
 
zzynxSoftware engineerCommented:
You're right, the data is changing, and the custom cell renderer accesses that data, but the background color of the JList just won't change unless I have some GUI interaction
Try what I posted.

Again, thank you for your suggestions so far,  
You're welcome
but I have to put this on hold until Monday.
No problem. Keep us up to date whenever you have new information.
0
 
krakatoaCommented:
Here's a bit more code you can try for size :

import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import javax.swing.event.*;
import java.awt.event.*;


class Cellular extends JFrame {

static JList<?> jlist;
static JTabbedPane tabs;
static Cellular cell;
static Exception exx;
static String[] sA={"A","B","C","D","E","Z"};
static ListDataEvent lde;

public static void main(String[] args) {

try{
	
	jlist = new JList<String>(sA);
	cell = new Cellular();
	tabs = new JTabbedPane();
         
        tabs.addTab("Main",new JLabel("Main"));
        tabs.addTab("Advanced",new JLabel());
        tabs.addTab("Privacy",new JLabel());
        tabs.addTab("eMail",new JLabel());
        tabs.addTab("Security",new JLabel());
        tabs.setSize(300, 100);
        tabs.setVisible(true);
	
	tabs.add(new JLabel("1"));
	tabs.add("JList",jlist);
	
	jlist.setBackground(java.awt.Color.WHITE);
	jlist.setVisible(true);
	
	cell.add(tabs);
	cell.setSize(new Dimension(450,255));
	cell.setVisible(true);
	
	int delay = 1000;
	
	ActionListener listUpdater = new ActionListener() {
	
      public void actionPerformed(ActionEvent evt) {
		
					try{
					if(!cell.isVisible()){throw new Exception(exx);}
					lde = new ListDataEvent(jlist,0,0,0);				
									
					if(jlist.getBackground()==java.awt.Color.WHITE){jlist.setForeground(new java.awt.Color(100,100,100));}
					else{jlist.setForeground(new java.awt.Color(255,255,255));}
								
					String st = (String)jlist.getModel().getElementAt(0);
					System.out.println(st);
					if(sA[0].equals("K")){sA[0]="A";}
					else{sA[0]="K";}
					if (lde.getSource()==jlist){
					jlist.setBackground(new java.awt.Color((int)(Math.random()*100),(int)(Math.random()*100),(int)(Math.random()*100)));}jlist.updateUI();
					}
					catch(Exception exx){System.exit(1);}
	  }
  };
	
	tabs.setSelectedComponent(jlist);
	new javax.swing.Timer(delay, listUpdater).start();
	
}catch(Exception t){System.exit(1);}

}

}

Open in new window

0
 
CEHJConnect With a Mentor Commented:
You only need to refresh when the data has changed. In that light, adding a ListDataListener was defintely a good step.
The 'inner wiring' of the JList should cause its rendering to be done correctly as soon as its data is mutated with no need for extra listeners.
 The fact that it's not doing so is probably caused by some blocking of the EDT caused by incorrect thread handling
0
 
MarkLoveExExAuthor Commented:
I finally found a solution that works.  I added a timer that adds an element to the JList, and then removes that element right away.  There is probably a better way, but this seems to work.  Thank you all for your input. I am not sure how to assign points, as I did not actually end up using any suggestions.  What is the protocol for this?
0
 
krakatoaCommented:
If this is real data you are dealing with then I would say that it is not really good practice to artificially insert some simply in order to fire an event. It is more than a notional compromise of integrity. But if this was an experimental / recreational / learning exercise then I guess it's fine. Did you run my last piece of code?
1
 
CEHJCommented:
Generally speaking (i think you know the quality of the workaround you just described, so i shan't comment on it) there is seldom much need to mutate a JList. What can happen is that a different model needs to be set on it, in which case, if the renderer is OK, then everything should work fine. When the new model is set, the renderer will carry on as before
0
 
zzynxSoftware engineerCommented:
I added a timer that adds an element to the JList, and then removes that element right away.
Really? That's quite a dirty workaround...
0
 
MarkLoveExExAuthor Commented:
Really? That's quite a dirty workaround...

I know right?  But it works surprisingly well.
0
 
MarkLoveExExAuthor Commented:
krakatoa -- I will try your latest code, maybe tomorrow.
0
 
krakatoaCommented:
No big deal. All I was really referring to is the point that CEHJ made, that the threading would affect performance, and my second piece of code has a better approach to that.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.