wnnmaw
wnnmaw

Reputation: 5534

Weird Behavior From wx.FileDialog

Ok folks, here's a weird one.

Theres' a GUI (in wxPython) which allows files to be attached. The file paths are saved to class attribute self.pathList. These paths are displayed on the GUI and edited with two functions (bound to buttons); OnAttach() and OnView(). The first, as the name implies, allows the user to select files, while the second allows the user to see a list of those files and choose which ones to delete.

There are two problems:

Again, it doesn't matter where sorted is applied (or if its there at all), the result is the same. Both lines below return the same self.pathList:

self.pathList = list(set(self.pathList + [str(path) for path in dlg.GetPaths()]))
self.pathList = sorted(list(set(self.pathList + [str(path) for path in dlg.GetPaths()])))

Hopefully someone can make sense of this. Thanks in advance

def OnAttach(self, event, viewattBtn):
    """Select a File"""
    self.dirname = ''
    dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN|wx.MULTIPLE|wx.FD_FILE_MUST_EXIST)
    if dlg.ShowModal() == wx.ID_OK:
        self.pathList = list(set(self.pathList + [str(path) for path in sorted(dlg.GetPaths())]))
        for path in self.pathList:
            self.fileNameList.append(path.split('\\')[-1]) 
        self.fileNameList = list(set(self.fileNameList))    #Applying sorted() here fixes the first issue
        self.att.SetLabel('\n'.join(self.fileNameList))
        self.vbox.Layout()
        self.panel.FitInside()
    if self.pathList != []: viewattBtn.Enable(True)
    return viewattBtn
    dlg.Destroy()  

def OnView(self, event, viewattBtn):
    dlg = wx.MultiChoiceDialog(self, "Attachments (Select attachments and push 'OK' to delete)", "", self.fileNameList, wx.OK|wx.CANCEL)   
    if options.diagMode: print self.fileNameList
    if dlg.ShowModal() == wx.ID_OK:
        selections = reversed(sorted(dlg.GetSelections()))
        selections = [self.fileNameList[index] for index in selections]              
        for item in selections:
            pathIndex = selections.index(item)
            self.pathList.pop(pathIndex)
            self.fileNameList.remove(item)   
        self.att.SetLabel('\n'.join(self.fileNameList))
        self.vbox.Layout() 
        self.panel.FitInside()
        if self.fileNameList == []: viewattBtn.Enable(False)
        return viewattBtn
    dlg.Destroy

EDIT: The first problem was fixed by sorted fileNameList on the marked line

Upvotes: 0

Views: 508

Answers (2)

abarnert
abarnert

Reputation: 366133

For your first issue, the problem is that you're creating a set out of the sorted list. Sets have no defined order; in fact, the order is documented to be arbitrary.

The solution is to just not create a set in the first place.

If you need to eliminate duplicates, you can use a recipe like unique_everseen from the itertools docs, or use an OrderedSet class of some kind. If you don't need to eliminate dups, just use the list as-is:

self.pathList = self.pathList + [str(path) for path in sorted(dlg.GetPaths())]

(Also, if you did want a set, you probably wouldn't want to convert that set to a list and add it to another list; you'd want to just keep it as a set in the first place.)


For your second issue, I'm not sure what your code is trying to do, but it's almost certainly doing things completely wrong.

First, you never want to iterate over a list and then search for the value's index. That does the wrong thing if there are any duplicates, and it's very slow, and it's very complicated. Just keep the index around:

    for index, item in enumerate(selections):

Second, I don't think the indexes in selections have anything to do with the indexes in pathList and fileNameList, in which case using the indexes doesn't work right in the first place.

But even if the indexes were the same at the start, every time you pop something out of the list, all of the remaining elements shift up one, so the indexes are no longer right after the first pop.

I think it would be better to reorganize your data structure—instead of keeping a bunch of lists, keep one list for whatever the thing is that needs to have a defined order, and keep everything else as dicts, using the values from that first list as keys.

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308530

Using a set will reorder your items, unsorting them. Don't do that, or sort after you've converted the set back to a list.

As you remove items from pathList the position of items in that list will change, and will no longer correspond to the numbers you're getting from selections. After you're removed enough items chances are one of the indexes will be beyond the size of the list.

Upvotes: 1

Related Questions