PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Jlist.... ich könnte kotzen


Senior Sanchez
2006-04-21, 19:39:03
Hi,

Ich muss meinem Unmut jetzt mal freien Lauf lassen über die tolle JList aus Swing.
Ich habe hier ne Applikation die etwa 500 Elemente inne Jlist hängt.
In nem späteren Schritt, wird die Liste komplett gelöscht und wieder ne gewisse Anzahl an Elementen rangehangen.
Soweit so gut.

Dann kamen aber die Probleme, Performanceprobleme um genau zu sein.
Ich habe erst ewig gesucht, bis ich irgendwann drauf gekommen bin, dass die JList Schuld ist.
Um mal Zahlen sprechen zu lassen: ist kein Element in der JList selektiert dauert das adden von 500 Elementen in die Liste (JLabels mit Grafik + System.out.println in jedem Durchlauf) etwa 130-160 ms.
Selektiert man dagegen aber das erste Element in der Jlist und added dann die 500 Elemente, dauert der ganze Spaß gleich über 14.000 ms!!! Die JList bzw. das Model feuert da Events wie bekloppt.

Naja, okay, wahrscheinlich Selektions- und Fokushandling. Rufste einfach mal nen clearSelection() auf dem zugrundeliegenden SelectionModel auf. Aber pustekuchen, hilft nicht, die Selektion bleibt bestehen!

Also blieb mir nix anderes übrig per Debugger mir vorm Adden der Elemente die Zustandsvariablen des SelectionModels anzuschauen und dann zu vergleichen wie die aussehen bei einer Selektion und wie ohne eine Selektion.
Jetzt modifiziere ich die Werte direkt so, als ob keine Selektion da wäre und nun klappt es auch wunderbar, aber mal ehrlich, was soll son scheiß? Ich habe dafür Stunden gebraucht um den Fehler zu finden, habe ständig an der falschen Stelle gesucht und dem Profiler zu wenig vertraut.

Oder habe ich irgendwie was übersehen einzustellen?

mithrandir
2006-04-24, 11:40:30
Dere!

hm... Warum setzt du die Liste nicht einfach fuer die Einfuege-Vorgaenge disabled und erst wieder enabled, wenn alles soweit fertig ist? Dann wuerden auch keine Events generiert werden.

bye, Peter

Monger
2006-04-24, 11:50:34
Auch ne Möglichkeit. Aber die JList ist wirklich zum kotzen. Warum z.B. akzeptiert die JList nur einen Vector im Konstruktor, und nicht alle List-Klassen?

mithrandir
2006-04-24, 15:08:46
Das ist doch auch bei anderen Komponenten ähnlich, hab mich z.B. schon bei den DefaultModels bzw. Konstruktoren von Tabellen, ComboBoxen und Co. darüber geärgert. Eigentlich arbeitet man selbst auch so, dass man bei solchen Dingen möglichst auf Interfaces zurückgreift, anstatt auf Implementierungen.

Senior Sanchez
2006-04-24, 16:49:39
Das disablen wäre natürlich auch ne Möglichkeit, die sich anbieten würde.
Ich mag das aber irgendwie nicht so gerne Komponenten für so etwas zu deaktivieren. Wenns Funktionen gibt, die das Problem eigentlich lösen sollten, erwarte ich es auch, dass diese das können.

Aber statt meines manuellen Umsetzens von SelectionModel internen Variablen kann man natürlich auch auf disabled gehen, wobei meine Lösung auch während des Einfügens zur Interaktion bereitsteht *g* Nur geht das Einfügen mittlerweile so schnell, da ist das auch nicht mehr von Relevanz *g*

Auch ne Möglichkeit. Aber die JList ist wirklich zum kotzen. Warum z.B. akzeptiert die JList nur einen Vector im Konstruktor, und nicht alle List-Klassen?

Das stimmt, ist wirklich Banane, zumal wozu den Vector? Ich weiß, anfangs waren sie Vector-verliebt aber Swing ist ja non-Thread-safe designed wurden, sprich alles muss durch den EDT. Da hätte man dann auch auf nicht synchronisierte Strukturen zugreifen können.

Xmas
2006-04-24, 18:56:10
Fügst du die neuen Elemente etwa einzeln in das ListModel ein?

Eine eigene ListModel-Implementation die ein List-implementierendes Objekt kapselt sollte nicht schwer sein.

Senior Sanchez
2006-04-24, 20:24:28
Fügst du die neuen Elemente etwa einzeln in das ListModel ein?

Eine eigene ListModel-Implementation die ein List-implementierendes Objekt kapselt sollte nicht schwer sein.

Ja ich füge sie einzeln hinzu.

Sicher wäre das auch gegangen, aber das war mir zu viel Aufwand ;)

HellHorse
2006-04-24, 21:12:30
Warum z.B. akzeptiert die JList nur einen Vector im Konstruktor, und nicht alle List-Klassen?
Legacy Code, Swing wurde vor Java 1.2 geschrieben auch wenn es erst mit 1.2 in SE integriert wurde. Keine Ahnung warum dann nicht noch schnell ein Refactoring gemacht haben, scheisse das hätte sogar ich hingekriet.
Ja ich füge sie einzeln hinzu.
IMHO sehr schlecht, du generiest damit events für unsichtbare ListItems!!!1111einself Ist aus meiner Sicht der Grund warum deine Performance so schlecht ist.
Wenn du MVC verwenden würdest hast du wenn du es richtig machst nur ein oder zwei Events.

Sicher wäre das auch gegangen, aber das war mir zu viel Aufwand ;)
Ist aus meiner Sicht weniger, ist ja nur ein Methodenaufruf. Im Moment hast du sicher mindest ein Methodenaufruf und eventuel noch ein Konstruktoraufruf wenn nicht noch mehr.

Senior Sanchez
2006-04-24, 21:18:32
Legacy Code, Swing wurde vor Java 1.2 geschrieben auch wenn es erst mit 1.2 in SE integriert wurde. Keine Ahnung warum dann nicht noch schnell ein Refactoring gemacht haben, scheisse das hätte sogar ich hingekriet.

IMHO sehr schlecht, du generiest damit events für unsichtbare ListItems!!!1111einself Ist aus meiner Sicht der Grund warum deine Performance so schlecht ist.
Wenn du MVC verwenden würdest hast du wenn du es richtig machst nur ein oder zwei Events.

Ist aus meiner Sicht weniger, ist ja nur ein Methodenaufruf. Im Moment hast du sicher mindest ein Methodenaufruf und eventuel noch ein Konstruktoraufruf wenn nicht noch mehr.

Naja, nen paar ms für nen paar tausend Items kann ich schon verkraften, aber keine hohen Sekunden- oder fast Minutenzahlen. Also es geht schon so, wies ist ;)

Erkläre mir mal deine Lösung mit dem Methodenaufruf, ich glaube ich stehe im Moment aufm Schlauch.

Monger
2006-04-24, 21:19:47
Das disablen wäre natürlich auch ne Möglichkeit, die sich anbieten würde.
Ich mag das aber irgendwie nicht so gerne Komponenten für so etwas zu deaktivieren. Wenns Funktionen gibt, die das Problem eigentlich lösen sollten, erwarte ich es auch, dass diese das können.

In dem bißchen was ich mit Swing gebastelt habe, habe ich das Listmodel bei jeder Änderung immer komplett weggeworfen und durch ein neues ersetzt. Also bei jeder Neusortierung, bei jeder textuellen Änderung, bei jedem entfernen...

Ist zwar Kacke, aber ist wohl immer noch die performantere Lösung als an einer aktiven Liste zu arbeiten. Vorallem hat man dadurch doppelte Datenhaltung: einerseits das was ist, und andererseits das was man sieht. Inkonsistenzen ahoi...

HellHorse
2006-04-25, 22:26:37
Erkläre mir mal deine Lösung mit dem Methodenaufruf, ich glaube ich stehe im Moment aufm Schlauch.
ListModel, Methode ist rot:

import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractListModel;

public class SimpleListModel extends AbstractListModel {

private List<String> items;

public SimpleListModel() {
this.items = new ArrayList<String>();
}

public void add(int amount) {
for (int i = 0; i < amount; ++i) {
this.items.add(Integer.toString(i));
}

// OMG bloss ein Methodenaufruf um alle Items hinzuzufügen !!!!11111einself
this.fireIntervalAdded(this, this.items.size() - amount, this.items.size() - 1);
}

public String getElementAt(int index) {
return this.items.get(index);
}

public int getSize() {
return this.items.size();
}

}


Action:

import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.KeyStroke;

public class AddAction extends AbstractAction {

private static final String ACTION_COMMAND = "add-command";
private static final int MNEMONIC = 'A';
private static final KeyStroke ACCELERATOR = KeyStroke.getKeyStroke("control A");

private SimpleListModel model;

private int amount;

public AddAction(SimpleListModel model, int amount) {
super("Add (" + amount + ")");
String description = "Add " + amount + " items to the list";
this.putValue(SHORT_DESCRIPTION, description);
this.putValue(LONG_DESCRIPTION, description);
this.putValue(MNEMONIC_KEY, new Integer(MNEMONIC));
this.putValue(ACCELERATOR_KEY, ACCELERATOR);
this.putValue(ACTION_COMMAND_KEY, ACTION_COMMAND);
this.model = model;
this.amount = amount;
}

public void actionPerformed(ActionEvent e) {
this.model.add(this.amount);
}

}


Applikation, Performance beim Hinzufügen von 500 Items war zu gross, da habe ich es halt auf 5000 erhöht ;D

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;

import static javax.swing.SwingUtilities.invokeLater;
import static javax.swing.BorderFactory.createEmptyBorder;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS;
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;

import static java.awt.BorderLayout.CENTER;
import static java.awt.BorderLayout.SOUTH;

public class ListGui {

protected static void createFrame() {
JFrame frame = new JFrame("List Demo");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);

SimpleListModel model = new SimpleListModel();
JList list = new JList(model);
JScrollPane scrollPane = new JScrollPane(list, VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_NEVER);

JButton button = new JButton(new AddAction(model, 5000));

BorderLayout layout = new BorderLayout(0, 11);

JComponent contentPane = (JComponent) frame.getContentPane();
contentPane.setLayout(layout);
contentPane.setBorder(createEmptyBorder(12, 12, 11, 11));

contentPane.add(scrollPane, BorderLayout.CENTER);
contentPane.add(button, BorderLayout.SOUTH);

frame.setBounds(200, 200, 200, 400);

frame.setVisible(true);
}

public static void main(String[] args) {
invokeLater(new Runnable() {
public void run() {
createFrame();
}
});
}

}


Scheisse, der Code hat ja fast mehr imports als sonst was :ugly:

Senior Sanchez
2006-04-25, 23:07:04
Na, okay, geht doch einfacher als ich dachte ;)
Aber von dir HellHorse, hab ich auch gar nix anderes erwartet *g*

Ist jetzt aber eh ritze *g*

Gast
2006-04-26, 11:05:50
Ist jetzt aber eh ritze *g*

Warum?

Senior Sanchez
2006-04-26, 16:01:28
Warum?

Weil ich daran jetzt nix mehr ändere und das betreffende Programm eigentlich abgeschlossen ist. ;)

Aber gut, falls man wieder mal das Problem hat, ist das natürlich nicht ritze.