[PyKDE] ListView weirdness

Ulrich Berning ulrich.berning at desys.de
Thu May 15 14:02:00 BST 2003


Geoff Gerrietts schrieb:

>I've been working on a little app that uses a listview on the left to
>select an item, while an edit panel on the right lets me modify its
>attributes. I think it's a fairly common interface idiom, seen quite a
>bit in configuration screens and the like.
>
>My difficulty started when I wanted to add a confirm dialog. I wanted
>it so that if you selected a new item while changes were still
>pending, you'd get a dialog saying "Discard changes?" Again, a fairly
>common UI idiom.
>
>My idea was, when I caught a selectionChanged() signal, I would raise
>the dialog. If I got "ok", I would update the edit panel and discard
>the changes. If I got anything else, I would reset the selection to
>the previous value. To facilitate this, I set it up so that if the
>same item was selected twice, I would return immediately.
>
>Conceptually, this seems sound. I catch the signal, discover it's
>going to discard changes, warn the user. When the user says "whoops" I
>reset the selection, and when my slot catches the new event, it
>returns immediately because that's what's already selected. Printing
>out the "selectionTree.selectedItem()" before the return should result
>in:  new, old.
>
>Instead, I get the warning dialog twice. The printout shows new, old,
>new, old.
>
>I have no idea where this second event is coming from, but I know
>(based on strategic commenting) it's related to the call to
>setSelected() in the handler. What am I doing wrong?
>
>Sample code that illustrates the case is below -- it's not the actual
>app, but it reproduces the erroneous behavior. I can send the actual
>app to anyone interested in seeing the whole thing, but it's still
>very much a work in progress.
>
>Thanks,
>--G.
>
>  
>
I guess it must have something to do with immediate signal delivery when 
setSelected() is called inside the slot routine.
Blocking the signals in the slot routine does not help. If the 
setSelected() is called outside the slot routine, it works.
A QTimer started with a timeout value of 0 helps do delay the 
setSelected() call until the slot routine has finished.

See the changed sample code below.

Ulli

-------------------------------------
 from qt import *

 data = {
     'fruit': ['apple', 'banana', 'cherry'],
     'animal': ['ant', 'bear', 'cat']
 }

 class NoteEditor(QDialog):
     selectedItem = None

     def __init__(self,parent = None,name = None,modal = 0,fl = 0):
         QDialog.__init__(self,parent,name,modal,fl)

         if name == None:
             self.setName("ListMadness!")

         self.resize(146,480)
         self.setCaption(self.trUtf8("Note Editor"))

         seltree = self.selectionTree = QListView(self,"selectionTree")
         seltree.addColumn(self.trUtf8("Topics"))
         seltree.header().setClickEnabled(0,seltree.header().count() - 1)
         seltree.setGeometry(QRect(4,10,130,460))

         for category, topics in data.items():
             cat_item = QListViewItem(seltree, category)
             for topic in topics:
                 top_item = QListViewItem(cat_item, topic)
                 if self.selectedItem is None:
                     seltree.setSelected(top_item, 1)
                     self.selectedItem = top_item
             cat_item.setOpen(1)

*>        self.idleTimer = QTimer(self)
 >        self.connect(self.idleTimer, SIGNAL("timeout()"), 
self.undoSelectionChange)
*
                        
self.connect(self.selectionTree,SIGNAL("selectionChanged(QListViewItem*)"),self.refreshActiveTopic)


     def refreshActiveTopic(self):
         currentListItem = self.selectionTree.selectedItem()
         print "currentListItem", currentListItem
         print "self.selectedItem", self.selectedItem

         if currentListItem == self.selectedItem:
             return
 
         res = QMessageBox.warning(self,
             "Are you sure?",
             "Are you sure you really want to change topics?",
             QMessageBox.Ok, QMessageBox.Cancel)
         if res != 1:
*>            self.idleTimer.start(0, True)
*         else:
             self.selectedItem = currentListItem

*>    def undoSelectionChange(self):
 >        self.selectionTree.blockSignals(True)
 >        self.selectionTree.setSelected(self.selectedItem,1)
 >        self.selectionTree.blockSignals(False)
*
 if __name__ == "__main__":
     import sys
     app = QApplication(sys.argv)
     app.connect(app, SIGNAL('lastWindowClosed()'), app, SLOT('quit()'))
     w = NoteEditor()
     w.show()
     app.exec_loop()
-------------------------------------

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20030515/b6947143/attachment.html


More information about the PyQt mailing list