前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Tkinter 导致的无限循环问题

Tkinter 导致的无限循环问题

原创
作者头像
华科云商小徐
发布于 2024-10-12 07:31:10
发布于 2024-10-12 07:31:10
17100
代码可运行
举报
文章被收录于专栏:小徐学爬虫小徐学爬虫
运行总次数:0
代码可运行

在使用 Tkinter 时,出现无限循环问题通常与事件绑定、函数调用以及窗口更新循环的方式有关。Tkinter 是一个事件驱动的 GUI 库,它依赖主循环 (mainloop()) 来处理用户交互和事件。如果代码的某一部分引发了循环或递归调用,可能会导致无限循环或应用程序无响应。

1、问题背景

我有一个脚本,在添加了用于用户交互的文件查询框之前一直运行良好。现在,它会不断重复询问问题,只有当强制使以下命令 (shutil.copy2) 崩溃(通过使输入/输出文件相同)时才退出。为什么会这样?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import os, xml, arcpy, shutil, datetime, Tkinter,tkFileDialog
from xml.etree import ElementTree as et
​
path=os.getcwd()
RootDirectory=path
arcpy.env.workspace = path
Count=0
​
Generated_XMLs=RootDirectory+'\GeneratedXML_LOG.txt'
f = open(Generated_XMLs, 'a')
f.write("Log of Metadata Creation Process - Update: "+str(datetime.datetime.now())+"\n")
f.close()for root, dirs, files in os.walk(RootDirectory, topdown=False):
    #print root, dirs
    for directory in dirs:
        currentPath=os.path.join(root,directory)
        os.chdir(currentPath)
        arcpy.env.workspace = currentPath
        print currentPath
#def Create_xml(currentPath):
​
        FileList = arcpy.ListFeatureClasses()
        zone="_Zone"for File in FileList:
            Count+=1
            FileDesc_obj = arcpy.Describe(File)
            FileNm=FileDesc_obj.file
            print FileNm
​
            check_meta=os.listdir(currentPath)
            existingXML=FileNm[:FileNm.find('.')]
            existingExtension=FileNm[FileNm.find('.'):]
            print "XML: "+existingXML
            print check_meta
            #if  existingXML+'.xml' in check_meta:
            for f in check_meta:
             if f.startswith(existingXML) and f.endswith('.xml'):
                print "exists, file name:", f
                newMetaFile=FileNm+"_2012Metadata.xml"
                shutil.copy2(f, newMetaFile)
​
代码导致循环
     else:
        #print "Does not exist"
        newMetaFile=FileNm+"_BaseMetadata.xml"
        root = Tkinter.Tk()
        file = tkFileDialog.askopenfile(parent=root,mode='rb',title='Choose a xml base file to match with: '+File)
        if file != None:
             metafile=os.path.abspath(file.name)
             file.close()
             print metafile
             shutil.copy2(metafile,newMetaFile)
             print "copied"
        else:
        shutil.copy2('L:\Data_Admin\QA\Metadata_python_toolset\Master_Metadata.xml', newMetaFile)
​
    tree=et.parse(newMetaFile)        
    print "Processing: "+str(File)  
​
剩下的工作代码
            for node in tree.findall('.//title'):
                node.text = str(FileNm)
            for node in tree.findall('.//northbc'):
                node.text = str(FileDesc_obj.extent.YMax)
            for node in tree.findall('.//southbc'):
                node.text = str(FileDesc_obj.extent.YMin)
            for node in tree.findall('.//westbc'):
                node.text = str(FileDesc_obj.extent.XMin)
            for node in tree.findall('.//eastbc'):
                node.text = str(FileDesc_obj.extent.XMax)        
            for node in tree.findall('.//native/nondig/formname'):
                node.text = str(os.getcwd()+"\\"+File)
            for node in tree.findall('.//native/digform/formname'):
                node.text = str(FileDesc_obj.featureType)
            for node in tree.findall('.//avlform/nondig/formname'):
                node.text = str(FileDesc_obj.extension)
            for node in tree.findall('.//avlform/digform/formname'):
                node.text = str(float(os.path.getsize(File))/int(1024))+" KB"
            for node in tree.findall('.//theme'):
                node.text = str(FileDesc_obj.spatialReference.name +" ; EPSG: "+str(FileDesc_obj.spatialReference.factoryCode))
            print node.text
            projection_info=[]
            Zone=FileDesc_obj.spatialReference.name
​
            if "GCS" in str(FileDesc_obj.spatialReference.name):
                projection_info=[FileDesc_obj.spatialReference.GCSName, FileDesc_obj.spatialReference.angularUnitName, FileDesc_obj.spatialReference.datumName, FileDesc_obj.spatialReference.spheroidName]
                print "Geographic Coordinate system"
            else:
                projection_info=[FileDesc_obj.spatialReference.datumName, FileDesc_obj.spatialReference.spheroidName, FileDesc_obj.spatialReference.angularUnitName, Zone[Zone.rfind(zone)-3:]]
                print "Projected Coordinate system"
            x=0
            for node in tree.findall('.//spdom'):
                for node2 in node.findall('.//keyword'):
                    print node2.text
                    node2.text = str(projection_info[x])
                    print node2.text
                    x=x+1
​
​
            tree.write(newMetaFile)
​
            f = open(Generated_XMLs, 'a')
            f.write(str(Count)+": "+File+"; "+newMetaFile+"; "+currentPath+"\n")
            f.close()
​
​
​
    #        Create_xml(currentPath)
​
​

2、解决方案

这个问题是由使用 tkFileDialog.askopenfile() 函数引起的,它会打开一个文件选择对话框,允许用户选择一个文件。但是,如果没有选择文件,file 变量将为 None,并且 shutil.copy2() 函数将在没有源文件的情况下尝试复制文件,这会导致无限循环。

为了解决这个问题,需要在使用 shutil.copy2() 函数之前检查 file 变量是否为 None。如果为 None,则需要执行其他操作,例如显示错误消息或退出脚本。

以下是我修改后的代码示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import os, xml, arcpy, shutil, datetime, Tkinter,tkFileDialog
from xml.etree import ElementTree as et
​
path=os.getcwd()
RootDirectory=path
arcpy.env.workspace = path
Count=0
​
Generated_XMLs=RootDirectory+'\GeneratedXML_LOG.txt'
f = open(Generated_XMLs, 'a')
f.write("Log of Metadata Creation Process - Update: "+str(datetime.datetime.now())+"\n")
f.close()for root, dirs, files in os.walk(RootDirectory, topdown=False):
    #print root, dirs
    for directory in dirs:
        currentPath=os.path.join(root,directory)
        os.chdir(currentPath)
        arcpy.env.workspace = currentPath
        print currentPath
#def Create_xml(currentPath):
​
        FileList = arcpy.ListFeatureClasses()
        zone="_Zone"for File in FileList:
            Count+=1
            FileDesc_obj = arcpy.Describe(File)
            FileNm=FileDesc_obj.file
            print FileNm
​
            check_meta=os.listdir(currentPath)
            existingXML=FileNm[:FileNm.find('.')]
            existingExtension=FileNm[FileNm.find('.'):]
            print "XML: "+existingXML
            print check_meta
            #if  existingXML+'.xml' in check_meta:
            for f in check_meta:
             if f.startswith(existingXML) and f.endswith('.xml'):
                print "exists, file name:", f
                newMetaFile=FileNm+"_2012Metadata.xml"
                shutil.copy2(f, newMetaFile)
​
代码导致循环
     else:
        #print "Does not exist"
        newMetaFile=FileNm+"_BaseMetadata.xml"
        root = Tkinter.Tk()
        file = tkFileDialog.askopenfile(parent=root,mode='rb',title='Choose a xml base file to match with: '+File)
        if file != None:
             metafile=os.path.abspath(file.name)
             file.close()
             print metafile
             shutil.copy2(metafile,newMetaFile)
             print "copied"
        else:
             print "No file selected. Exiting..."
             sys.exit(0)
​
    tree=et.parse(newMetaFile)        
    print "Processing: "+str(File)  
​
剩下的工作代码
            for node in tree.findall('.//title'):
                node.text = str(FileNm

Tkinter 中,避免无限循环的关键是:

  1. 不要直接调用事件处理程序,而是通过事件绑定来调用。
  2. 使用 after() 而不是递归调用或阻塞循环,确保 GUI 能够继续响应用户输入。
  3. 避免在事件处理程序中使用阻塞操作,如有必要,使用多线程或将任务分段处理。
  4. 谨慎使用 update(),频繁的 update() 调用可能导致无限循环,应使用 after() 进行调度。

通过合理设计事件处理逻辑,可以避免无限循环,并确保 Tkinter 应用程序始终保持响应状态。如果你有具体的代码或错误信息,我可以帮助进一步调试。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验