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

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

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.

  1. import os, glob
  2. import fileinput
  3. import tkinter as tk
  4. import dateutil
  5. import datetime
  6. from dateutil.relativedelta import *
  7. from dateutil.easter import *
  8. from dateutil.parser import *
  9. from dateutil.rrule import *
  10. import PyPDF2
  11. from PyPDF2 import PdfReader
  12. from datetime import datetime, timedelta
  13. from tkinter import *
  14. folder_path = 'C:users/axlra/documents/datechecker'
  15. for filename in glob.glob(os.path.join(folder_path, '*.pdf')):
  16. with open(files[i], 'r') as f:
  17. text = f.read()
  18. print (files[i])
  19. print (len(text))
  20. def checknow():
  21. tomorrow = (datetime.now() + timedelta(days=1)).strftime("%d-%m-%Y")
  22. file = open(files[i], 'rb')
  23. reader = PdfReader(files[i])
  24. total = len(reader.pages)
  25. for x in range(total+1):
  26. if x > total: file.close()
  27. page = reader.pages[0]
  28. found = False
  29. text = (page.extract_text())
  30. parts = []
  31. def visitor_body(text, cm, tm, fontDict, fontSize):
  32. y = tm[5]
  33. if y > 1600 and y < 10000:
  34. parts.append(text)
  35. page.extract_text(visitor_text=visitor_body)
  36. text_body = "".join(parts)
  37. #print(text_body)
  38. word = text_body
  39. word=word[22:-1]
  40. #print(word)
  41. prodate = parse(word)
  42. str_date = prodate.strftime("%d-%m-%Y")
  43. print(str_date)
  44. print(files[i])
  45. if tomorrow in str_date:
  46. found = True
  47. if found:
  48. #print(x)
  49. print("Tomorrow's date was found on page"+ " "+str(x))
  50. else:
  51. #print(x)
  52. print("Tomorrow's date was NOT found on page"+ " "+str(x))
  53. location = os.getcwd() # get present working directory location here
  54. counter = 0 #keep a count of all files found
  55. files = [] #list to store all pdf files found at location
  56. for file in os.listdir(location):
  57. try:
  58. if file.endswith(".pdf"):
  59. print ("pdf file found:\t", file)
  60. files.append(str(file))
  61. counter = counter
  62. except Exception as e:
  63. raise e
  64. print ("No files found here!")
  65. root = Tk()
  66. btn = [] #creates list to store the buttons ins
  67. for i in range(counter): #this just popultes a list as a replacement for the actual inputs for troubleshooting purposes
  68. files.append(str(i))
  69. for i in range(len(files)): #this says for *counter* in *however many elements there are in the list files*
  70. #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
  71. btn.append(Button(root, text=files[i], command=checknow))
  72. btn[i].pack() #this packs the buttons
  73. 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:

  1. import os
  2. import tkinter as tk
  3. from tkinter import messagebox
  4. import os, glob
  5. import fileinput
  6. import tkinter as tk
  7. import dateutil
  8. import datetime
  9. from dateutil.relativedelta import *
  10. from dateutil.easter import *
  11. from dateutil.parser import *
  12. from dateutil.rrule import *
  13. import PyPDF2
  14. from PyPDF2 import PdfReader
  15. from datetime import datetime, timedelta
  16. from tkinter import *
  17. import re
  18. location = os.getcwd()
  19. counter = 0
  20. files = []
  21. for file in os.listdir(location):
  22. try:
  23. if file.endswith(".pdf"):
  24. print ("pdf file found:\t", file)
  25. files.append(str(file))
  26. counter = counter
  27. except Exception as e:
  28. raise e
  29. print ("No files found here!")
  30. tomorrow = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
  31. tomorrow = tomorrow.replace(" ", "")
  32. tomorrow2 = (datetime.now() + timedelta(days=-1)).strftime("%d.%m.%Y")
  33. tomorrow2 = tomorrow.replace(" ", "")
  34. tomorrow3 = (datetime.now() + timedelta(days=-1)).strftime("%A%e%B%Y")
  35. tomorrow3 = tomorrow.replace(" ", "")
  36. tomorrow4 = (datetime.now() + timedelta(days=-1)).strftime("%A,%B%e")
  37. tomorrow4 = tomorrow.replace(" ", "")
  38. tomorrow5 = (datetime.now() + timedelta(days=-1)).strftime("%A,%e%B")
  39. tomorrow5 = tomorrow.replace(" ", "")
  40. def open_pdf(file_path):
  41. file = open(file_path, 'rb')
  42. reader = PdfReader(file)
  43. total = len(reader.pages)
  44. for x in range(total):
  45. if x > x: file.close()
  46. page = reader.pages[x]
  47. text = (page.extract_text())
  48. text = text.replace(" ", "")
  49. #print(text)
  50. substring = tomorrow
  51. first_index = text.find(substring)
  52. if first_index != -1:
  53. second_index = text.find(substring, first_index + len(substring))
  54. if second_index != -1:
  55. print("Tomorrows date "+ tomorrow+ " appears twice on page"+ " "+str(x).format(substring))
  56. else:
  57. print("Tomorrows date "+ tomorrow+ " appears only once on page"+ " "+str(x)+" -".format(substring))
  58. else:
  59. print("Tomorrows date "+ tomorrow+ " does not appear on page"+ " "+str(x)+" ---".format(substring))
  60. def create_buttons(directory):
  61. for filename in os.listdir(directory):
  62. if filename.endswith(".pdf"):
  63. file_path = os.path.join(directory, filename)
  64. button = tk.Button(root, text=filename, command=lambda f=file_path: open_pdf(f))
  65. button.pack()
  66. root = tk.Tk()
  67. create_buttons(os.getcwd())
  68. root.mainloop()

答案1

得分: 0

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

  1. for i in range(3):
  2. pass
  3. print(i)

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

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

  1. class FileButton:
  2. def checknow(self):
  3. file_name = self._file_name
  4. # 作为如何引用file_name的示例
  5. # 你也可以通过self._button.cget("text")来实现,而不必存储file_name
  6. pass
  7. def __init__(self, root, file_name):
  8. self._root = root
  9. self._file_name = file_name
  10. self._button = tkinter.Button(root, text=file_name, command=self.checknow)
  11. self._button.pack()
  12. for i in range(len(files)):
  13. 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.

  1. for i in range(3):
  2. pass
  3. 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

  1. class FileButton:
  2. def checknow(self):
  3. file_name = self._file_name
  4. #as an example of how you can reference the file_name.
  5. #you can also do this by doing self._button.cget("text") and not have to store file_name
  6. pass
  7. def __init__(self, root, file_name):
  8. self._root = root
  9. self._file_name = file_name
  10. self._button = tkinter.Button(root, text=file_name, command=self.checknow)
  11. self._button.pack()
  12. for i in range(len(files)):
  13. 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:

确定