Hallo,
Als ich gestern mehrere tausend Werte in ein ListControl eintragen lies stellte ich etwas seltsames fest. Unter Windows dauerte das ganze etwa eine Sekunde ( bei 1500 Werten) - inkl. Gauge fuer die Statusanzeige. Unter Linux (Ubuntu 5.1 - Gnome) dauert es mindestens 10 Sekunden fuer die gleiche Arbeit.
Ist die Performance von WX unter Linux allgemein schlechter, ist dies nur bei Gnome oder bei bestimmten Controls so oder gibt es andere Erklaerungen fuer dieses Phaenomen?
Beim Code habe ich mich relativ nah an der Wx-Demo orientiert, daran duerfte es also eigentlich nicht liegen
Gruß
WX unter Linux ca um den Faktor 10 langsamer
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi freze!freze hat geschrieben:Ist die Performance von WX unter Linux allgemein schlechter, ist dies nur bei Gnome oder bei bestimmten Controls so oder gibt es andere Erklaerungen fuer dieses Phaenomen?
Ich habe soeben unter Gnome eine Liste mit 10.000 Einträgen gefüllt. Das Programm, wenn es sich nach 30 sec. endlich wieder gefangen hat, ist kaum bedienbar.
Auch bei 3000 ist die Geschwindigkeit nicht unbedingt super. Das wird wohl am GTK, das unter Linux von WX verwendet wird, liegen.
Listengröße schrumpfen. Was anderes fällt mir nicht ein.
mfg
Gerold

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Nein, am GTK liegt es nicht. Ich habe eben einen Test mit GTK gemacht.
Eine Liste mit 10.000 Einträgen ist für GTK kein Problem. Es muss an etwas anderem liegen.
Wenn es jemanden interessiert. Diesen Code habe ich zum Testen verwendet:
mfg
Gerold

Eine Liste mit 10.000 Einträgen ist für GTK kein Problem. Es muss an etwas anderem liegen.
Wenn es jemanden interessiert. Diesen Code habe ich zum Testen verwendet:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
pygtk.require("2.0")
import gtk
#----------------------------------------------------------------------
class SimpleList(gtk.ScrolledWindow):
"""
Stellt eine einfache Liste mit Laufbalken dar. Das wird mit
den Objekten ScrolledWindow und TreeView erreicht.
"""
#----------------------------------------------------------------------
def append_item(self, value, key = ""):
"""
Fügt der Liste Werte und wenn gewünscht, Schlüssel hinzu.
"""
self.list_store.append([key, value])
#----------------------------------------------------------------------
def _on_row_activated(self, treeview, path, view_column, data = None):
"""
Setzt den Wert von self.selected_items. Dieser Wert kann
mit der Methode "get_selection_data" abgerufen werden.
"""
iter = self.list_store.get_iter(path)
if iter:
self.selected_item = (
path[0], # Position
self.list_store.get_value(iter, 0), # Key
self.list_store.get_value(iter, 1) # Value
)
#----------------------------------------------------------------------
def _on_cursor_changed(self, widget, data1 = None, data2 = None):
"""
Setzt den Wert von self.selected_items. Dieser Wert kann
mit der Methode "get_selection_data" abgerufen werden.
"""
selection = widget.get_selection()
(model, iter) = selection.get_selected()
if iter:
self.selected_item = (
int(selection.get_selected_rows()[1][0][0]), # Position
str(model.get_value(iter, 0)), # Key
str(model.get_value(iter, 1)) # Value
)
#----------------------------------------------------------------------
def get_selection_data(self):
"""
Gibt die Variable self.selected_item zurück.
Diese enthält ein Tupel. (<Position>, <Key>, <Value>)
"""
return self.selected_item # (<Position>, <Key>, <Value>)
#----------------------------------------------------------------------
def set_eventfunction__cursor_changed(self, function):
"""
Verbindet die übergebene Funktion mit dem
Signal "cursor-changed".
"""
self.tree_view.connect("cursor-changed", function)
#----------------------------------------------------------------------
def __init__(self):
"""
Initialisieren
"""
gtk.ScrolledWindow.__init__(self)
self.selected_item = None # (<Position>, <Key>, <Value>)
# Liste
self.list_store = gtk.ListStore(str, str)
# ScrolledWindow
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
#self.set_border_width(6)
self.set_shadow_type(gtk.SHADOW_IN)
# Treeview
self.tree_view = gtk.TreeView(self.list_store)
self.tree_view.set_headers_visible(False)
self.tree_view.get_selection().set_mode(gtk.SELECTION_BROWSE)
self.tree_view.connect("cursor-changed", self._on_cursor_changed)
self.tree_view.connect("row-activated", self._on_row_activated)
self.tree_view.show()
# Key-Spalte hinzufügen
self.key_cell = gtk.CellRendererText()
self.key_column = gtk.TreeViewColumn("Key")
self.key_column.pack_start(self.key_cell, True)
self.key_column.add_attribute(self.key_cell, "text", 0)
self.key_column.set_visible(False)
self.tree_view.append_column(self.key_column)
# Value-Spalte hinzufügen
self.value_cell = gtk.CellRendererText()
self.value_column = gtk.TreeViewColumn("Caption")
self.value_column.pack_start(self.value_cell, True)
self.value_column.add_attribute(self.value_cell, "text", 1)
self.tree_view.append_column(self.value_column)
# Suchspalte setzen
# Leider funktioniert die Suche im Moment nicht so
# wie ich das möchte. Deshalb habe ich die Suche abgeschaltet.
self.tree_view.set_enable_search(False)
#self.tree_view.set_search_column(1)
# Anzeigen
self.add(self.tree_view)
self.show()
if __name__ == "__main__":
# Fenster erstellen
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("SimpleList")
window.set_default_size(300, 400)
window.connect("destroy", gtk.main_quit)
# SimpleList erstellen und dazugehöriges Event verbinden
simple_list = SimpleList()
def cursor_changed(*args):
print "(pos, key, value) =", simple_list.get_selection_data()
simple_list.set_eventfunction__cursor_changed(cursor_changed)
# SimpleList befüllen
for item in [ "Hallo Welt %s" % item for item in range(10000) ]:
simple_list.append_item(item)
# Anzeigen
window.add(simple_list)
window.show()
gtk.main()
Gerold

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
PS: Es gibt wahrscheinlich eine Möglichkeit, die Liste virtuell im Speicher zu halten und immer nur die aktuellen Einträge anzuzeigen. Ich suche mal -- vielleicht finde ich etwas.
mfg
Gerold

mfg
Gerold

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- User
- Beiträge: 773
- Registriert: Mittwoch 5. November 2003, 18:06
- Wohnort: Schweiz
- Kontaktdaten:
Hi
Ja das gibt es und nennt sich VirtualList
Hier das Beispiel aus dem Buch wxPython in Action:
Der Hauptunterschied ist der Style (wx.LC_VIRTUAL).
Habs nicht getestet und im Buch steht, dass data einfach eine Klasse ist, die die Daten bereitstellt, mehr nicht.
Gruss
PS: falls es nicht geht kann ich dem Interessierten den Ausschnitt des Buches zuschicken, sind nur 5 Seiten
Ja das gibt es und nennt sich VirtualList
Hier das Beispiel aus dem Buch wxPython in Action:
Code: Alles auswählen
import wx
import sys, glob, random
import data
class DataSource:
def GetColumnHeaders(self):
return data.columns
def GetCount(self):
return len(data.rows)
def GetItem(self, index):
return data.rows[index]
def UpdateCache(self, start, end):
pass
class VirtualListCtrl(wx.ListCtrl):
def __init__(self, parent, dataSource):
wx.ListCtrl.__init__(self, parent, \
style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL)
self.dataSource = dataSource
self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)
self.SetItemCount(dataSource.GetCount())
columns = dataSource.GetColumnHeaders()
for col, text in enumerate(columns):
self.InsertColumn(col, text)
def DoCacheItems(self, evt):
self.dataSource.UpdateCache(evt.GetCacheFrom(), evt.GetCacheTo())
def OnGetItemText(self, item, col):
data = self.dataSource.GetItem(item)
return data[col]
def OnGetItemAttr(self, item):
return None
def OnGetItemImage(self, item):
return -1
class DemoFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Virtual wx.ListCtrl", size=(600,400))
self.list = VirtualListCtrl(self, DataSource())
app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()
Habs nicht getestet und im Buch steht, dass data einfach eine Klasse ist, die die Daten bereitstellt, mehr nicht.
Gruss
PS: falls es nicht geht kann ich dem Interessierten den Ausschnitt des Buches zuschicken, sind nur 5 Seiten
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi!
Angeregt von rayo's Beispiel, habe ich mich ein wenig umgesehen und bin auf die Objekte **VListBox** und **HtmlListBox** gestoßen. Zuerst habe ich VListBox ausprobiert, da der Name recht vielversprechend war. Aber die Handhabung war mir zu kompliziert. Dann habe ich mir noch HtmlListBox angesehen. Trotz des Namens, denke ich mal, dass **HtmlListBox** genau das richtige ist, um schnelle Listen zu erstellen.
Der einzige, optische Unterschied zur ListBox, den ich entdecken konnte: Zu breite Einträge werden in die nächste Zeile umgebrochen. Es erscheint keine horizontale Bildlaufleiste.
Hier ein Beispiel:
mfg
Gerold

Angeregt von rayo's Beispiel, habe ich mich ein wenig umgesehen und bin auf die Objekte **VListBox** und **HtmlListBox** gestoßen. Zuerst habe ich VListBox ausprobiert, da der Name recht vielversprechend war. Aber die Handhabung war mir zu kompliziert. Dann habe ich mir noch HtmlListBox angesehen. Trotz des Namens, denke ich mal, dass **HtmlListBox** genau das richtige ist, um schnelle Listen zu erstellen.
Der einzige, optische Unterschied zur ListBox, den ich entdecken konnte: Zu breite Einträge werden in die nächste Zeile umgebrochen. Es erscheint keine horizontale Bildlaufleiste.
Hier ein Beispiel:
Code: Alles auswählen
import wx
class FastListBox(wx.HtmlListBox):
_data = []
def get_data(self):
return self._data
def set_data(self, data):
self._data = list(data)
self.SetItemCount(len(data))
data = property(get_data, set_data)
def OnGetItem(self, n):
return self._data[n]
app = wx.App()
frame = wx.Frame(None, -1, "Hallo Welt")
choices = [ "Hallo Welt %s" % item for item in range(10000) ]
def on_listbox(event):
print choices[event.GetSelection()]
fast = FastListBox(frame)
fast.Bind(wx.EVT_LISTBOX, on_listbox)
fast.data = choices
fast.SetFocus()
frame.Show()
app.MainLoop()
Gerold

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- User
- Beiträge: 773
- Registriert: Mittwoch 5. November 2003, 18:06
- Wohnort: Schweiz
- Kontaktdaten:
Hi
Also das versteh ich jetzt nicht warum du noch andere Objekte gesucht hast, das ListCtrl macht ja genau das.
Hier noch ein Beispiel der class DataSource, einfach mit der von meinem Beispiel ersetzen und laufenlassen, unter Win ist alles kein Problem (schnell gefüllt und Geschwindigkeit ist auch super:
Also das versteh ich jetzt nicht warum du noch andere Objekte gesucht hast, das ListCtrl macht ja genau das.
Hier noch ein Beispiel der class DataSource, einfach mit der von meinem Beispiel ersetzen und laufenlassen, unter Win ist alles kein Problem (schnell gefüllt und Geschwindigkeit ist auch super:
Code: Alles auswählen
class DataSource:
def __init__(self):
self.data = [(str(x),str(x),'test','noch mehr eintraege') for x in xrange(10000)]
def GetColumnHeaders(self):
return ['x','y','teststring','str']
def GetCount(self):
return len(self.data)
def GetItem(self, index):
return self.data[index]
def UpdateCache(self, start, end):
pass
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi rayo!rayo hat geschrieben:Also das versteh ich jetzt nicht warum du noch andere Objekte gesucht hast, das ListCtrl macht ja genau das.
Ich wollte nur einen schnellen Ersatz für **ListBox** finden. Da bin ich auf **VListBox** gestoßen.
Ich wollte nur mehr über wxPython lernen. Mir ging es nicht darum, einen Ersatz für **ListCtrl** zu finden.
**HtmlListBox** ist mir ins Auge gestoßen, weil man damit nur die Methode **OnGetItem** überschreiben muss. Es ist also viel einfacher zu handhaben als **ListCtrl** mit dem Flag **wx.C_VIRTUAL** und die Handhabung von **VListBox** ist auch nicht unbedingt einfach.
Deshalb habe ich als Ersatz für die einfache **ListBox** **HtmlListBox** vorgeschlagen. Was natürlich kein Ersatz für das **ListCtrl** sein kann.
lg
Gerold

http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.