wx.ListCtrl Items deselktieren

Plattformunabhängige GUIs mit wxWidgets.
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

wx.ListCtrl Items deselktieren

Beitragvon JR » Donnerstag 16. November 2006, 22:56

DESELECT, Liste, Event


Hallo!

Vielleicht weiß jemand da einen Rat:

Ich habe eine Klasse geschrieben, die von wx.ListCtrl erbt und auch solch eine Liste erzeugt. In dieser Klasse gibt es folgende Methode zum selektieren bestimmter Zeilen. Der Methode wird eine Liste voller Item-Nummern übergeben.

Code: Alles auswählen

    def SelectItems(self, items=[]):
        """items contains the index no. of rows to select."""
        if items:
            makeVisible = False
           
            for item in range(self.GetItemCount()):
                makeVisible = True
                if item in items:
                    self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
                    self.SetItemState(item, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED)
                else:
#                    following does not work :-(
#                    event = wx.ListEvent(wx.wx.EVT_LIST_ITEM_DESELECTED)
#                    self.GetEventHandler().ProcessEvent(event)
                    pass
            if makeVisible:
                # make top row of items to select visible
                toselectItem = items[0]
                if type(toselectItem) == type(1) and toselectItem < self.GetItemCount():
                    self.EnsureVisible(toselectItem)
            self.SetSelectedItemsIdsAttributs()
            self.SetFocus()


Wenn vor dem Aufruf der Methode zum Beispiel die Zeilen [0, 1] selektiert waren, ich die Liste aber mit self.DeleteAllItems() leere und frisch auffüllen lasse, dann liefert mir ein Aufruf der obigen Methode mit z.B. self.SelectItems([7, 8])
einen Zustand, wo die Zeilen [0, 1, 7, 8] selektiert sind. Wie kommt das? Ich habe die Liste doch geleert und dennoch merkt sie sich, was selektiert war?
In den Zeilen 14 und 15 hatte ich spaßenshalber mal versucht, sozusagen ein Event zum Deselektieren zu rufen. War aber zu erwarten, dass es dieses nicht gibt, wenn es nicht in den Docs aufgeführt wird.

Hoffe so eine umfangreichere Frage schreckt niemanden ab. Wenn ich das Problem nicht gelöst kriege, dann habe ich einen nicht vertretbaren Bug in meiner Listenbibliothek.

Grüße
Jamil
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Re: wx.ListCtrl Items deselktieren

Beitragvon gerold » Donnerstag 16. November 2006, 23:07

JR hat geschrieben:Vielleicht weiß jemand da einen Rat

Hi Jamil!

Wenn du uns funktionierenden Code zeigst, damit wir das auch ausprobieren und nachvollziehen können, dann können wir dir auch leichter helfen.

Es muss ja nicht dein Programm sein, aber zumindest irgendein kleines Codebeispiel, welches das Problem verdeutlicht.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Donnerstag 16. November 2006, 23:15

Hi Gerold!

Das kann ich verstehen und habe ich befürchtet.
Da setze ich mich jetzt ran, denn meine Klasse referenziert auf so viele Abhängigkeiten, dass ich das hier nie posten könnte.

Ich hoffe das geht jetzt noch. Mal sehen wie fix ich mit wxPython schon bin. Ansonsten eher am WE.

Bis gleich hoffentlich :-)
Jamil
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Donnerstag 16. November 2006, 23:55

Es ist zum Verzweifeln..

Habe ein Beispiel zusammen kopiert und da geht es. Habe den Code zwar weitestgehend aus meiner Klasse so übernommen, doch es poppt kein Dialog auf, wie es in der vollen Version meiner Listenbibliothek in diesem Zusammenhang der Fall ist.
Sprich irgendwo muss ich einen blöden Fehler haben.

Ich schildere es mal kurz. Ich ermögliche dem Anwender, einen Datensatz aus der Liste zu editieren. Wenn er auf "Bearbeiten" geht, poppt ein Dialog mit den Werten des DS auf, dessen Werte er ändern möchte. Nun kann es aber sein, dass er z.B. den Nachnamen einer Person in einer Personenliste ändert. Wenn die Liste nach der Nachname-Spalte sortiert ist, ändert sich u.U. die Position (Zeilennummer) des bearbeiteten DS. Daher wähle ich ihn in solch einem Fall nach dem Schließen des Dialogs wieder aus.

Was bei mir da passiert ist, dass die Zeile (z.B. 3. Zeile) vorm und nach dem Dialog selektiert bleibt. Ist der DS nun auf Position 1 gelandet, wird diese Zeile korrekterweise selektiert. Die 3. Zeile soll aber nicht mehr selektiert sein.
Ich langweile euch damit sicherlich. Das Codebeispiel poste ich dennoch, falls jemand reinschauen will, nur zu.



Code: Alles auswählen

# -*- coding: iso-8859-1 -*-
# File: test.py
import wx
import wx.lib.mixins.listctrl as listmix
from wx import ImageFromStream, BitmapFromImage
import cStringIO
#----------------------------------------------------------------------
def getSmallUpArrowData():
    return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00<IDAT8\x8dcddbf\xa0\x040Q\xa4{h\x18\xf0\xff\xdf\xdf\xffd\x1b\x00\xd3\
\x8c\xcf\x10\x9c\x06\xa0k\xc2e\x08m\xc2\x00\x97m\xd8\xc41\x0c \x14h\xe8\xf2\
\x8c\xa3)q\x10\x18\x00\x00R\xd8#\xec\xb2\xcd\xc1Y\x00\x00\x00\x00IEND\xaeB`\
\x82'
#----------------------------------------------------------------------
def getSmallUpArrowBitmap():
    return BitmapFromImage(getSmallUpArrowImage())
#----------------------------------------------------------------------
def getSmallUpArrowImage():
    stream = cStringIO.StringIO(getSmallUpArrowData())
    return ImageFromStream(stream)
#----------------------------------------------------------------------
def getSmallDnArrowData():
    return \
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00HIDAT8\x8dcddbf\xa0\x040Q\xa4{\xd4\x00\x06\x06\x06\x06\x06\x16t\x81\
\xff\xff\xfe\xfe'\xa4\x89\x91\x89\x99\x11\xa7\x0b\x90%\ti\xc6j\x00>C\xb0\x89\
\xd3.\x10\xd1m\xc3\xe5*\xbc.\x80i\xc2\x17.\x8c\xa3y\x81\x01\x00\xa1\x0e\x04e\
?\x84B\xef\x00\x00\x00\x00IEND\xaeB`\x82"
#----------------------------------------------------------------------
def getSmallDnArrowBitmap():
    return BitmapFromImage(getSmallDnArrowImage())
#----------------------------------------------------------------------
def getSmallDnArrowImage():
    stream = cStringIO.StringIO(getSmallDnArrowData())
    return ImageFromStream(stream)
#----------------------------------------------------------------------
class Liste(wx.ListCtrl,
            listmix.ListCtrlAutoWidthMixin,
            listmix.ColumnSorterMixin,
            listmix.TextEditMixin):
   
    def __init__(
                self,
                dialog,
                panel,
                pos=wx.DefaultPosition,
                size=(250, 250),
                style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES|wx.LC_SMALL_ICON):

        wx.ListCtrl.__init__(self, panel, -1, pos, size, style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES)
        listmix.ListCtrlAutoWidthMixin.__init__(self)

        self.il = wx.ImageList(16,16)
        self.sm_up = self.il.Add(getSmallUpArrowBitmap())
        self.sm_dn = self.il.Add(getSmallDnArrowBitmap())
        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
               
        self.initValues = (
                           ('Müller', 'Michael'),
                           ('Wurst', 'Hans'),
                           ('Huns', 'Kunz'),
                           ('Westernhagen', 'Wuzelfuzel'),
                           ('Adam', 'Eva'),
                           ('Klaus', 'Martin')
                           )
        self.LoadValues()
        self.CreateList()
        self.FillList()
        self.SortListItems(0, True)
    #------------------------------------------------------------------------   
    def GetListCtrl(self):
        """Module wx.lib.mixins.listctrl needs that."""
        return self
    #------------------------------------------------------------------------
    def GetSortImages(self):
        """Module wx.lib.mixins.listctrl needs that."""
        return (self.sm_dn, self.sm_up)   
    #------------------------------------------------------------------------   
    def CreateList(self):
        column_definitions = [['Nachname', wx.ALIGN_RIGHT, 125],
                              ['Vorname', wx.ALIGN_LEFT, 125]]
               
        for colNo, column_definition in enumerate(column_definitions):
            column_title = column_definition[0]
            align = column_definition[1]
            width = column_definition[2]
           
            info = wx.ListItem()
            # columns contains text and horizontal orientation can be set
            info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
            info.m_format = align
            info.m_text = column_title
            self.InsertColumnInfo(colNo, info)   
            self.SetColumnWidth(colNo, width)
           
        listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())       
    #------------------------------------------------------------------------     
    def LoadValues(self):
        self.itemDataMap = {}
        for no, record in enumerate(self.initValues):
            self.itemDataMap.update({no : record})
    #------------------------------------------------------------------------
    def FillList(self, insert_items=True):
        self.DeleteAllItems()
        if hasattr(self, 'itemDataMap'):
            items = self.itemDataMap.items()
            for key, record in items:
                if insert_items:
                    index = self.InsertStringItem(0, str(record[0]))
                for col in range(len(record)):
                    self.SetStringItem(index, col, str(record[col]))
                self.SetItemData(index, key)
    #------------------------------------------------------------------------
    def SelectItems(self, items=[]):
        """items contains the index no. of rows to select."""
        if items:
            for item in range(self.GetItemCount()):
                if item in items:
                    self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
                    self.SetItemState(item, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED)

            # make top row of items to select visible
            toselectItem = items[0]
            if type(toselectItem) == type(1) and toselectItem < self.GetItemCount():
                self.EnsureVisible(toselectItem)
            self.SetFocus()                                   
    #------------------------------------------------------------------------
#------------------------------------------------------------------------         
class MyFrame(wx.Dialog):
    def __init__(self, parent, title):
        wx.Dialog.__init__(self, parent, -1, title,
                          pos=(150, 150), size=(300, 350))

        panel = wx.Panel(self, -1)
        s = wx.BoxSizer(wx.VERTICAL)
       
        self.list = Liste(self, panel)
        self.list.SelectItems([2])
       
        btn = wx.Button(panel, -1, 'Leere und fülle Liste und wähle Zeile 4')
        btn.Bind(wx.EVT_BUTTON, self.OnButton)
       
        s.Add(self.list, 0, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 15)
        s.Add(btn, 0, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 15)
       
       
        panel.SetSizer(s)
        s.Fit(panel)
    #------------------------------------------------------------------------     
    def OnButton(self, event):
        self.list.DeleteAllItems()
        self.list.LoadValues()
        self.list.CreateList()
        self.list.FillList()
        self.list.SelectItems([3])       
        event.Skip()
#------------------------------------------------------------------------
class MyApp(wx.App):
    def OnInit(self):
        dialog = MyFrame(None, "Simple wxPython App")
        if dialog.ShowModal() == wx.ID_OK:
            print dialog.object.GetDate()
        return True
       
app = MyApp(0)
app.MainLoop()
[/code]
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Freitag 17. November 2006, 00:01

Nochmal kurz was von mir.
Guckt euch das Beispiel nicht so genau an. Ich habe es schnell zusammengeschustert um was zu demonstrieren und weiter nix.
Das man mit dem Klick auf den Knopf immer mehr Spalten einfügt ist natürlich blödsinnig und ein Sortieren sollte beim Klick auch noch folgen. egal...

Gute Nacht allerseits!
Jamil
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Freitag 17. November 2006, 00:08

Oh Mann :oops:

Also mein Beispiel ist doch wunderbar um mein Problem zu zeigen.
Ich sitze wohl schon zu lange vor der Kiste.
Ihr müsst nur die Methode "OnButton" mit folgendem austauschen.

Code: Alles auswählen

    def OnButton(self, event):
        self.list.SelectItems([3])       
        event.Skip()

Dann passiert genau das, was ich gerade nicht will.
Nur die Zeile 4 soll nach einem Drücken auf den Button selektiert sein. Wie deselektiere ich die anfänglich gewählte 3. Zeile?

Bis denn
Jamil[/code]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Freitag 17. November 2006, 17:45

Zeile 121-124:

Code: Alles auswählen

            for item in range(self.GetItemCount()):
                if item in items:
                    self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
                    lastitem = item
                else:
                    self.SetItemState(item, 0, wx.LIST_STATE_SELECTED)
            self.SetItemState(lastitem, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Freitag 17. November 2006, 23:32

Hi Gerold,

dank dir für die Antwort. Werde dazu nochmal was schreiben. Habs nur grad gesehen und komme erst am Sonntag dazu, mich wieder an die Entwicklung zu setzen. Freue mich schon jetzt darauf.

Bis denn und Grüße
Jamil
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Samstag 18. November 2006, 19:03

Hi Gerold!

Was bewirkt Zeile 6 bei dir?

Code: Alles auswählen

self.SetItemState(item, 0, wx.LIST_STATE_SELECTED)


In der Referenz heißt es:
bool SetItemState(long item, long state, long stateMask)

Bedeutet dies in deinem Fall und in Worten:
Setze die Eigenschaft "selektiert" auf Null, sprich nicht mehr selektiert?

Grüße
Jamil
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Sonntag 19. November 2006, 10:17

JR hat geschrieben:Was bewirkt Zeile 6 bei dir?

Code: Alles auswählen

self.SetItemState(item, 0, wx.LIST_STATE_SELECTED)

Bedeutet dies in deinem Fall und in Worten:
Setze die Eigenschaft "selektiert" auf Null, sprich nicht mehr selektiert?

Hi Jamil!

Ja, so ist es.

Jedes dieser Konstanten stellt ein Bit dar:

Code: Alles auswählen

>>> import wx
>>> wx.LIST_STATE_DONTCARE
0
>>> wx.LIST_STATE_DROPHILITED
1
>>> wx.LIST_STATE_FOCUSED
2
>>> wx.LIST_STATE_SELECTED
4
>>> wx.LIST_STATE_CUT
8
>>> wx.LIST_STATE_DISABLED
16
>>> wx.LIST_STATE_FILTERED
32
>>> wx.LIST_STATE_INUSE
64
>>> wx.LIST_STATE_PICKED
128
>>> wx.LIST_STATE_SOURCE
256
>>>


Mit

Code: Alles auswählen

SetItemState(long item, long state, long stateMask)

kannst du eine Auswahl aus diesen Bits in einem Rutsch setzen. In ``stateMask`` gibst du an, welche Bits du verändern möchtest und in ``item`` gibst du den neuen Wert der zu verändernden Bits an. Das hat etwas damit zu tun: http://de.wikipedia.org/wiki/Bitmaske
Leider hat man versäumt, je eine einfache Möglichkeit zum Setzen und Auslesen der einzelnen Bits als Methoden in das ListCtrl einzuprogrammieren. :roll:

Anmerkung an die Entwickler:
``GetSelections``, ``SetSelections`` und die anderen nützlichen Methoden, die man so von der ``ListBox`` kennt -- warum gibt es die nicht auch im ``ListCtrl``?

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Sonntag 19. November 2006, 14:37

Hi Gerold!

Danke für deine Antwort.
Ich dachte "wx.LIST_STATE_DONTCARE" tut einfach gar nichts.

Wieso schreibst du "An die Entwickler"? Gibt es hier wxPython-Entwickler?

Viele Grüße
Jamil
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Sonntag 19. November 2006, 22:14

JR hat geschrieben:Gibt es hier wxPython-Entwickler?

Hi Jamil!

Ich weiß nicht. Ich kann aber auch keinen FeatureRequest schreiben, da mein Englisch erbärmlich ist. Also lasse ich solche Bemerkungen so nebenbei fallen. Vielleicht habe ich Glück und es liest jemand, der bei wxPython etwas mitreden kann. ;-)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Beitragvon Francesco » Montag 20. November 2006, 12:21

gerold hat geschrieben:
JR hat geschrieben:Gibt es hier wxPython-Entwickler?

Hi Jamil!

Ich weiß nicht. Ich kann aber auch keinen FeatureRequest schreiben, da mein Englisch erbärmlich ist. Also lasse ich solche Bemerkungen so nebenbei fallen. Vielleicht habe ich Glück und es liest jemand, der bei wxPython etwas mitreden kann. ;-)

lg
Gerold
:-)

Hi Gerold,
es gibt folgende "Shortcut" Methoden:
Select (idx, on=1) (Also auch zum Deselektieren)
GetFirstSelected
GetNextSelected
IsSelected
GetSelectedItemCount
Zuletzt geändert von Francesco am Montag 20. November 2006, 13:23, insgesamt 1-mal geändert.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Montag 20. November 2006, 12:36

Francesco hat geschrieben:es gibt folgende "Shortcut" Methoden:
Select (idx, on=1) (Also auch zum Deselektieren)
GetFirstSelected
GetNextSelected
IsSelected
GetSelectedItemCound

Hi Francesco!

Diese Methoden habe ich übersehen, da sie nicht in der wxWidgets-Referenz zu finden sind.

Gibt es irgendwo eine **herunterladbare** wxPython-Referenz? Dann wären solche Fehler nicht die Regel.
http://wxpython.org/docs/api/ ist zwar nett, aber meistens elendlich langsam und schon deshalb nicht zum täglichen Arbeiten brauchbar.

Francesco, du hast doch einen guten Draht zu den wxPython-Entwicklern. Kannst du nicht irgendwie veranlassen, dass es irgendwo einen Link zum Herunterladen der wxPython-Referenz gibt? Zur Not tut es ja auch schon, wenn man die derzeitge API-Referenz, gepackt, herunterladen kann.

Bitte, das wäre wirklich super! :D

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Beitragvon Francesco » Montag 20. November 2006, 12:58

Hi Gerold,

gerold hat geschrieben:Diese Methoden habe ich übersehen, da sie nicht in der wxWidgets-Referenz zu finden sind.


Die sind wahrscheinlich deswegen nicht drin, da sie nur in wxPython gibt, nicht aber in den wxWidgets.
Das sind eben die "Helpers" :)
_controls.py ca. Zeile 4850 bei meiner 2.6.1.2 wxPython Version
#
# Some helpers...
def Select(self, idx, on=1):
'''[de]select an item'''
if on: state = wx.LIST_STATE_SELECTED
else: state = 0
self.SetItemState(idx, state, wx.LIST_STATE_SELECTED)

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder