【问题标题】:Tkinter canvas doesn't show entire photo imageTkinter 画布不显示整个照片图像
【发布时间】:2015-11-29 08:24:31
【问题描述】:

我创建了一个简短的脚本来在 Tkinter 画布元素中显示照片。我将画布元素的大小调整为与照片相同的大小,但是当我启动窗口时,无论我扩大多少窗口,我通常只会看到图像的一小部分。

此外,当我打印出用于设置画布大小的图像大小时,该大小显示为 (922, 614),而当我在画布上记录鼠标点击时,右下角位于 (500, 300) 之类的位置。我的代码如下。我应该更改哪些内容才能使画布与图像大小相同并完全显示图像?

class AppWindow(Frame):

def __init__(self, parent, list_of_files, write_file):
    Frame.__init__(self, parent)           
    self.parent = parent
    ...
    self.image = None
    self.canvas = None
    self.index = -1
    self.loadImage()
    self.initUI()
    self.resetCanvas()

def initUI(self):
    self.style = Style()
    self.style.theme_use("default")
    self.pack(fill=BOTH, expand=1)
    ...
    self.canvas = Tkinter.Canvas(self, width = self.image.width(), height = self.image.height())   

def loadImage(self):
    self.index += 1
    img = cv2.imread(self.list_of_files[self.index])                       
    img = cv2.resize(img, (0,0), fx = IMAGE_RESIZE_FACTOR, fy = IMAGE_RESIZE_FACTOR)
    b, g, r = cv2.split(img)
    img = cv2.merge((r,g,b))
    im = Image.fromarray(img)
    self.image = ImageTk.PhotoImage(image=im)       

def resetCanvas(self):        
    self.canvas.create_image(0, 0, image=self.image)
    self.canvas.place(x = 0, y = 0, height = self.image.height(), width = self.image.width())

这是一张截图,展示了一张照片以及它在 Tkinter 画布中的呈现方式:

这是我迄今为止尝试过的:

  • 不调整图像大小或更改调整大小 - 这没有任何作用
  • 使画布成为图像大小的两倍而不是等于图像,喜欢self.canvas = Tkinter.Canvas(self, width = self.image.width()*2, height = self.image.height()*2) 这确实使画布更大(我可以说是因为我在画布上有一些绘图功能),但图像保持不变相同的小尺寸,不显示整个图像
  • 当我用cv2.imshow() 显示 cv2 格式图像时,我看到了完整的图像,所以不是cv2 正在切断图像的一部分。

我意识到我上面的内容并不是一个完整的工作示例。我已经缩减了脚本,现在运行它我仍然看到同样的问题:

import Tkinter
import Image, ImageTk
from Tkinter import Tk, BOTH
from ttk import Frame, Button, Style
import cv2
import os
import time
import itertools


IMAGE_RESIZE_FACTOR = .3

class AppWindow(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)           
        self.parent = parent
        self.loadImage()
        self.initUI()

    def loadImage(self):
        img = cv2.imread("w_4131.jpg")            
        img = cv2.resize(img, (0,0), fx = IMAGE_RESIZE_FACTOR, fy = IMAGE_RESIZE_FACTOR)
        b, g, r = cv2.split(img)
        img = cv2.merge((r,g,b))
        im = Image.fromarray(img)
        self.image = ImageTk.PhotoImage(image=im)       

    def initUI(self):
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)

        print "width and height of image should be ", self.image.width(), self.image.height()
        self.canvas = Tkinter.Canvas(self, width = self.image.width(), height = self.image.height())
        self.canvas.pack()
        self.canvas.create_image(0, 0, image=self.image)


def main():

    root = Tk()
    root.geometry("250x150+300+300")
    app = AppWindow(root)
    root.mainloop()  


if __name__ == '__main__':

    main()  

【问题讨论】:

  • 如果你 pack 画布而不是放置它会发生什么?
  • @Kevin 我只是尝试了self.canvas.pack()self.canvas.pack(fill=Tkinter.BOTH) 而不是.place() 调用。结果是一样的。您建议如何/在哪里致电pack()
  • self.canvas.configure(height = self.image.height(), width = self.image.width()) in resetCanvas?
  • @EricLevieil 也许我的排序错误,但在place 之前或之后或pack 之前或之后,它本身没有明显的影响

标签: python tkinter


【解决方案1】:

当您将图像放置在画布上的 0,0 处时,它指定图像中心的位置,而不是左上角。图片都在那里,只是你看到的只是右下角。

在创建图片时添加anchor="nw"的坐标代表图片的左上角:

self.canvas.create_image(0, 0, image=self.image, anchor="nw")

至于画布与图像的大小不同,我没有看到。图片似乎非常适合画布。

【讨论】:

  • 但是...对于那些可能从 Windows(可能还有其他人)来到这里的人来说,0, 0 的来源最终会略微剪辑。如果您注意到这种顶部和左侧的剪裁,请尝试2, 21,1 还不够)。很确定这也不是一个新问题。
  • 我在 Ubuntu 18.04 上试了一下... 可以在 1,12,2 上使用,但如果图像偏移更多,则需要将画布放大 >= 1,11,1.
  • @MartyMacGyver:剪辑是由于画布边框。您看到的剪辑量与borderwidth 选项直接相关。
  • @BryanOakley 我感谢您的回复 - 我评论更多是仅供参考,但默认情况下 borderwidth0,我不会在任何地方覆盖它。如上所述,在这方面,我相同的确切测试代码在 Linux 和 Windows 上的工作方式不同。 TBH 我认为这是tkinter 中的一个潜在缺陷,虽然我看到你是这个工具的人。这里的评论线程不适合对此进行扩展讨论,但我很乐意离线讨论它(如果这确实是一个错误,我会提交一个错误,但无论哪种方式都很好理解这个更好)。
  • @MartyMacGyver:您是否验证了默认边框宽度为零?在不同的平台上可能会有所不同。
最近更新 更多