【问题标题】:How to make a image viewer with left right functionality in tkinter?如何在 tkinter 中制作具有左右功能的图像查看器?
【发布时间】:2021-08-08 06:56:55
【问题描述】:

我在list 中有一堆链接和标签,用于查看我想要制作具有下一个上一个 功能的图像查看器。我的各个图像的链接和标签位于list。到目前为止,我已经尝试过:

urls=[url,url1,url2,url3]
labels=["label 1","label 2","label 3","label 4"]

images=[]
for ur in urls:
    raw_data = urllib.request.urlopen(ur).read()
    im = Image.open(io.BytesIO(raw_data))
    image = ImageTk.PhotoImage(im)
    images.append(image)

现在我在 images 中准备好了图片,现在我想在图片查看器中显示它,但在图片查看器中只能看到最后一张图片。

Label(root).grid(row=1,column=1)

for i in range(len(images)):
    image_label=Label(root,image=images[i])
    image_label.grid(row=1,column=2)
    
    name=Label(root,text=labels[i])
    name.grid(row=2,column=2)

def left():
    image_label=Label(root,image=images[i-1])
    image_label.grid(row=1,column=2)

def right():
    image_label=Label(root,image=images[i+1])
    image_label.grid(row=1,column=2)
    
left_button=Button(root,text="Left",command=left)
left_button.grid(row=2,column=1)

right_button=Button(root,text="Right",command=right)
right_button.grid(row=2,column=3)

右键不工作,左键工作,但只有一次。当我第二次单击左键时,没有任何效果。
单击右键时出错:

line 45, in right
    image_label=Label(root,image=images[i+1])
IndexError: list index out of range

【问题讨论】:

  • This 代码可能对您有所帮助
  • @CoolCloud 实际上是的,如果我发现我肯定不会问/回答。 :)

标签: python tkinter image-viewer


【解决方案1】:

代码与原始发布的示例非常接近。

Button 中没有lambda,直接向前command 可以访问左右功能。

名称标签是不必要的,因为label 对象已经具有text 属性,因此我将图像和文本集成到单个label 中并增加了字体大小。

label 复合用于控制图像相对于文本的显示位置,我选择了top。也就是说,图片会放在文字上方。

在函数中使用global会跟踪count


from tkinter import Tk, Label, Frame, Button
from PIL import ImageTk, Image
import io
import requests
import urllib 

root = Tk()
urls = [url, url1, url2, url3]
labels = ["label 1","label 2","label 3","label 4"]
count = -1
images = []
for ur in urls:
    raw_data = urllib.request.urlopen( ur ).read()
    im = Image.open(io.BytesIO( raw_data ))
    image = ImageTk.PhotoImage(im)
    images.append(image)

def left( ):
    global count
    count = (count - 1) % len(images)
    image_label.config(image = images[count], text = labels[count])

def right( ):
    global count
    count = (count + 1) % len(images)
    image_label.config(image = images[count], text = labels[count])

image_label = Label(
    root, image = images[count], font = "Helvetica 20 normal",
    text = labels[count], compound = "top")
image_label.grid(row = 0, column = 0, columnspan = 2, sticky = "nsew")

Button(
    root, text = "<< LEFT", command = left).grid( row = 1, column = 0, sticky = "ew")
Button(
    root, text = "RIGHT >>", command = right).grid(row = 1, column = 1, sticky = "ew")

right( ) # display first image
root.mainloop()

【讨论】:

  • 实际上比其他答案更好的解释。是的!接近原始代码。 :)
  • 好一个@Xitiz。编码愉快。
【解决方案2】:

这是一种通过显示和隐藏带有图像及其名称的Labels 对来实现此目的的方法。出于开发和测试目的,它从磁盘加载图像而不是下载它们,但您可以轻松地将其替换为您的问题。

from pathlib import Path
from PIL import Image, ImageTk
from tkinter import Button, Tk, Label


root = Tk()
root.title('Image Viewer')

# Create thumbnails of all the images.
image_folder = '/path/to/image/folder'
images = []
for filepath in Path(image_folder).iterdir():
    img = Image.open(filepath)
    w, h = img.size
    if w > h:
        f = 100 / w
        nw, nh = 100, int(f*h)
    else:
        f = 100 / h
        nw, nh = int(f*w), 100
    # Offsets to center thumbnail within (100, 100).
    woff, hoff = (100-nw) // 2, (100-nh) // 2
    img = img.resize((nw, nh), Image.BICUBIC)  # Shrink so largest dimen is 100.
    thumbnail = Image.new('RGBA', (100, 100), (255, 255, 255, 0))  # Blank.
    thumbnail.paste(img, (woff, hoff))  # Offset keep it centered.
    images.append(ImageTk.PhotoImage(thumbnail))

names = ['Name 1', 'Name 2', 'Name 3', 'Name 4']

def get_images():
    """Create all image and name Label pairs but initially  hidden."""
    global image_labels, name_labels

    image_labels, name_labels  = [], []
    for i, (img, name) in enumerate(zip(images, names)):
        image_label = Label(root, image=img)
        image_label.grid(row=1, column=2)
        image_labels.append(image_label)

        name_label = Label(root, text=name)
        name_label.grid(row=2, column=2)
        name_labels.append(name_label)

        hide(i)

def hide(i):
    """Hide specified image and name pair."""
    image_labels[i].grid_remove()
    name_labels[i].grid_remove()

def show(i):
    """Unhide specified image and name pair."""
    image_labels[i].grid()
    name_labels[i].grid()

def shift(direction):
    """Display the image and pair before or after the current one that is
    `direction` steps away (usually +/-1).
    """
    global current
    hide(current)
    current = (current + direction) % len(images)
    show(current)


left_button = Button(root, text="Left", command=lambda: shift(-1))
left_button.grid(row=2, column=1)

right_button = Button(root, text="Right", command=lambda: shift(+1))
right_button.grid(row=2, column=3)

get_images()
current = 0  # Currently displayed image.
show(current)

root.mainloop()

运行截图:

【讨论】:

  • 真正独特的方法。 :) 但这真的比其他方法更好吗?
  • 它是否更好当然取决于您认为重要的品质。它的好处是它主要是数据驱动的,一旦一切就绪,显示不同的图像和相关的名称标签对只需隐藏和取消隐藏其中的几个。
【解决方案3】:

在左移或右移时应该只更新图像标签,而不是创建新标签。 使用模数% 查找下一回合。

为了减少代码和可执行文件,我在这里使用了 PySimpleGUI 中的图像数据和图像的简单名称。

import tkinter as tk
import PySimpleGUI as sg

def shift(num):
    global index
    index = (index + num) % size
    label1.configure(image=images[index])
    label2.configure(text =labels[index])

root = tk.Tk()

images = [tk.PhotoImage(data=image) for image in sg.EMOJI_BASE64_HAPPY_LIST]
size = len(images)
labels = [f'Image {i:0>2d}' for i in range(size)]
index = 0

label1 = tk.Label(root, image=images[index])
label1.grid(row=1, column=2)
label2 = tk.Label(root, text=labels[index])
label2.grid(row=2, column=2)

button1 = tk.Button(root, text="<LEFT",  width=6, anchor='center', command=lambda num=-1:shift(num))
button1.grid(row=1, column=1)
button2 = tk.Button(root, text="RIGHT>", width=6, anchor='center', command=lambda num=+1:shift(num))
button2.grid(row=1, column=3)

root.mainloop()

【讨论】:

  • 但是关于Label的问题还有关于Label的问题。 :D 我相信你也可以添加 Label 部分。
  • 如果是name标签,也只创建一个name_label,同时在回调函数shift更新name_label的选项text和labels[index]。
  • 我不想要答案,我已经添加了我的答案并且我知道如何添加标签,但我要求您在答案中也添加标签部分,因为有问题我实际上已经要求标签和链接。
  • Jason:仅供参考,grid() 方法总是返回None,所以这是分配给button1button2 的值。见Tkinter: AttributeError: NoneType object has no attribute <attribute name>
  • 如上更新。
【解决方案4】:

你可以试试这个:

from tkinter import Tk,Label,Button
from PIL import ImageTk,Image
import io
import requests
import urllib 

root=Tk()

count=0 # To know the current image and label
urls=[url,url1,url2,url3]
labels=["label 1","label 2","label 3","label 4"]

images=[]
for ur in urls:
    raw_data = urllib.request.urlopen(ur).read()
    im = Image.open(io.BytesIO(raw_data))
    image = ImageTk.PhotoImage(im)
    images.append(image)

def change(direction): # Function to change image
    global count
    if direction=="left":
        if count<=0:
            count=len(urls)-1
        else:
            count-=1
    else:
        if count>=len(urls)-1:
            count=0
        else:
            count+=1
    name.config(text=labels[count])
    image_label.config(image=images[count])

Label(root).grid(row=1,column=1)
image_label=Label(root,image=images[count])
image_label.grid(row=1,column=2)

left_button=Button(root,text="Left",command=lambda : change("left"))
left_button.grid(row=2,column=1)

name=Label(root,text=labels[count])
name.grid(row=2,column=2)

right_button=Button(root,text="Right",command=lambda : change("right"))
right_button.grid(row=2,column=3)

root.mainloop()

【讨论】:

  • @Art 如果我愿意,我可以不提供任何代码,但我提供的代码只是为了展示一个简单的示例,例如...我应该从问题中删除代码吗?
  • 很抱歉没有收到您的最后一条评论。你至少应该解释一下你改变了什么你可以试试这个没有任何解释。
  • 我的意思是我必须从问题中删除代码吗?如果我愿意,那么我不必提供任何有问题的代码,我可以正确回答,没关系!我没有解释它,因为一件事代码是不言自明的,第二个代码我已经解释了我想要做什么!
  • 也许,我不知道。显示 IndexError 是使这篇文章模棱两可的原因。此外,一旦您知道它是什么,所有代码都是不言自明的。初学者可能会觉得很难理解。
  • 你在回答你自己的问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 2018-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多