AbstractTableModel+modyfikacja list poza JTable

0

Cześć,

buduję w swingu interfejs do prostego programu. I tak:

Mam klasę o nazwie Wodomierz, która zawiera proste pola (String NrWdowomierza, Int IloscOdczytow itd)
mam Klasę CopyIt, w której zdefiniowałem listę List<Wodomierz> listaWodomierzy,
Dalej, mam AbstractTableModel, o nazwie WodomierzTableModel gdzie wyświetlam zawartość listy listaWodomierzy.

Gdzieś tam w tym wszystskim istnieje StartGui, gdzie mam definicję JTable (z podpiętym WodomierzTableModel) oraz obiektem

CopyIt copyGwmax= new CopyIt();
WodomierzeTableModel wtm = new WodomierzeTableModel(copyGwmax.getListaWodomierzy());
JTable tabela = new JTable(wtm);
JScrollPane scrollPane = new JScrollPane(tabela);

oraz podpięte pod batona:

copyGwmax.doMagic_copy(); //doMagic_copy() wypełnia tablice wewnątrz klasy
wtm.FillTable(copyGwmax.getListaWodomierzy());

gdzie getListaWodomierzy() to zwyczajne:

	public List<Wodomierz> getListaWodomierzy()
	{
		return ListaWodomierzy;
	}

na chwilę obecną zrobiłem po głupiemu, w WodomierzTableModel dodałem:

public class WodomierzeTableModel extends AbstractTableModel{
	List<String> NrWodomierza;
	List<String> NrObiektu;
	List<String> sposobRozliczania;
	List<Double> srednia;
	List<Integer> LiczbaOdczytow;

public void FillTable(List<Wodomierz> lw)
	{
	
		System.out.println("FillTable");
		
		NrWodomierza.clear();
		NrObiektu.clear();
		sposobRozliczania.clear();
		srednia.clear();
		LiczbaOdczytow.clear();
		{
			for(Wodomierz w : lw)
			{
				NrObiektu.add(w.getNrObiektu());
				NrWodomierza.add(w.getWodomierzNumber());
				sposobRozliczania.add(w.getSposobRozliczania());
				srednia.add(w.getMeanOfMeans());
				LiczbaOdczytow.add(w.getLiczbaOdczytow());
				System.out.println(w.toString());
			}
		}
		
		fireTableDataChanged();
	}
}

Ale rozwiązanie to jest mało optymalne. Chciałbym pracować nie na kopi danych, tylko przekazać referencje do właściwych pól oraz w przypadku zmiany danych w sposób inny niż przez AbstractTableModel (np metoda uruchamiana batonem aktualizująca wyznaczone średnie) chciałbym żeby TableModel został poinformowany o zmianach i mógł azktualizować widok.

Teoretycznie mogę przerzucić ciężar aplikacji na abstractTableModel i w niej wykonywać wszystkie operacje, ale chyba nie do końca ta klasa służy.

Moje pytania:
Chciałbym przekazać referencję do listaWodomierzy poprzez konstruktor WodomierzTableModel, jak to zrobić?
Chciałbym, żeby WodomierzTableModel był poinformowany, że listaWodomierzy została zaktualizowana, jak to zrobić??

Dziękuję za wszelką pomoc i rady :)
Piotrek

1

Ale rozwiązanie to jest mało optymalne.

Nie zgodzę się - kombinujesz w dobrym kierunku, tylko trzeba to dobrze rozegrać. Wieki temu robiłem dość dużą aplikację symulacyjną w Swingu, gdzie całe GUI bazowało na tym, że dostawało krótkożyjące snapshoty oryginalnych danych tylko na potrzeby renderingu, a właściwe dane siedziały sobie gdzie indziej (dodatkowo jeszcze wszystko się rysowało i animowało z prędkością 35 fps, również otrzymując dane w ten sam sposób) i działało fajnie. Pamiętaj, że w Swingu bardzo ważne jest, aby wszystkie GUI-owe operacje były wykonywane w wątku Swinga. Jeśli będziesz chciał w przyszłości np. w innym wątku coś na bieżąco robić z obliczeniami, możesz albo bawić się w synchronizację i w pewnym momencie przestać ogarniać, co się dzieje, albo... generować snapshoty dla GUI i ograniczyć synchronizację do absolutnego minimum.

A oto, jak możesz do tego podejść:

  1. zrób sobie dwie klasy: WaterMeter oraz WaterMeterSnapshot.
  2. pierwsza klasa trzyma sobie właściwe dane, posiada metody do aktualizacji danych itd.
  3. druga klasa to prosta lista danych z pojedynczego wodomierza - niech dodatkowo posiada zaimplementowane metody equals() i hashCode().
  4. niech dodatkowo klasa WaterMeter ma metodę createSnapshot(), która po prostu będzie pakować dane i zwracać WaterMeterSnapshot.
  5. AbstractTableModel przyjmuje albo listę snapshotów, albo pojedynczy snapshot. Jeśli dostanie listę snapshotów, odświeża całą listę. Jeśli dostanie jeden snapshot, to wywołuje jedną z metod fireXXX do zmiany tylko fragmentu.

I teraz jak coś zmienisz w swoich wodomierzach, generuj snapshoty i wysyłaj je do GUI. Na dłuższą metę taka architektura bardzo upraszcza panowanie nad tym, co się w aplikacji dzieje. Używałem jej kiedyś do Swinga, używam obecnie w innych zastosowaniach i mogę polecić.

0

rozwiązanie urzekające swoją prostotą :)

postaram się to zakodować tak jak sugerujesz.

Dzięki!

1 użytkowników online, w tym zalogowanych: 0, gości: 1