如何通过Tkinter在Python中创建可选择的图像“列表”

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

How to create a selectable "list" of images via Tkinter in Python

问题

以下是您要翻译的内容:

假设有一个包含大量图片的文件夹。当用户打开窗口时,程序应加载文件夹中的所有图像,并以可选择的“ListBox”形式显示它们,带有滚动条,其中不仅包括图像,还包括它们的名称。

我已经尽力在图片1中绘制了它。
图片1

因此,程序应该像图片2中所示那样工作。
图片2

用户选择需要删除的图像,然后按下删除按钮。之后,图片会从文件夹中消失,所谓的“列表”会自动更新,显示文件夹中剩余的图片。

问题是,我不知道如何创建这个可“选择”的图像列表框。之所以称其为ListBox(在这种情况下可能不正确),是因为我设法创建了一个程序,使用ListBox小部件,仅显示文件夹中图片的名称,没有它们的图像。但是,我可以选择其中的多个并一次删除多个。

所以我的问题是,'是否可以通过Tkinter创建我所描述的这个东西?' 我只需要知道如何创建带有图像和它们名称的这种“ListBox”。

如果有人有任何关于如何做到这一点的想法或见解,请分享
我将非常感激!
提前感谢所有人!

英文:

Say there is a folder with a bunch of pictures. When a user opens the window the program should load all of the images in that are in the folder and display them in a kind of a selectable "ListBox" with ScrollBar, which contains not only images, but their names underneath as well.

I've tried my best to draw it in Picture 1.
Picture 1

So the program should work like this, as in Picture 2.
Picture 2

User selects the images that needs to be deleted and presses the delete_button. After that the pictures disappear from the folder and the so called "list" of images automatically updates displaying the remaining pictures in the folder.

The problem is that I don't know how to create this "selectable" ListBox of images. The reason why I call it ListBox (it's probably not correct in this case) is because I managed to create a program, using ListBox widget, that displays only the names of the pictures that are in the folder, without images of them though. However, I can select multiple of them and delete several in one time.

So my question is 'Is it possible to create the thing I've described via Tkinter?' I only need to know how to create such 'ListBox' with images and their names

If anybody has any ideas or insights on how to do it, please, share it
I'll be extremely grateful!
Thanks to everyone in advance!

答案1

得分: 0

这是您提供的代码的翻译部分:

  1. # needed imports
  2. import tkinter as tk
  3. from PIL import Image, ImageTk
  4. import os
  5. from PIL.Image import Resampling
  6. from math import ceil
  7. # create a window
  8. root = tk.Tk()
  9. # set window's size
  10. screen_width = root.winfo_screenwidth()
  11. screen_height = root.winfo_screenheight()
  12. root.geometry("%dx%d" % (screen_width, screen_height))
  13. # configure columns and rows
  14. root.columnconfigure(0, weight=3)
  15. root.columnconfigure(2, weight=1)
  16. root.rowconfigure(0, weight=3)
  17. # create canvas, which will hold the selectable buttons
  18. canvas = tk.Canvas(root, bg='Black')
  19. canvas.grid(row=0, column=0, sticky='nwes')
  20. # create scrollbar for canvas
  21. scroll = tk.Scrollbar(root, orient="vertical")
  22. scroll.grid(row=0, column=1, sticky='nswe')
  23. # create frame which will be placed into canvas
  24. containter = tk.Frame(root, padx=10)
  25. # create another frame which will hold a label and a button for deleting selected images
  26. side_containter = tk.Frame(root, padx=10)
  27. side_containter.grid(row=0, column=2)
  28. # create label which will indicate how many images are chosen
  29. mylable = tk.Label(side_containter, text='Chosen: ', font=(None, 20), pady=150)
  30. mylable.pack()
  31. # create button by pressing which the selected images will be deleted
  32. delete_button = tk.Button(side_containter, text='Delete', font=(None, 20), command=lambda: delete())
  33. delete_button.pack()
  34. # make the canvas expandable
  35. def update_size(e=None):
  36. canvas["scrollregion"] = canvas.bbox("all")
  37. # create a binding on canvas
  38. canvas.bind('<Configure>', update_size)
  39. canvas.after_idle(update_size)
  40. # declare the needed directory, where the images are
  41. path = f"{os.getcwd()}\{'Acceptances'}\Acceptance1"
  42. # create two lists, first one is going to hold image objects, second one will hold their 'labels'
  43. image_list = [] # 1-st parameter
  44. image_vars = [] # 2-nd parameter
  45. # collect all the files that are in the directory (assume that there are only needed types of file like .png or .jpg
  46. # (otherwise a fileter should be created for unwanted types of files)
  47. get_image_files = lambda: os.listdir(path) # 3-rd parameter
  48. # create function which takes three parameters, which I declared above.
  49. def fill_canvas(image_list, image_vars, image_files):
  50. global path
  51. # using for loop append lists that will hold image objects and the names to them
  52. for image in range(0, len(image_files)):
  53. image_list.append(ImageTk.PhotoImage(Image.open(path + '/' + image_files[image]), Resampling.LANCZOS)) # image object
  54. image_vars.append(f'img_{image}') # names
  55. # declare how many columns do you want and calculate how many rows will be needed by dividing quantity of images in the folder on the number of columns
  56. columns = 5
  57. rows = ceil(len(image_vars) / columns)
  58. # declare:
  59. positions = [] # list which will hold the positions of images in a row like [0, 1, 2, 3 ,4]
  60. matrix = {} # dictionary which will be kind of a matrix, indicating what positions each row contains
  61. pos = 0 # variable to count the positions
  62. # via for loop fill the matrix
  63. for row in range(rows):
  64. for column in range(columns):
  65. if pos == len(image_vars):
  66. break
  67. else:
  68. positions.append(pos)
  69. pos += 1
  70. matrix[row] = positions
  71. positions = []
  72. # create button objects using for loop
  73. for key, value in matrix.items(): # take a row and the positions it contains like [row1]:[0,1,2,3,4]
  74. for n in range(len(image_vars)): # for each image that is in the folder
  75. if n in value: # if the count doesn't go beyond the quantity of the images in the folder do:
  76. # create a button and add it place it into the frame
  77. globals()[image_vars[n]] = tk.Button(containter, text=image_vars[n], font=(None, 12),
  78. image=image_list[n], compound=tk.TOP, bg='snow',
  79. command=lambda n=n: print_button(n))
  80. globals()[image_vars[n]].grid(row=key, column=value.index(n))
  81. # make the canvas scrollable
  82. containter.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox('all')))
  83. # place the frame with buttons inside of the canvas
  84. canvas.create_window((0, 0), window=containter, anchor="nw", tags='my_tag')
  85. # set configs on scrollbar and canvas
  86. scroll.config(command=canvas.yview)
  87. canvas.config(yscrollcommand=scroll.set)
  88. # set canvas scroll regions
  89. def set_canvas_scrollregion(event):
  90. width = event.width - 4
  91. canvas.itemconfigure("my_tag", width=width)
  92. canvas.config(scrollregion=canvas.bbox("all"))
  93. # create binding
  94. canvas.bind("<Configure>", lambda e: set_canvas_scrollregion)
  95. # call the function that will display the buttons
  96. fill_canvas(image_list, image_vars, get_image_files())
  97. # declare an empty list which will hold the selected buttons
  98. selected_buttons = []
  99. # create a function which will change a background of a button which was selected and add it to the counter of selected ones
  100. def print_button(image):
  101. if image not in selected_buttons: # if the pressed button is not in selected_buttons, then it'll add it and will change the background color
  102. selected_buttons.append(image)
  103. globals()[image_vars[image]].config(bg='light blue')
  104. else: # if it's there it will remove the button from the list and will change the color back as well
  105. selected_buttons.remove(image)
  106. globals()[image_vars[image]].config(bg='snow')
  107. mylable.config(text=f'Chosen: {len(selected_buttons)}') # change the counter
  108. # create delete selected buttons function
  109. def delete():
  110. global selected_buttons, get_image_files, image_list, image_vars
  111. image_files = get_image_files() # use our lambda function to get all files from a folder
  112. if not selected_buttons: # if selected_buttons list is empty
  113. print('nothing is selected')
  114. else: # if not and something was selected
  115. for photo in selected_buttons:
  116. os.remove(f'{path}\{image_files[photo]}') # remove each image that was selected from the computer
  117. # to make the canvas display the remaining buttons after the deleting selected ones:
  118. canvas.delete("all") # clear the canvas
  119. selected_buttons = [] # reset selected_buttons list
  120. mylable.config(text='Chosen: 0') # reset counter label
  121. # reset those lists which will contain the remaining images and their names in the folder
  122. image_list = []
  123. image_vars = []
  124. # call the function that will display the remaining files in the folder
  125. fill_canvas(image_list, image_vars, get
  126. <details>
  127. <summary>英文:</summary>
  128. It&#39;s been quite a while, but I&#39;m back now with a solution which I expected to come up with. In a couple of days after posting this question I postponed working on this idea cause the guy who initially asked me to create this program said that it&#39;s unnecessary. Though in the beginning I thought the opposite. Anyway, these days I&#39;ve been playing around with this idea in my spare time. I managed to do something sketchy, but at least it demonstrates a little bit of the program I wanted to create back then.
  129. &gt; Before I post the pictures and the code I want to say thank you to
  130. &gt; everyone who tried to help me! :)
  131. **Here are some pictures:**
  132. This
  133. [Picture][1] shows how some of the images are getting selected.
  134. And this [Picture][2] shows how the selected images are being deleted.
  135. **Here is the code I sketched:**
  136. # needed imports
  137. import tkinter as tk
  138. from PIL import Image, ImageTk
  139. import os
  140. from PIL.Image import Resampling
  141. from math import ceil
  142. # create a window
  143. root = tk.Tk()
  144. # set window&#39;s size
  145. screen_width = root.winfo_screenwidth()
  146. screen_height = root.winfo_screenheight()
  147. root.geometry(&quot;%dx%d&quot; % (screen_width, screen_height))
  148. # configure columns and rows
  149. root.columnconfigure(0, weight=3)
  150. root.columnconfigure(2, weight=1)
  151. root.rowconfigure(0, weight=3)
  152. # create canvas, which will hold the selectable buttons
  153. canvas = tk.Canvas(root, bg=&#39;Black&#39;)
  154. canvas.grid(row=0, column=0, sticky=&#39;nwes&#39;)
  155. # create scrollbar for canvas
  156. scroll = tk.Scrollbar(root, orient=&quot;vertical&quot;)
  157. scroll.grid(row=0, column=1, sticky=&#39;nswe&#39;)
  158. # create frame which will be placed into canvas
  159. containter = tk.Frame(root, padx=10)
  160. # create another frame which will hold a label and a button for deleting selected images
  161. side_containter = tk.Frame(root, padx=10)
  162. side_containter.grid(row=0, column=2)
  163. # create label which will indicate how many images are chosen
  164. mylable = tk.Label(side_containter, text=&#39;Chosen: &#39;, font=(None, 20), pady=150)
  165. mylable.pack()
  166. # create button by pressing which the selected images will be deleted
  167. delete_button = tk.Button(side_containter, text=&#39;Delete&#39;, font=(None, 20), command=lambda: delete())
  168. delete_button.pack()
  169. # make the canvas expandable
  170. def update_size(e=None):
  171. canvas[&quot;scrollregion&quot;] = canvas.bbox(&quot;all&quot;)
  172. # create a binding on canvas
  173. canvas.bind(&#39;&lt;Configure&gt;&#39;, update_size)
  174. canvas.after_idle(update_size)
  175. # declare the needed directory, where the images are
  176. path = f&quot;{os.getcwd()}\{&#39;Acceptances&#39;}\Acceptance1&quot;
  177. # create two lists, first one is going to hold image objects, second one will hold their &#39;labels&#39;
  178. image_list = [] # 1-st parameter
  179. image_vars = [] # 2-nd parameter
  180. # collect all the files that are in the directory (assume that there are only needed types of file like .png or .jpg
  181. # (otherwise a fileter should be created for unwanted types of files)
  182. get_image_files = lambda: os.listdir(path) # 3-rd parameter
  183. # create function which takes three parameters, which I declared above.
  184. def fill_canvas(image_list, image_vars, image_files):
  185. global path
  186. # using for loop append lists that will hold image objects and the names to them
  187. for image in range(0, len(image_files)):
  188. image_list.append(ImageTk.PhotoImage(Image.open(path + &#39;/&#39; + image_files[image]), Resampling.LANCZOS)) # image object
  189. image_vars.append(f&#39;img_{image}&#39;) # names
  190. # declare how many columns do you want and calculate how many rows will be needed by dividing quantity of images in the folder on the number of columns
  191. columns = 5
  192. rows = ceil(len(image_vars) / columns)
  193. # declare:
  194. positions = [] # list which will hold the positions of images in a row like [0, 1, 2, 3 ,4]
  195. matrix = {} # dictionary which will be kind of a matrix, indicating what positions each row contains
  196. pos = 0 # variable to count the positions
  197. # via for loop fill the matrix
  198. for row in range(rows):
  199. for column in range(columns):
  200. if pos == len(image_vars):
  201. break
  202. else:
  203. positions.append(pos)
  204. pos += 1
  205. matrix[row] = positions
  206. positions = []
  207. # create button objects using for loop
  208. for key, value in matrix.items(): # take a row and the positions it contains like [row1]:[0,1,2,3,4]
  209. for n in range(len(image_vars)): # for each image that is in the folder
  210. if n in value: # if the count doesn&#39;t go beyond the quantity of the images in the folder do:
  211. # create a button and add it place it into the frame
  212. globals()[image_vars[n]] = tk.Button(containter, text=image_vars[n], font=(None, 12),
  213. image=image_list[n], compound=tk.TOP, bg=&#39;snow&#39;,
  214. command=lambda n=n: print_button(n))
  215. globals()[image_vars[n]].grid(row=key, column=value.index(n))
  216. # make the canvas scrollable
  217. containter.bind(&#39;&lt;Configure&gt;&#39;, lambda e: canvas.configure(scrollregion=canvas.bbox(&#39;all&#39;)))
  218. # place the frame with buttons inside of the canvas
  219. canvas.create_window((0, 0), window=containter, anchor=&quot;nw&quot;, tags=&#39;my_tag&#39;)
  220. # set configs on scrollbarr and canvas
  221. scroll.config(command=canvas.yview)
  222. canvas.config(yscrollcommand=scroll.set)
  223. # set canvas scroll regions
  224. def set_canvas_scrollregion(event):
  225. width = event.width - 4
  226. canvas.itemconfigure(&quot;my_tag&quot;, width=width)
  227. canvas.config(scrollregion=canvas.bbox(&quot;all&quot;))
  228. # create binding
  229. canvas.bind(&quot;&lt;Configure&gt;&quot;, lambda e: set_canvas_scrollregion)
  230. # call the function that will display the buttons
  231. fill_canvas(image_list, image_vars, get_image_files())
  232. # declare an empty list which will hold the selected buttons
  233. selected_buttons = []
  234. # create a function which will change a background of a button which was selected and add it to the counter of selected ones
  235. def print_button(image):
  236. if image not in selected_buttons: # if the pressed button is not in selected_buttons, then it&#39;ll add it and will change the backgorund color
  237. selected_buttons.append(image)
  238. globals()[image_vars[image]].config(bg=&#39;light blue&#39;)
  239. else: # if it&#39;s there it will remove the button from the list and will change the color back as well
  240. selected_buttons.remove(image)
  241. globals()[image_vars[image]].config(bg=&#39;snow&#39;)
  242. mylable.config(text=f&#39;Chosen: {len(selected_buttons)}&#39;) # change the counter
  243. # create delete selected buttons function
  244. def delete():
  245. global selected_buttons, get_image_files, image_list, image_vars
  246. image_files = get_image_files() # use our lambda function to get all files from a folder
  247. if not selected_buttons: # if selected_buttons list is empty
  248. print(&#39;nothing is selected&#39;)
  249. else: # if not and something was selected
  250. for photo in selected_buttons:
  251. os.remove(f&#39;{path}\{image_files[photo]}&#39;) # remove each image that was selected from the computer
  252. # to make the canvas display the remaining buttons after the deleting selected ones:
  253. canvas.delete(&quot;all&quot;) # clear the canvas
  254. selected_buttons = [] # reset selected_buttons list
  255. mylable.config(text=&#39;Chosen: 0&#39;) # reset counter label
  256. # reset those lists which will contain the remaining images and their names in the folder
  257. image_list = []
  258. image_vars = []
  259. # call the function that will display the remaining files in the folder
  260. fill_canvas(image_list, image_vars, get_image_files())
  261. # start the mainloop
  262. root.mainloop()
  263. I believe there is a better and a nicer way of doing it than mine, but I just wanted to share it with everyone for further reference in case someone ever needs to do something alike.
  264. [1]: https://i.stack.imgur.com/zu17J.png
  265. [2]: https://i.stack.imgur.com/N8sUV.png
  266. </details>

huangapple
  • 本文由 发表于 2023年7月13日 22:30:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76680546.html
匿名

发表评论

匿名网友

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

确定