为什么无论我选择哪一个,这些按钮都会打开同一个文件?

huangapple go评论62阅读模式
英文:

Why do these buttons open the same file regardless of which on I select?

问题

以下是翻译好的部分:

I'm making a pdf 'date checker' in Python which tells me if every page of the pdf has tomorrows date at the top (for checking newspapers as part of my job).

So far so good until I attempted to put it all into a GUI, the buttons display the correct filename, but only open and check the last file in the list the buttons were generated from 'Files[i]'.

Can anybody figure out from my horrible nooby code why this is happening? please excuse the mess (I'm new) 为什么无论我选择哪一个,这些按钮都会打开同一个文件?

Here is my ugly code 为什么无论我选择哪一个,这些按钮都会打开同一个文件? I think the issue is either where I open the file using 'with open(files[i])' or 3rd line from the bottom where the buttons are created.
Any help would be greatly appreciated, thank you.

英文:

I'm making a pdf 'date checker' in Python which tells me if every page of the pdf has tomorrows date at the top (for checking newspapers as part of my job).

So far so good until I attempted to put it all into a GUI, the buttons display the correct filename, but only open and check the last file in he list the buttons were generated from 'Files[i]'.

Can anybody figure out from my horrible nooby code why this is happening? please excuse the mess (I'm new) 为什么无论我选择哪一个,这些按钮都会打开同一个文件?

Here is my ugly code 为什么无论我选择哪一个,这些按钮都会打开同一个文件? I think the issue is either where I open the file using
'with open(files[i])' or 3rd line from the bottom where the buttons are created.
Any help would be greatly appreciated, thank you.

import os, glob
import fileinput
import tkinter as tk
import dateutil
import datetime
from dateutil.relativedelta import *
from dateutil.easter import *
from dateutil.parser import *
from dateutil.rrule import *
import PyPDF2
from PyPDF2 import PdfReader
from datetime import datetime, timedelta
from tkinter import *



folder_path = 'C:users/axlra/documents/datechecker'
for filename in glob.glob(os.path.join(folder_path, '*.pdf')):
  with open(files[i], 'r') as f:
    text = f.read()
    print (files[i])
    print (len(text))




def checknow():
 tomorrow = (datetime.now() + timedelta(days=1)).strftime("%d-%m-%Y")
 file = open(files[i], 'rb')
 reader = PdfReader(files[i])
 total = len(reader.pages)
 for x in range(total+1):
  if x > total: file.close()


  page = reader.pages[0]
  found = False
  text = (page.extract_text())
  parts = []
  
  def visitor_body(text, cm, tm, fontDict, fontSize):
      y = tm[5]
      if y > 1600 and y < 10000:
          parts.append(text)
          
  page.extract_text(visitor_text=visitor_body)
  text_body = "".join(parts)
   #print(text_body)

  word = text_body
  word=word[22:-1]
  #print(word)
  prodate = parse(word)
  str_date = prodate.strftime("%d-%m-%Y")
  print(str_date)
  print(files[i])
  if tomorrow in str_date:
   found = True
  if found:
   #print(x)
   print("Tomorrow's date was found on page"+ " "+str(x))
  else:
   #print(x)
   print("Tomorrow's date was NOT found on page"+ " "+str(x))


location = os.getcwd() # get present working directory location here
counter = 0 #keep a count of all files found
files = [] #list to store all pdf files found at location


for file in os.listdir(location):
    try:
        if file.endswith(".pdf"):
            print ("pdf file found:\t", file)
            files.append(str(file))
            counter = counter

    except Exception as e:
        raise e
        print ("No files found here!")



root = Tk()


btn = [] #creates list to store the buttons ins

for i in range(counter): #this just popultes a list as a replacement for the actual inputs for troubleshooting purposes
    files.append(str(i))

for i in range(len(files)): #this says for *counter* in *however many elements there are in the list files*
    #the below line creates a button and stores it in an array we can call later, it will print the value of it's own text by referencing itself from the list that the buttons are stored in
    btn.append(Button(root, text=files[i], command=checknow))
    btn[i].pack() #this packs the buttons

                                                                 
root.mainloop()


Based off the given solutions, this is the working code, the solution was to completely get rid of the 'i list' and just use file_path:

import os
import tkinter as tk
from tkinter import messagebox
import os, glob
import fileinput
import tkinter as tk
import dateutil
import datetime
from dateutil.relativedelta import *
from dateutil.easter import *
from dateutil.parser import *
from dateutil.rrule import *
import PyPDF2
from PyPDF2 import PdfReader
from datetime import datetime, timedelta
from tkinter import *
import re
location = os.getcwd() 
counter = 0 
files = [] 


for file in os.listdir(location):
    try:
        if file.endswith(".pdf"):
            print ("pdf file found:\t", file)
            files.append(str(file))
            counter = counter

    except Exception as e:
        raise e
        print ("No files found here!")
        
tomorrow = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
tomorrow = tomorrow.replace(" ", "")
tomorrow2 = (datetime.now() + timedelta(days=-1)).strftime("%d.%m.%Y")
tomorrow2 = tomorrow.replace(" ", "")
tomorrow3 = (datetime.now() + timedelta(days=-1)).strftime("%A%e%B%Y")
tomorrow3 = tomorrow.replace(" ", "")
tomorrow4 = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
tomorrow4 = tomorrow.replace(" ", "")
tomorrow5 = (datetime.now() + timedelta(days=-1)).strftime("%A,%e%B")
tomorrow5 = tomorrow.replace(" ", "")
    
def open_pdf(file_path):
  file = open(file_path, 'rb')
  reader = PdfReader(file)
  total = len(reader.pages)
  for x in range(total):
   if x > x: file.close()
   page = reader.pages[x]
   text = (page.extract_text())
   text = text.replace(" ", "")
   #print(text)
   substring = tomorrow
   first_index = text.find(substring)
   if first_index != -1:
       second_index = text.find(substring, first_index + len(substring))
       if second_index != -1:
           print("Tomorrows date "+ tomorrow+ " appears twice on page"+ " "+str(x).format(substring))
       else:
           print("Tomorrows date "+ tomorrow+ " appears only once on page"+ " "+str(x)+" -".format(substring))
   else:
       print("Tomorrows date "+ tomorrow+ " does not appear on page"+ " "+str(x)+" ---".format(substring))   

def create_buttons(directory):
    for filename in os.listdir(directory):
        if filename.endswith(".pdf"):
            file_path = os.path.join(directory, filename)
            button = tk.Button(root, text=filename, command=lambda f=file_path: open_pdf(f))
            button.pack()

root = tk.Tk()
create_buttons(os.getcwd())
root.mainloop()

答案1

得分: 0

基本的答案是,在for i in range(len(files))结束后,i 不会像某些编程语言中那样被取消引用。一个简单的测试是这将给你一个i为2的值。

for i in range(3):
    pass
print(i)

所以,当你调用checknow()时,引用的文件将是files中的最后一个文件,因为在循环后,i 不再改变。

我过去曾经创建一个包含文件引用的类,以便每个类都保持自己的引用。我没有使用tkinter类的子类,但你可以。我提供一个示例来说明我所做的事情:

class FileButton:
    def checknow(self):
        file_name = self._file_name
        # 作为如何引用file_name的示例
        # 你也可以通过self._button.cget("text")来实现,而不必存储file_name
        pass

    def __init__(self, root, file_name):
        self._root = root
        self._file_name = file_name

        self._button = tkinter.Button(root, text=file_name, command=self.checknow)
        self._button.pack()

for i in range(len(files)):
    btn.append(FileButton(root, files[i]))

我没有测试过这个特定的代码,我的先前使用更多是用于标签和输入框,但其原则是相同的,我可以确认使用这种方式的回调函数是有效的。此外,如果你不再需要引用这些按钮,你也不必再将它们附加到btn列表中。

英文:

The basic answer is that at the end of for i in range(len(files)) the i does not get dereference like it does in some languages. A simple test to do is that this will give you an i of 2.

for i in range(3):
    pass
print(i)

So when you call checknow() the referenced file would be the last file in files since your i doesn't change after the loop.

Something I've done in the past is create a class encompassing it so that each one holds to their own references. I did it without subclassing the tkinter class, but you could. A sample for an idea of what I did is

class FileButton:
    def checknow(self):
        file_name = self._file_name
        #as an example of how you can reference the file_name.
        #you can also do this by doing self._button.cget("text") and not have to store file_name
        pass

    def __init__(self, root, file_name):
        self._root = root
        self._file_name = file_name

        self._button = tkinter.Button(root, text=file_name, command=self.checknow)
        self._button.pack()

for i in range(len(files)):
    btn.append(FileButton(root, files[i]))


I haven't tested this particular code, and my previous uses were more for labels and entries, but the principle of it was the same and I can confirm that using the callback in this manner worked. Also, if you don't need to reference the buttons anymore you don't have to append them to the btn list either.

huangapple
  • 本文由 发表于 2023年2月8日 12:50:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75381492.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定