来自wx.FileDialog的奇怪行为

时间:2013-12-10 22:42:22

标签: python python-2.7 wxpython

好的伙计,这是一个奇怪的。

Theres'是一个允许附加文件的GUI(在wxPython中)。文件路径保存到类属性self.pathList。这些路径显示在GUI上,并使用两个功能进行编辑(绑定到按钮); OnAttach()OnView()。第一个,顾名思义,允许用户选择文件,而第二个允许用户查看这些文件的列表并选择要删除的文件。

有两个问题:

  • [已解决]这些项目已添加到self.pathList ,无需考虑排序。无论是否应用sorted(),列表永远不会排序。我们通过选择100个名为“1.txt”,“2.txt”的文本文件来测试它,依此类推。订单似乎是随机的。这两个函数的完整代码如下,但有问题的行是:

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

同样,应用sorted的地方(或者根本不存在)并不重要,结果是一样的。以下两行都返回相同的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()])))
  • 如果选择了超过3/4的附件,则从列表中删除项目似乎会失败。 很奇怪,对吧?我没有解释为什么会这样,但它非常一致。具体错误为IndexError: pop index out of range

希望有人能理解这一点。提前致谢

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

编辑:第一个问题是在标记的行上按已排序的fileNameList修复的

2 个答案:

答案 0 :(得分:1)

对于您的第一个问题,问题是您要从排序列表中创建set。集没有定义的顺序;事实上,订单记录是任意的。

解决方案是首先不要创建set

如果您需要消除重复项,可以使用unique_everseen文档中的itertools之类的配方,或者使用某种OrderedSet类。如果您不需要消除重复,只需按原样使用列表:

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

(另外,如果 想要一个集合,您可能不希望将该集合转换为列表并将其添加到另一个列表中;您只想将其保存为另一个列表;设置在第一位。)


对于你的第二个问题,我不确定你的代码是做什么的,但它几乎肯定是完全错误的。

首先,您从不想要遍历列表,然后搜索值的索引。如果有任何重复,这是错误的,而且非常慢,而且非常复杂。只需保持索引:

    for index, item in enumerate(selections):

其次,我不认为selections中的索引与pathListfileNameList中的索引有任何关系,在这种情况下使用索引不能正常工作第一名。

但即使索引在开始时相同,每次pop列表中的某些内容时,所有剩余的元素都会向上移动一个,因此索引为no在第一个pop之后更长。

我认为重新组织你的数据结构会更好 - 而不是保留一堆列表,保留一个列表,无论什么东西需要有一个已定义的顺序,并保留其他所有内容作为dicts,使用来自首先列为键。

答案 1 :(得分:1)

使用set会重新排序您的商品,并将其分类。不要那样做,或者在之后对进行排序,然后将集合转换回列表。

当您从pathList中移除项目时,该列表中项目的位置将发生变化,并且将不再与您从selections获得的数字相对应。删除足够多的项目后,其中一个索引将超出列表的大小。