- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个更新 ObjectListView 的列表,它以前可以工作,但在解决另一个问题时,我以某种方式破坏了它,但现在无法弄清楚为什么它不工作。
当程序解析目录时,它应该使用找到的 .mp3 文件的信息更新 ListView 。它正在更新显示,但仅包含空行。但是,如果您强制输出到命令行,则表明列表的内容是正确的。
更让我困惑的是,我还有第二个列表,它充当一种“日志”。它工作正常,并且它们都使用相同的技术来更新各自的列表。我已经检查了代码以找到我的拼写错误在哪里(我猜测),但我一生都无法弄清楚为什么现在不起作用。
未正确更新的列表是 TrackOlv。要查看实际错误,只需浏览到包含 .mp3 文件的源目录,然后选择目标目录。您将看到显示更新为空行而不是数据行。
#Boa:Frame:Frame1
import wx
import os
import glob
import shutil
import datetime
from mutagen.mp3 import MP3
from mutagen.easyid3 import EasyID3
import mutagen.id3
import unicodedata
from ObjectListView import ObjectListView, ColumnDefn
########################################################################
class Track(object):
def __init__(self, title, artist, album, source, dest):
"""
Model of the Track Object
Contains the followign attributes:
'Title', 'Artist', 'Album', 'Source', 'Dest'
"""
self.atrTitle = title
self.atrArtist = artist
self.atrAlbum = album
self.atrSource = source
self.atrDest = dest
class Action(object):
def __init__(self, timestamp, action, result):
self.timestamp = timestamp
self.action = action
self.result = result
########################################################################
# Non GUI
########################################################################
def selectFolder(sMessage):
print "Select Folder"
dlg = wx.DirDialog(None, message = sMessage)
if dlg.ShowModal() == wx.ID_OK:
# User has selected something, get the path, set the window's title to the path
filename = dlg.GetPath()
else:
filename = "None Selected"
dlg.Destroy()
return filename
def getList(SourceDir):
print "getList"
listOfFiles = None
print "-list set to none"
listOfFiles = glob.glob(SourceDir + '/*.mp3')
return listOfFiles
def getListRecursive(SourceDir):
print "getListRecursive"
listOfFiles = None
listOfFiles = []
print "-list set to none"
for root, dirs, files in os.walk(SourceDir):
for file in files:
if file.endswith(".mp3"):
listOfFiles.append(os.path.join(root,file))
#print listOfFiles
return listOfFiles
def strip_accents(s):
print "strip_accents"
return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))
def replace_all(text):
print "replace_all " + text
dictionary = {'\\':"", '?':"", '/':"", '...':"", ':':"", '&':"and"}
print "-- repl_orig: " + text
print "-- repl_decode: " + text.decode('utf-8')
text = strip_accents(text.decode('utf-8'))
for i, j in dictionary.iteritems():
text = text.replace(i,j)
return text
def getTitle(fileName):
print "getTitle"
audio = MP3(fileName)
try:
sTitle = str(audio["TIT2"])
except KeyError:
sTitle = os.path.basename(fileName)
frame.lvActions.Append([datetime.datetime.now(),fileName,"Title tag does not exist, set to filename"])
# TODO: Offer to set title to filename
## If fileName != filename then
## prompt user for action
## Offer Y/n/a
sTitle = replace_all(sTitle)
return sTitle
def getArtist(fileName):
print "get artist"
audio = MP3(fileName)
try:
sArtist = str(audio["TPE1"])
except KeyError:
sArtist = "unkown"
frame.lvActions.Append([datetime.datetime.now(),fileName,"Artist tag does not exist, set to unkown"])
#Replace all special chars that cause dir path errors
sArtist = replace_all(sArtist)
#if name = 'The Beatles' change to 'Beatles, The'
if sArtist.lower().find('the') == 0:
sArtist = sArtist.replace('the ',"")
sArtist = sArtist.replace('The ',"")
sArtist = sArtist + ", The"
return sArtist
def getAblum(fileName):
print "get album"
audio = MP3(fileName)
try:
sAlbum = str(audio["TALB"])
except KeyError:
sAlbum = "unkown"
frame.lvActions.Append([datetime.datetime.now(),fileName,"Album tag does not exist, set to unkown"])
#Replace all special chars that cause dir path error
sAlbum = replace_all(sAlbum)
return sAlbum
########################################################################
# GUI
########################################################################
class MainPanel(wx.Panel):
#----------------------------------------------------------------------
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
#Create Track Object List
self.TrackOlv = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.TrackOlv.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK
self.setTracks()
#Create Actions Objet List
self.ActionsOlv = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.setActions()
# create browse to source button
sourceBtn = wx.Button(self, wx.ID_ANY, "Browse Source")
sourceBtn.Bind(wx.EVT_BUTTON, self.onBrowseSource)
# create source txt box
self.txSource = wx.TextCtrl(self, wx.ID_ANY, name=u'txSource', value=u'')
# create browse dest button
destBtn = wx.Button(self, wx.ID_ANY, "Browse Destination")
destBtn.Bind(wx.EVT_BUTTON, self.onBrowseDest)
# create dest txt box
self.txDest = wx.TextCtrl(self, wx.ID_ANY, name=u'txDest', value=u'')
# create Move Files button
moveBtn = wx.Button(self, wx.ID_ANY, "Move Files")
moveBtn.Bind(wx.EVT_BUTTON, self.onMoveFiles)
# print list button - debug only
printBtn = wx.Button(self, wx.ID_ANY, "Print List")
printBtn.Bind(wx.EVT_BUTTON, self.onPrintBtn)
# create check box to include all sub files
self.cbSubfolders = wx.CheckBox(self, wx.ID_ANY,
label=u'Include Subfolders', name=u'cbSubfolders', style=0)
self.cbSubfolders.SetValue(True)
self.cbSubfolders.Bind(wx.EVT_CHECKBOX, self.OnCbSubfoldersCheckbox)
# create check box to repace file names
self.cbReplaceFilename = wx.CheckBox(self, wx.ID_ANY,
label=u'Replace Filename with Title Tag',
name=u'cbReplaceFilename', style=0)
self.cbReplaceFilename.SetValue(False)
self.cbReplaceFilename.Bind(wx.EVT_CHECKBOX, self.OnCbReplaceFilenameCheckbox)
# Create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
feedbackSizer = wx.BoxSizer(wx.VERTICAL)
sourceSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
feedbackSizer.Add(self.TrackOlv, 1, wx.ALL|wx.EXPAND, 2)
feedbackSizer.Add(self.ActionsOlv, 1, wx.ALL|wx.EXPAND, 2)
sourceSizer.Add(sourceBtn, 0, wx.ALL, 2)
sourceSizer.Add(self.txSource, 1, wx.ALL|wx.EXPAND, 2)
sourceSizer.Add(destBtn, 0, wx.ALL, 2)
sourceSizer.Add(self.txDest, 1, wx.ALL|wx.EXPAND, 2)
btnSizer.Add(printBtn)
btnSizer.Add(moveBtn, 0, wx.ALL, 2)
btnSizer.Add(self.cbSubfolders, 0, wx.ALL, 2)
btnSizer.Add(self.cbReplaceFilename, 0, wx.ALL, 2)
mainSizer.Add(feedbackSizer, 1 , wx.ALL|wx.EXPAND, 2)
mainSizer.Add(sourceSizer, 0, wx.ALL|wx.EXPAND, 2)
#mainSizer.Add(destSizer, 0, wx.ALL|wx.EXPAND, 2)
#mainSizer.Add(destSizer, 0, wx.All|wx.Expand, 2)
mainSizer.Add(btnSizer, 0, wx.ALL, 2)
self.SetSizer(mainSizer)
mainSizer.Fit(self)
#----------------------------------------------------------------------
# Set the GUI column headers and width
#----------------------------------------------------------------------
def setTracks(self, data=None):
self.TrackOlv.SetColumns([
ColumnDefn("Title", "left", 100, "title"),
ColumnDefn("Artist", "left", 100, "artist"),
ColumnDefn("Album", "left", 100, "album"),
ColumnDefn("Source", "left", 300, "source"),
ColumnDefn("Destination", "left", 300, "dest"),
])
def setActions(self, data=None):
self.ActionsOlv.SetColumns([
ColumnDefn("Time", "left", 100, "timestamp"),
ColumnDefn("Action", "left", 450, "action"),
ColumnDefn("Result", "left", 450, "result")
])
#----------------------------------------------------------------------
# GUI EVENTS
#-----------------------------------------------------------------------
#Select Source of files
def onBrowseSource(self, event):
print "OnBrowseSource"
source = selectFolder("Select the Source Directory")
print "--source :" + source
self.txSource.SetValue(source)
self.anEvent = Action(datetime.datetime.now(),source,"Set as Source dir")
self.ActionsOlv.AddObject(self.anEvent)
self.populateList()
#Select Source of files
def onBrowseDest(self, event):
print "OnBrowseDest"
dest = selectFolder("Select the Destination Directory")
print dest
self.txDest.SetValue(dest)
self.anEvent = Action(datetime.datetime.now(),dest,"Set as Destination dir")
self.ActionsOlv.AddObject(self.anEvent)
self.populateList()
def OnCbSubfoldersCheckbox(self, event):
print "cbSubfolder"
self.populateList()
def OnCbReplaceFilenameCheckbox(self, event):
print "cbReplaceFilename"
self.populateList()
def onMoveFiles(self, event):
print "onMoveFiles"
self.moveFiles()
def onPrintBtn(self, event):
print "onPrintBtn"
#Why does this work
#rowObj = self.dataOlv.GetSelectedObject()
#print rowObj.author
#print rowObj.title
#debug - how many item in the list... why does it only print 1?
itemcount = self.TrackOlv.GetItemCount()
print "-- itemcount: " + str(itemcount)
getData = self.TrackOlv.GetItemData(1)
print "-- getData: " + str(getData)
trackList = self.TrackOlv.GetObjects()
for tracks in trackList:
print tracks.atrTitle, tracks.atrArtist, tracks.atrAlbum, tracks.atrSource, tracks.atrDest
#-------------
#Computations
#-------------
def defineDestFilename(self, sFullDestPath):
print "define dest"
iCopyX = 0
bExists = False
sOrigName = sFullDestPath
#If the file does not exist return original path/filename
if os.path.isfile(sFullDestPath) == False:
print "-" + sFullDestPath + " is valid"
return sFullDestPath
#Add .copyX.mp3 to the end of the file and retest until a new filename is found
while bExists == False:
sFullDestPath = sOrigName
iCopyX += 1
sFullDestPath = sFullDestPath + ".copy" + str(iCopyX) + ".mp3"
if os.path.isfile(sFullDestPath) == False:
print "-" + sFullDestPath + " is valid"
self.lvActions.Append([datetime.datetime.now(),"Desitnation filename changed since file exists",sFullDestPath])
bExists = True
#return path/filename.copyX.mp3
return sFullDestPath
def populateList(self):
print "populateList"
sSource = self.txSource.Value
sDest = self.txDest.Value
#Initalize list to reset all values on any option change
itemcount = self.TrackOlv.GetItemCount()
print "-- itemcount: " + str(itemcount)
if itemcount > 0:
self.TrackOlv.DeleteAllItems()
print "--list cleaned"
#Create list of files
if self.cbSubfolders.Value == True:
listOfFiles = getListRecursive(sSource)
else:
listOfFiles = getList(sSource)
print listOfFiles
#prompt if no files detected
if listOfFiles == []:
self.anEvent = Action(datetime.datetime.now(),"Parse Source for .MP3 files","No .MP3 files in source directory")
self.ActionsOlv.AddObject(self.anEvent)
#Populate list after both Source and Dest are chosen
if len(sDest) > 1 and len(sDest) > 1:
print "-iterate listOfFiles"
for file in listOfFiles:
#gest Source and Filename
(sSource,sFilename) = os.path.split(file)
print "-- source: " + sSource
print "-- filename: " + sFilename
#sFilename = os.path.basename(file)
sTitle = getTitle(file)
print "-- title: " + sTitle
#Get artist
try:
sArtist = getArtist(file)
except UnicodeDecodeError:
print "unicode"
sArtist = "unkown"
print "-- artist: " + sArtist
#Get Album
sAlbum = getAblum(file)
print "-- album: " + sAlbum
# Make dest path = sDest + Artist + Album
sDestDir = os.path.join (sDest, sArtist)
sDestDir = os.path.join (sDestDir, sAlbum)
#If file exists change destination to *.copyX.mp3
if self.cbReplaceFilename.Value == True:
sDestDir = self.defineDestFilename(os.path.join(sDestDir,sTitle))
else:
sDestDir = self.defineDestFilename(os.path.join(sDestDir,sFilename))
print "-- dest: " + sDestDir
# Populate listview with track info
self.aTrack = Track(sTitle,sArtist,sAlbum,sSource,sDestDir)
self.TrackOlv.AddObject(Track(sTitle,sArtist,sAlbum,sSource,sDestDir))
self.Update()
print "** ITEM ADDED **"
else:
print "-list not iterated"
def moveFiles (self):
print "move files"
#for track in self.TrackOlv:
# print "-iterate SourceDest"
# #create dir
# (sDest,filename) = os.path.split(self.TrackOlv)
# print "-check dest"
#
# if not os.path.exists(sDest):
# print "-Created dest"
# os.makedirs(sDest)
# self.lvActions.Append([datetime.datetime.now(),sDest,"Created"])
# self.Update()
# self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1)
#
# #Move File
# print "-move file"
# shutil.move(SourceDest[0],SourceDest[1])
# self.lvActions.Append([datetime.datetime.now(),filename,"Moved"])
# self.Update()
# self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1)
#
#self.lvActions.Append([datetime.datetime.now(),"Move Complete","Success"])
#self.Update()
#self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1)
########################################################################
class MainFrame(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
title="MP3 Manager", size=(1024,768)) #W by H
panel = MainPanel(self)
########################################################################
class GenApp(wx.App):
#----------------------------------------------------------------------
def __init__(self, redirect=False, filename=None):
wx.App.__init__(self, redirect, filename)
#----------------------------------------------------------------------
def OnInit(self):
# create frame here
frame = MainFrame()
frame.Show()
return True
#----------------------------------------------------------------------
def main():
"""
Run the demo
"""
app = GenApp()
app.MainLoop()
if __name__ == "__main__":
main()
最佳答案
问题是 setTracks 方法中 ColumnDefn 中的第四个参数与 Track 对象的属性名称不匹配。如果它们不完全匹配,则它将无法正确映射,并且小部件中不会显示任何内容。
因此,在 setTracks 方法中将“title”更改为“atrTitle”等,或者在 Track 对象中执行相反的操作。
这是我在使用 ObjectListView 时遇到的少数问题之一。
关于python ObjectListView 用空行更新显示,即使列表具有有效数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5083563/
我遇到了一个奇怪的问题。我有这个: $(document).ready(function () {
我正在编写一个程序,它从列表中读取一些 ID,从中找出不同的 URL,然后将图像保存到我的 C: 驱动器中。 如果我在浏览器中导航到图像 URL,它们就会起作用。此外,如果我尝试从不同的服务器获取图像
我编写了一个 REST WCF RIA Silverlight 4.0 兼容服务,我可以从 javascript + jQuery.1.4.2.js + JSON2.js(当然,还可以从 .NET 4
我很确定这个网站实际上还没有得到回答。一劳永逸地,与 32 位有符号整数范围内的数字字符串匹配的最小正则表达式是什么,范围是 -2147483648至 2147483647 . 我必须使用正则表达式进
我有两个data.table;我想从那些与键匹配的元素中随机分配一个元素。我现在这样做的方式相当慢。 让我们具体点;这是一些示例数据: dt1<-data.table(id=sample(letter
我已经安装了 celery 、RabitMQ 和花。我可以浏览到花港。我有以下简单的工作人员,我可以将其附加到 celery 并从 python 程序调用: # -*- coding: utf-8 -
我正在使用 ScalaCheck 在 ScalaTest 中进行一些基于属性的测试。假设我想测试一个函数,f(x: Double): Double仅针对 x >= 0.0 定义的, 并返回 NaN对于
我想检查文件是否具有有效的 IMAGE_DOS_SIGNATURE (MZ) function isMZ(FileName : String) : boolean; var Signature: W
在 Herbert Schildt 的“Java:完整引用,第 9 版”中,有一个让我有点困惑的例子。它的关键点我无法理解可以概括为以下代码: class Test { public stat
我在工作中查看了一些代码,发现了一些我以前没有遇到过的东西: for (; ;) { // Some code here break; } 我们一直调用包含这个的函数,我最近才进去看看它是
在 Herbert Schildt 的“Java:完整引用,第 9 版”中,有一个让我有点困惑的例子。它的关键点我无法理解可以概括为以下代码: class Test { public stat
我试图编写一个函数,获取 2D 点矩阵和概率 p 并以概率 p 更改或交换每个点坐标 所以我问了一个question我试图使用二进制序列作为特定矩阵 swap_matrix=[[0,1],[1,0]]
这个问题在这里已经有了答案: Using / or \\ for folder paths in C# (5 个答案) 关闭 7 年前。 我在某个Class1中有这个功能: public v
PostgreSQL 10.4 我有一张 table : Column | Type ------------------------- id | integer| title
我正在 Postgresql 中编写一个函数,它将返回一些针对特定时区(输入)计算的指标。 示例结果: 主要问题是这只是一个指标。我需要从其他表中获取其他 9 个指标。 对于实现此目标的更简洁的方法有
我需要在 python 中模拟超几何分布(用于不替换采样元素的花哨词)。 设置:有一个装满人口许多弹珠的袋子。弹珠有两种类型,红色和绿色(在以下实现中,弹珠表示为 True 和 False)。从袋子中
我正在使用 MaterializeCSS 框架并动态填充文本输入。我遇到的一个问题是,在我关注该字段之前,valid 和 invalid css 类不会添加到我的字段中。 即使我调用 M.update
是否有重叠 2 个 div 的有效方法。 我有以下内容,但无法让它们重叠。 #top-border{width:100%; height:60px; background:url(image.jpg)
我希望你们中的一位能向我解释为什么编译器要求我在编译单元中重新定义一个静态固定长度数组,尽管我已经在头文件中这样做了。这是一个例子: 我的类.h: #ifndef MYCLASS_H #define
我正在使用旧线程发布试图解决相同问题的新代码。什么是安全 pickle ? this? socks .py from socket import socket from socket import A
我是一名优秀的程序员,十分优秀!