Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

JList Items not Visible Until All Items are Added 1

Status
Not open for further replies.

YerMom

Programmer
Oct 3, 2006
127
0
0
US
I have a JList which is in a JScrollPane, on a JPanel, in a JTabbbedPane on a JFrame. The JList is called list_XSDStatusList, and the JScrollPane is called listScrollPane.

When processing starts, my UI (the JFrame) consecutively adds items to the list with no break between adding items. For example, it might add 100 items, then stops adding items.

The problem is that the items on the list are not visible until all the items have been added.

I'm using an instance of the DefaultListModel class to maintain the list of items. I've tried various techniques to make the list visible as items are being added, such as:

Code:
int index = listModel.size() - 1;
list_XSDStatusList.ensureIndexIsVisible(index);
list_XSDStatusList.validate();
list_XSDStatusList.repaint();
listScrollPane.repaint();

But none of this works.

Can anyone help?
Thanks.
 
stefanwagner,

I did quite a bit of research and reading, and determined that I need to use the SwingUtilities.invokeLater. One source said to use invokeLater in the main method for an application, which I did (see below). However, my JList still does not get updated until all items have been added.

So I must be over-simplifying the problem or making assumptions.

Can you help? Sorry if my code is hard to understand.
Thanks.

This is where call invokeLater
(Dashboard is my class that extends JFrame.)
Code:
public class StartDashboard 
{
	public static void main(String[] args)
	{
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
        		Dashboard d = new Dashboard();
        		d.setVisible(true);	            	
            }
        });
	}
}

The process of adding items to the JList starts when I click a button:
Code:
public void actionPerformed(java.awt.event.ActionEvent e) {
						xsdReader.process();
}

This is the part of my code where the DefaultListModel object gets updated:
Code:
public void update(Observable observable) 
{
  XsdReader reader = (XsdReader) observable; 
  int state = observable.getState();
  String msg = "";
  // Code to set value of msg
  // is here.
  listModel.addElement(msg);
}// END update


 
Did you try a Google search on Jlist update?

It shows some interesting results as this

Cheers,
Dian
 
Dianecht and stefanwagner,
Thanks very much for responding. I have to switch my attentions to another project for about a day, but I will provide a sample as stefan requested and also read the link that dianecht provides.

Thanks again.
 
Stefan and Dian,

I did additional reading but I still need help.

I created a simple program that replicates the problem and pasted the location into the Attachment edit box, but when I do a Preview Post I don't see any option to view the file. So I inserted the program below.

Thanks very much.

Code:
import java.awt.Rectangle;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;

public class TekTips extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel jContentPane = null;
	private JTabbedPane jTabbedPane = null;
	private JPanel jPanel_list = null;
	private JScrollPane jScrollPane = null;
	private JList jList = null;
	private JButton jButton = null;
	private DefaultListModel listModel = null;

	public TekTips() {
		super();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		initialize();
	}

	private void initialize() {
//		this.setSize(493, 270);
		this.setContentPane(getJContentPane());
		this.setTitle("JFrame");
		listModel = new DefaultListModel();
		this.jList.setModel(listModel);
	}
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(null);
			jContentPane.add(getJTabbedPane(), null);
		}
		return jContentPane;
	}

	private JTabbedPane getJTabbedPane() {
		if (jTabbedPane == null) {
			jTabbedPane = new JTabbedPane();
			jTabbedPane.setBounds(new Rectangle(30, 13, 427, 211));
			jTabbedPane.addTab("List", null, getJPanel_list(), null);
		}
		return jTabbedPane;
	}

	private JPanel getJPanel_list() {
		if (jPanel_list == null) {
			jPanel_list = new JPanel();
			jPanel_list.setLayout(null);
			jPanel_list.add(getJScrollPane(), null);
			jPanel_list.add(getJButton(), null);
		}
		return jPanel_list;
	}

	private JScrollPane getJScrollPane() {
		if (jScrollPane == null) {
			jScrollPane = new JScrollPane();
			jScrollPane.setBounds(new Rectangle(121, 31, 281, 135));
			jScrollPane.setViewportView(getJList());
		}
		return jScrollPane;
	}

	private JList getJList() {
		if (jList == null) {
			jList = new JList();
		}
		return jList;
	}

	private JButton getJButton() {
		if (jButton == null) {
			jButton = new JButton();
			jButton.setBounds(new Rectangle(16, 31, 92, 20));
			jButton.setText("Add Items");
			jButton.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {

					if (listModel.getSize()>0)
					{
						listModel.clear();
						jList.removeAll();
					}
					for (int i = 0; i < 200000; i++)
					{
						listModel.addElement(String.valueOf(i));
					}
				}
			});
		}
		return jButton;
	}
	public static void main(String[] args)
	{

		TekTips app = new TekTips();
		app.setSize(493, 270);
		app.setVisible(true);

	}
}
 
reduced to a lean minimum would more look like that:
Code:
import java.awt.BorderLayout;
import java.awt.Rectangle;
import javax.swing.*;
import java.awt.event.*;

public class TekTips extends JFrame
{
	DefaultListModel listModel = new DefaultListModel ();
	
	public TekTips ()
	{
		super ("TekTips");
		setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		JPanel jp = new JPanel ();
		jp.setLayout (new BorderLayout ());
		
		JList jList = new JList ();
		jList.setModel (listModel);
		
		JScrollPane jsp=  new JScrollPane (jList);
		jsp.setBounds (new Rectangle (121, 31, 281, 135));
		jp.add (jsp, BorderLayout.CENTER);
		
		JButton addItems = new JButton ("Add Items");
		jp.add (addItems, BorderLayout.SOUTH);
		addItems.addActionListener (new java.awt.event.ActionListener ()
		{
			public void actionPerformed (ActionEvent e)
			{
				if (listModel.getSize () > 0)
				{
					listModel.clear ();
					// jList.removeAll ();
				}
				for (int i = 0; i < 200000; i++)
				{
					listModel.addElement (String.valueOf (i));
				}
			}
		});
		getContentPane ().add (jp);
		setSize (493, 270);
		setVisible (true);	
	}

	public static void main (String[] args)
	{
		TekTips app = new TekTips ();
	}
}
without those fancy = null and if ... null Statements, without tabbedPane.

Give me a few moments for the improved version...

don't visit my homepage:
 
Here you have a solution, which is immeadiately responsive after hitting the button, and updated while filled:
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TekTipsApp extends JFrame implements ActionListener
{
	DefaultListModel listModel = new DefaultListModel ();
	JLabel jl = new JLabel ("todo");
	JList jList = new JList ();
	
	public TekTipsApp ()
	{
		super ("TekTips");
		setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		JPanel jp = new JPanel ();
		jp.setLayout (new BorderLayout ());
		
		jp.add (jl, BorderLayout.NORTH);

		jList.setModel (listModel);
		jp.add (jList, BorderLayout.CENTER);
		
		JButton addItems = new JButton ("Add Items");
		jp.add (addItems, BorderLayout.SOUTH);
		
		addItems.addActionListener (this);
		getContentPane ().add (jp);
		setSize (493, 270);
		setVisible (true);	
	}

	public static void main (String args[])
	{
		Runnable runner = new Runnable () 
		{
			public void run () 
			{
				new TekTipsApp ();
			}
		};
		EventQueue.invokeLater (runner);
	}

	@Override
	public void actionPerformed (ActionEvent arg0)
	{
		SwingWorker worker = new SwingWorker () 
		{
			protected String doInBackground () throws InterruptedException 
			{
				listModel.clear ();
				for (int i = 0; i < 5; i++)
				{
					listModel.addElement ("" + i);
					Thread.sleep (500);
				}
				return "done";						
			}
			
			protected void done () 
			{
				jl.setText ("done");
			}
		};
		worker.execute ();
	}
}

don't visit my homepage:
 
Stefan,

Thank so much. I will modify my application to match your example. Just wondering -- how long have you been doing Java?

Thanks.
 
Since about 1998 :)

But good tutorials about the event-dispatching-thread came late - at about 2004/5 which clarified the way to do it - older tutorials didn't cover the topic.

In many situations, without threads, you will be fine, because the time to perform an action isn't that long to block the user. But the best way is to do it right from the beginning.

don't visit my homepage:
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top