JList uzupelnianie

JList uzupelnianie
SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

Witam

Mam mały problem z uzupełnianiem JList.

W swoim programie tworze nowy JDialog który ma listę z elementami, która z kolei jest pobierana z servera.
Aby okno dialogu od razu się otwierało zamiast czekać na ściągnięcie elementów z servera wstawiłem wypełnianie do SwingWorkera.

Problem w tym, że raz na 10-15 razy lista jest pusta(na pewno się ładuje, widać mrugnięcie z danymi).
Repaint nie pomaga.

Może znacie najczęstsze tego przyczyny? Na co zwrócić uwagę?

CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
0

Podejrzewam, że zmiany listy robisz w którejś funkcji, która nie jest w EDT. Stąd taki efekt, zależny jak się wątki będą realizować. Pokaż kod tego SwingWorker'a.

SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

Troche śmieci jest bo próbuje i próbuje

Kopiuj

	private class FillList extends SwingWorker<Integer, Integer> 
	{

		private JLabel loadLabel = null;
		private JDialog dialog = null;
		private JTabbedPane pane = null;
		
		  public FillList(JLabel loadLabel, JDialog dialog, JTabbedPane pane) 
		  {
			  this.loadLabel = loadLabel;
			  this.dialog = dialog;
			  this.pane = pane;
		  }

		  @Override
		  protected Integer doInBackground() throws Exception {
		    System.out.println( "GuiWorker.doInBackground" );
		   
		    //this.loadLabel.setVisible(true);
		    this.loadLabel.setIcon(load);
		    fillDeviceList();
		    return 0;
		  }

		  @Override
		  protected void done() {
		    System.out.println("done");
		    this.loadLabel.setIcon(null);
		    this.pane.repaint();
		    //this.pane.revalidate();
		    this.dialog.invalidate();
		    
		  }

		}

i wywoluje tak z jdialog:

Kopiuj
EventQueue.invokeLater( new Runnable() {
	        @Override
	        public void run() {
	         
	           new FillList(loadLabel, thisDialog, tabbedPane).execute();

	        }
	      } );
edytowany 2x, ostatnio: Swr
CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
1

Nie musi być invokeLater, może być samo new...execute(); (a o ile się nie mylę, to powinno być bez invokeLater)
Widzę, że w doInBackground robisz setIcon, a tak nie powinno być. Nie wiem co robi fillDeviceList, ale przypuszczam, że pisze do modelu listy, a to też nie powinno mieć miejsca. Jeżeli cała lista pobiera się od razu, todo modelu wpisz ją w done(), a jeżeli po kawałku (po itemie), to użyj metod publish -> process.

edytowany 1x, ostatnio: chodnik
SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

Poniżej kod metody fillDeviceList.
Listę mam od razu całą,ale przetwarzam, dodaje do modelu pokolei to co odczytam. Czy w takim wypadku powinno być w done czy uzywając process?

Próbowałem rzucić do done ale wtedy program przytnie aż metoda fillDeviceList się wykona.
W moim kodzie najpierw musi pobrać z servera więc przycinka troche trwa. Podzielić to na metody pobierające z servera i wypelniajace model? umieścić do doInBackground pobranie z servera, a to co ściągnie wrzucić do wypełnienia modelu w done() - wtedy powinno być chyba szybciej?

I jescze takie pytanie gdzie umiescic to setIcon lub jesli lepiej setVisible? Chce wyswietlac gif od ladowania.

Kopiuj
private boolean fillDeviceList()
	{
		Document d = httpConnections.getDeviceList(this.login, this.password);
		
		if(d == null)
			return false;
			
		return this.fillDeviceList(d);
	}


private boolean fillDeviceList(Document d)
	{
		XPathFactory xpfactory = null;
		XPath path = null;
		String id = null;
		
		try
		{
			xpfactory = XPathFactory.newInstance();
			path = xpfactory.newXPath();
			
			int attrCount = ((Number)path.evaluate("count(devices/id)" , d, XPathConstants.NUMBER)).intValue();
			
			for(int i = 1; i <= attrCount; i++) // indeksy w XPath zaczynaja sie od 1
			{
				id = path.evaluate("devices/id["+ i +"]", d);
				this.deviceListModel.add(i-1, id); // indeksy w XPath zaczynaja sie od 1 w modelu od 0	
			}

			return true;
		}
		catch(XPathExpressionException e)
		{
			e.printStackTrace();
			return false;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}
CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
1

Zrób taki SwingWorker
SwingWorker<Document, String> worker = new SwingWorker<Document, String>() {...
W metodzie Document doInBackground wywołaj Document d = httpConnections.getDeviceList(this.login, this.password);
i daj return d;
W metodzie done napisz Document d=get();
this.fillDeviceList(d);

W ten sposób pobieranie, które trwa długo jest w osobnym wątku, a wypełnianie listy jest w EDT.
Co do ustawiania ikonki to pierwszą zmianę daj przed wywołaniem execute, a drugą w done. Jest też opcja użycia addPropertyChangeListener, ale może nie jest tutaj konieczna.

SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

Dzięki : ) Po poprawkach działa, przynajmniej koło 30 otwarć dobrze zadziałało jak na razie : )

Gdyby jednak okazało się, że wypełnienie modelu w done będzie czasochłonne z powodu ilości elementów to trzeba będzie przejść na publish process ?

CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
0
Swr napisał(a):

Dzięki : ) Po poprawkach działa, przynajmniej koło 30 otwarć dobrze zadziałało jak na razie : )

Gdyby jednak okazało się, że wypełnienie modelu w done będzie czasochłonne z powodu ilości elementów to trzeba będzie przejść na publish process ?

Zasadniczo tak by trzeba zrobić.
Skoro działa, to dobrze. Teraz, żeby to wszystko miało sens, to powinieneś przemyśleć dorobienie możliwości przerwania tego wątku przez użytkownika, albo jakiś timeout na połączenie dać. No ale to już inna bajka, tu właściwie chodziło o to, że się czasem lista nie pokazywała i mam nadzieję, że to był powód i jest to rozwiązane.

SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

w klasie od pobrania listy z servera HttpConnections mam shutdown który przerywa połączenie http, wiec wtedy kończy się chyba tez wątek bo tam nie ma żadnej pętli, mam to dorobione przy przycisku anuluj, chyba powinno wystarczyć. Niby nie jest to przerwanie SwingWorkera, ale chyba tak też może być?

CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
0

Nie wiem, nie chcę cię wprowadzić w błąd, bo kwestii przerywania wątku nie testowałem. Najlepiej sprawdź, ale mam pewne obawy. Przycisk działa w innym wątku niż pobieranie więc może być tak, jak się zaczęło: 10 razy zadziała, a raz nie. Ale popróbuj. W takiej sytuacji wywoła się metoda done, więc tam trzeba zabezpieczyć na wypadek jak nie dostanie dokumentu.

SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

W obu wątkach dostęp do tej samej zmiennej, biblioteka od połączen Apachea , a przycisk anuluj zamyka całe okno. Z tego co widze to wyrzuca mi ConnectionShutdown i wszystko idzie ok, czyli przerywa pobieranie danych, konczy sie metoda fillDeviceList.

Próbuję teraz rozbić to na process ale mam błąd ciągle przy każdym List<Integer> : "The type List is not generic, it cannot be parametrized with arguments<Integer>

Po usunięciu Integer wszędzie zostaje tylko błąd w process.

Kopiuj

private class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) 
{ 
     //initialize 
}

 @Override
 public List<Integer> doInBackground() {

	 return null;
 }

 @Override
 protected void process(List<Integer> chunks) {

     }
}

Przykład z http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 2 godziny
1

Zobacz jakiego List masz w importach, bo możliwe że zaimportowałeś złą klasę (tzn masz więcej niż jedną klasę o nazwie List na classpath'ie i wybrałeś złą).


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
SW
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 4 lata
  • Postów:426
0

dzięki : ) w sumie o tym myślałem ale byłem dość pewny że tego nie zrobiłem...okazało się, że miałem java.awt.*

CH
  • Rejestracja:prawie 19 lat
  • Ostatnio:prawie 2 lata
  • Postów:656
0

Zrób SwingWorker<Document, Integer> To Document to już masz i to jest to, co zwraca doInBackground i tego nie zmieniaj. process też masz dobrze, tylko teraz w doInBackground daj
for(int i = 1; i <= attrCount; i++) // indeksy w XPath zaczynaja sie od 1
{
id = path.evaluate("devices/id["+ i +"]", d);
publish(id);

                    }

a w process
for(Integer id:chunks){
this.deviceListModel.addElement(id);
}

Pomijam tu indeks pętli indeksów XPath, bo do samego modelu listy to on nic nie wnosi. Ale jak ci jest potrzebny jakoś, to możesz sobie przerzucać jakiś swój obiekt albo tablicę, zamiast tego Integer.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.