Langsamer FlexGridSizer

Plattformunabhängige GUIs mit wxWidgets.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Dienstag 19. September 2006, 12:51

In einem Script verwenden ich einen FlexGridSizer zur Darstellung von Daten in Tabellenform. Bei wenigen Daten klappt die Darstellung recht zügig. Sobald die Datenmenge aber anwächst, wird insbesondere das Löschen des Fensters extrem langsam. Da die Datenmenge in meinem Script aber kontinuierlich anwächst, suche ich nach einer schnelleren Möglichkeit. Zum Testen habe ich ein kurzes Script, das das Wesentliche enthält, geschrieben:

Code: Alles auswählen

from random import randrange
import wx
import wx.lib.scrolledpanel as scrolled

class SlowGrid(scrolled.ScrolledPanel):
    def __init__(self, parent, row=10, col=10):
        scrolled.ScrolledPanel.__init__(self, parent, -1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        grid = wx.FlexGridSizer(cols=col, vgap=4, hgap=4)
        for i in range(row):
            for j in range(col):
                label = wx.StaticText(self, -1, str(randrange(100000000)))
                grid.Add(label, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
        sizer.Add(grid, 0, wx.ALIGN_LEFT | wx.ALL, 5)
        self.SetSizer(sizer)
        self.SetAutoLayout(1)
        self.SetupScrolling(rate_x=1, rate_y=1)

app = wx.PySimpleApp()
frame = wx.Frame(None, -1, 'SlowGrid', size=(500, 500))
SlowGrid(frame, 20, 100) # <- Hier andere Groessen eingeben
frame.Show()
app.MainLoop()
MfG
HWK
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Dienstag 19. September 2006, 13:31

Hi

Zum Anzeigen von tabellarischen Daten ist doch das ListCtrl bestens geeignet.
In der Demo von wxPython hat es 3 Einträge unter "Core Windows/Controls" mit ListCtrl.

Da sollte eigentlich alles enthalten sein was du so brauchst.

Gruss
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Dienstag 19. September 2006, 21:12

Danke für den Vorschlag!
Ich weiß zwar nicht warum, aber es scheint wirklich schneller zu sein. Das zeigt zumindest ein Test von ca. 100 Spalten.
ListCtrl erfüllt aber nicht ganz meine Wünsche. Ich kann z.B. nur die Farbe einer ganzen Zeile ändern und nicht eines einzelnen Eintrags.
Andererseits besitzt es Funktionalität, die überflüssig ist oder sogar stört, z.B. eine Zeile auszuwählen.
Gibt es evtl. Alternativen?
MfG
HWK
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Dienstag 19. September 2006, 21:49

wx.grid.Grid
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Mittwoch 20. September 2006, 12:18

Wx.grid.Grid liefert ja noch mehr Funktionalität, die ich nicht brauche. Ich will lediglich möglichst einfach und schnell Daten in Tabellenform darstellen.
Gerold schrieb in einem anderen Thread (http://www.python-forum.de/topic-6468.h ... 553399a0eb), daß er zur Darstellung einer Tabelle das HtmlWindow benutzt. Ich kenne mich in Html aber nur wenig aus. Auf den ersten Blick wirkt mir das sehr kompliziert. Auch frage ich mich, ob dabei eine automatische Anpassung der Spaltenbreite möglich ist.
Also Gerold, falls Du dies liest, könntest du einmal ein Beipiel zeigen, wie man am geschicktesten eine Html-Tabelle mit Python erstellt?
MfG
HWK
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Mittwoch 20. September 2006, 12:29

ja das grid kann mehr, wurde allerdings auch für grosse Datenmengen ausgelegt. Und findest du ein TextCtrl besser? da hast du viel mehr aufwand... Du kannst auch ein virtuelles Grid machen, dann bist du allerdings für das data handling zuständig. Allerdings hättest du sicherlich die gewünschte performance...
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Mittwoch 20. September 2006, 14:46

Das geht ja rasant schnell. Das Aussehen ist natürlich jetzt etwas anders. Das Störendste für mich ist aber, daß der Benutzer die Möglichkeit hat, eine Auswahl zu treffen und mit den Cursortasten zu arbeiten. Kann man das irgendwie "disablen"?
Vielen Dank schon mal
HWK
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Mittwoch 20. September 2006, 16:49

du bindest diesen Event an das grid (Example aus meinem Programm)

Code: Alles auswählen

self.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnEdit)
Danach machst du eine Methode OnEdit

Code: Alles auswählen

    def OnEdit(self, evt):
        evt.Veto()
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Mittwoch 20. September 2006, 19:16

So funktioniert es nicht. Das Editieren verhindere ich bereits mit

Code: Alles auswählen

        self.EnableEditing(False)
Das Benutzen der Cursortasten und das Selektieren mit der Maus verhindert es nicht. Das erste kann man durch Veto für das Event EVT_GRID_SELECT_CELL verhindern:

Code: Alles auswählen

        self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnSelectCell)

    def OnSelectCell(self, evt): 
        evt.Veto()
Für das zweite habe ich noch keine Lösung gefunden. Man kann zwar die Auswahl mit

Code: Alles auswählen

        self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)

    def OnRangeSelect(self, evt): 
        self.ClearSelection()
wieder löschen, das Auswählen ist aber weiterhin möglich. Auch der Rahmen um die aktuelle Zelle bleibt bestehen.
MfG
HWK
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Mittwoch 20. September 2006, 19:20

Code: Alles auswählen

        self.SetSelectionMode(wx.grid.Grid.SelectRows)
So kann er zumindest nur ganze Reihen auswählen
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Mittwoch 20. September 2006, 21:27

Ich glaube, das ist nicht wirklich eine Verbesserung.
Danke trotzdem
HWK
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Samstag 23. September 2006, 12:42

Mit wx.Grid bin ich noch nicht so ganz glücklich. Es funktioniert zwar (auch sehr schnell), es gibt dem Anwender aber unnötige Möglichkeiten (Cursor bewegen, Auswählen), obwohl ich nur eine Tabelle anzeigen möchten. Wenn der Benutzer eine Auswahl macht, sieht das schon etwas komisch aus. Ich möchte deshalb nochmal auf Gerolds Hinweis im Thread http://www.python-forum.de/topic-6468.h ... 553399a0eb zurückkommen. Wäre eine Umwandlung in eine HTML-Tabelle und deren Anzeige mit HtmlWindow eine Alternative? Ist diese schneller im Grafikaufbau als FlexGridSizer? Wie wandelt man die Daten am einfachsten mit Python in HTML um? Ich besitze keine größeren Erfahrungen mit HTML, habe lediglich etwas in SELFHTML gestöbert und winzige HTML-Dateien geschrieben. Kennt sich jemand damit aus und kann mir ein paar Tips geben oder am besten ein Beispiel zeigen?
Danke im voraus
HWK
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 23. September 2006, 14:05

HWK hat geschrieben:HtmlWindow
Hi HWK!

Hier ein Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import wx
import wx.html
from simpletal import simpleTAL, simpleTALES
from StringIO import StringIO


class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, id = -1, title = "Einfache HTML-Tabelle"):
        wx.Frame.__init__(self, parent, id, title)
        
        html_window = wx.html.HtmlWindow(self, -1)
        
        daten = (
            {"vorname": u"ööö ööö", "nachname": u"äää äää"},
            {"vorname": u"aaa aaa", "nachname": u"fff"},
            {"vorname": u"bbb", "nachname": u"ggg ggg"},
            {"vorname": u"ccc ccc", "nachname": u"hhh"},
            {"vorname": u"ddd", "nachname": u"iii iii"},
            {"vorname": u"eee eee", "nachname": u"jjj"},
        )
        template_string = """
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
        <html>
          <head>
            <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
          </head>
          <body bgcolor="#FFFFF2">
            <table border="0" cellspacing="3" cellpadding="2">
              <tr>
                <th bgcolor="#D8D8D8"><strong>Vorname</strong></th>
                <th bgcolor="#D8D8D8"><strong>Nachname</strong></th>
              </tr>
              <tr tal:repeat="datensatz daten">
                <td bgcolor="#E9E9E9" tal:content="datensatz/vorname">
                  [Vorname]
                </td>
                <td bgcolor="#E9E9E9" tal:content="datensatz/nachname">
                  [Nachname]
                </td>
              </tr>
            </table>
          </body>
        </html>
        """
        
        context = simpleTALES.Context(allowPythonPath = True)
        context.addGlobal("daten", daten)
        
        template = simpleTAL.compileHTMLTemplate(template_string, "iso-8859-1")
        html_output = StringIO()
        template.expand(context, html_output, "iso-8859-1")
        
        html_window.SetPage(html_output.getvalue())
        
        self.Center()
        self.Show()


def main():
    app = wx.PySimpleApp()
    f = MyFrame()
    app.MainLoop()
    

if __name__ == "__main__":
    main()
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Samstag 23. September 2006, 14:37

Danke für die prompte Antwort, Gerold!
Ich werde es mal ausprobieren.
MfG
HWK
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Sonntag 24. September 2006, 14:07

So, ich hab's ausprobiert. Dies ist mein Beispielscript:

Code: Alles auswählen

from random import randrange
import wx
import wx.html 

class HTMLGrid:
    def __init__(self, parent, row=10, col=10):
        text = '''
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>
<html>
  <head>
    <meta http-equiv='content-type' content='text/html; charset=iso-8859-1'>
  </head>
  <body>
    <table border='0' cellspacing='0' cellpadding='2'>
'''
        text += '      <tr>\n        <th></th>\n'
        for i in range(col):
            text += '        <th nowrap><strong>Spalte %i</strong></th>\n' % i
        text += '      </tr>\n'
        for i in range(row):
            text += ('      <tr>\n'
                     '        <th align="LEFT" nowrap><strong>Reihe %i'
                     '</strong></th>\n' % i)
            for j in range(col - 1):
                text += ('        <td align="RIGHT" nowrap>%i</td>\n' %
                         randrange(100000000))
            text += ('        <td align="RIGHT" nowrap><font color="#FF0000">%i'
                     '</font></td>\n      </tr>\n' %randrange(100000000))
        text += '    </table>\n  </body>\n</html>\n'
        #print text
        html_window = wx.html.HtmlWindow(parent, -1)
        html_window.SetPage(text)

app = wx.PySimpleApp()
frame = wx.Frame(None, -1, 'HTMLGrid', size=(500, 500))
HTMLGrid(frame, 20, 100) # <- Hier andere Groessen eingeben
frame.Show()
app.MainLoop()
Ich habe auf simpletal, was ich im übrigen gar nicht kannte, verzichtet, um beim Datenformat nicht auf die etwas seltsame Form einer Liste von Dictionaries fixiert zu sein. Die Ausgabe ist schnell und qualitativ vergleichbar zu den anderen Varianten. Wie beim wx.grid.Grid kann der Anwender aber wieder eine Auswahl treffen. Anders als beim FlexGridSizer und wx.grid.Grid kann ich auch nicht automatisch ans Tabellenende scrollen. Da die Erstellung des HTML-Codes für einen HTML-Laien etwas verwirrend wirkt, werde ich wohl doch wx.grid.Grid verwenden. Ein Beispiel hierzu habe ich in einem anderen Thread gezeigt (http://www.python-forum.de/viewtopic.php?p=45638#45638).
MfG
HWK
Antworten