黎明丿晓小 发表于 2021-8-31 16:36:23

关于如何使得Tkinter中在画布上的图片随画布的变化而变化

主要问题:
1.在画布上导入的图片无法全覆盖画布
2.图片不随画布的缩放而缩放或者随窗口的缩放而缩放

PS:另外希望有大佬跟我讲解一下具体什么时候才使用全局变量

本人Python新手一枚,在网上查阅相关资料后无果,特发此贴请求各路大佬的指点{:10_298:}
在此鸣谢提供代码的@qq1151985918大佬,基于此代码我稍作改动,代码贴在下方,希望能基于此代码提供相关修改代码

from os import listdir
from tkinter import *
from tkinter import filedialog
from PIL import Image,ImageTk

files = {}
img_open = None
img = None

help_text="""
1.打开文件

2.选择打开文件或文件夹

3.单击显示图片
"""




root = Tk()
root.title("树叶计数")
root.geometry("600x600")
#-------------------命令----------------------#
def open_file():
    file_paths = filedialog.askopenfilenames()
    list1.delete(0,END)
    files.clear()

    file_list = []
    for file_path in file_paths:
      name = file_path.split("/")[-1]
      file_list.append(name)
      files = file_path
      list1.insert(END,name)

def open_dir():
    dir_path = filedialog.askdirectory()
    list1.delete(0,END)
    files.clear()

    file_names = []
    target_file_name = ["jpg","png","gif"]
    for name in listdir(dir_path):
      if name.split(".")[-1].lower() in target_file_name:
            file_names.append(name)
            files = dir_path+"/"+name
            list1.insert(END,name)

def show_view(event):
    global img_open
    global img
    get_file = list1.get(ACTIVE)
    file_path = files
    img_open = Image.open(file_path)
    img_open.thumbnail((400,600),Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img_open)
    back.create_image(200,300,anchor=CENTER,image=img)

#-------------------菜单栏--------------------#
menubar = Menu(root)
file_menu = Menu(menubar,tearoff=0)
file_menu.add_command(label="打开文件",command=open_file)
file_menu.add_command(label="打开文件夹",command=open_dir)
file_menu.add_separator()
file_menu.add_command(label="退出",command=root.quit)

menubar.add_cascade(label="文件",menu=file_menu)

train_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="训练",menu=train_menu)

test_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="测试",menu=test_menu)

detect_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="检测",menu=detect_menu)

root.config(menu=menubar)
#------------------画布-----------------------#
back = Canvas(root,width=400,height=600,bg="white")
back.pack(side=RIGHT,fill=BOTH,expand=True)
back.create_text(200,300,anchor=CENTER,text=help_text)

#------------------滚动条---------------------#
sb = Scrollbar(root)
sb.pack(side=RIGHT,anchor=CENTER,fill=Y)
#-------------------列表框--------------------#
list1 = Listbox(root,yscrollcommand=sb.set)
list1.pack(side=LEFT,fill=Y)
list1.bind("<Button-1>",show_view)
sb.config(command=list1.yview())

root.mainloop()

gdmao002 发表于 2021-8-31 16:49:40

全局变量 你要看你需要这个变量的场景,如果只是函数需要这个变量,其他的地方都没用到,那么他就不用作为全局,全局之所以全局 也是因为其他的函数需要使用到他,那么必然是经常性的引用,所以就需要这个全局了,必然不可能每次局部定义一个在返回在更改把,这样多麻烦。全局就是统筹了大家使用的东西的一致性,节省了变量额外多使用和程序中的一些设定会方便点。

qq1151985918 发表于 2021-8-31 17:20:19

tkinter Treeview 在线观看妹子图组件自适应窗口 多线程 太过暴力请谨慎使用
https://fishc.com.cn/thread-201655-1-1.html
(出处: 鱼C论坛)

我昨晚突发奇想没事干写的
就是我给你发的代码的基础上敲的
仔细看看,应该有你想要的。

另外给你的这个代码,就你帖子中这个,我其实后来有修改
就是删除了 30334246 行,当时只是随手就敲了,直觉会有用
后来发现没用到,就删掉了,你原帖现在看到的就是我删除后的

看得出来,代码有所修改,应该是你自己手动敲了一遍
给楼主一些小小的建议
写代码最好从开始养成比较良好的习惯,这样代码才会美观,有可读性
即使不注释也能看得清楚明白,自己将来即使过了一段时间也能看得懂
包括别人也看得懂
我看到代码中其实并没什么变化,加了几行注释,布局方式有所改变
改了几个变量和常量,这都是好事
我的习惯不一定适合楼主你自己
有自己的方法习惯最好不过

不过我发现代码中少了几乎所有的间隔空格
如果是楼主自己敲了一遍,那真是再好不过
希望楼主能够有所进步
也希望楼主能在写代码的时候多注意这些小细节
养成良好的习惯

如果是特地删除,那么大可不必
我原来发给楼主的是比较规范的普遍的约定俗成的代码
而特地把空格删除并不能给代码带来什么好处
既不会减少内存也不会加快运行速度
反而会显得密集凌乱,使代码的可读性有所降低

最后建议楼主仔细看看我上面的链接,说不定你想要的答案就找到了{:9_227:}

黎明丿晓小 发表于 2021-8-31 17:51:18

gdmao002 发表于 2021-8-31 16:49
全局变量 你要看你需要这个变量的场景,如果只是函数需要这个变量,其他的地方都没用到,那么他就不用作为 ...

{:5_110:}

黎明丿晓小 发表于 2021-8-31 17:53:42

qq1151985918 发表于 2021-8-31 17:20
tkinter Treeview 在线观看妹子图组件自适应窗口 多线程 太过暴力请谨慎使用
https://fishc.com.cn/thre ...

正在研究你的那个代码{:7_146:},十分感谢

黎明丿晓小 发表于 2021-8-31 18:07:26

qq1151985918 发表于 2021-8-31 17:20
tkinter Treeview 在线观看妹子图组件自适应窗口 多线程 太过暴力请谨慎使用
https://fishc.com.cn/thre ...

缩放的部分在定义show_img和refresh那吧。我想详细请教一下这个,还有就是我用的是pack()实现的,我想能不能基于pack()来完成这项工作。


PS:我自己只是修改了一些细节,像是布局什么的,我想基于我的布局来完成这个

qq1151985918 发表于 2021-8-31 20:12:15

黎明丿晓小 发表于 2021-8-31 18:07
缩放的部分在定义show_img和refresh那吧。我想详细请教一下这个,还有就是我用的是pack()实现的,我想能 ...

当然可以,了解一下config这个方法吧。

黎明丿晓小 发表于 2021-8-31 20:49:30

qq1151985918 发表于 2021-8-31 20:12
当然可以,了解一下config这个方法吧。

恕我直言,那个代码我把能想到的地方都改着试了试,还是不行,需要你指点一下{:10_285:}

qq1151985918 发表于 2021-8-31 21:13:41

黎明丿晓小 发表于 2021-8-31 20:49
恕我直言,那个代码我把能想到的地方都改着试了试,还是不行,需要你指点一下

把你改了之后的代码发一下

黎明丿晓小 发表于 2021-8-31 21:35:33

qq1151985918 发表于 2021-8-31 21:13
把你改了之后的代码发一下

我把你的一些尺寸数据套用了,我不会判断组件究竟怎么放置到自己想要的位置{:10_269:} ,这个假期刚起步,很多东西都还是一片空白,先是照着别人的学习




from os import listdir
from tkinter import *
from tkinter import filedialog
from PIL import Image,ImageTk

files = {}
img_open = None
img = None

help_text="""
1.打开文件

2.选择打开文件或文件夹

3.单击显示图片
"""

#-------------------命令----------------------#
def open_file():
    file_paths = filedialog.askopenfilenames()
    list1.delete(0,END)
    files.clear()

    file_list = []
    for file_path in file_paths:
      name = file_path.split("/")[-1]
      file_list.append(name)
      files = file_path
      list1.insert(END,name)

def open_dir():
    dir_path = filedialog.askdirectory()
    list1.delete(0,END)
    files.clear()

    file_names = []
    target_file_name = ["jpg","png","gif"]
    for name in listdir(dir_path):
      if name.split(".")[-1].lower() in target_file_name:
            file_names.append(name)
            files = dir_path+"/"+name
            list1.insert(END,name)

def show_view(event):
    global img_open
    global img
    get_file = list1.get(ACTIVE)
    file_path = files

    canvas_width = back.winfo_width()
    canvas_height = back.winfo_height()
    img_open = Image.open(file_path)
    img_open.thumbnail((canvas_width,canvas_height),Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img_open)
    back.create_image(canvas_width / 2, canvas_height / 2,anchor=CENTER,image=img)

def refresh(event):
    root_width = root.winfo_width()
    root_height = root.winfo_height()

    sb.place(x=205, y=5, width=15, height=root_height - 10)
    back.place(x=225, y=5, width=root_width - 230, height=root_height - 10)


root = Tk()
root.title("树叶计数")
root.geometry("500x400")
root.bind("<Configure>",refresh)
#-------------------菜单栏--------------------#
menubar = Menu(root)
file_menu = Menu(menubar,tearoff=0)
file_menu.add_command(label="打开文件",command=open_file)
file_menu.add_command(label="打开文件夹",command=open_dir)
file_menu.add_separator()
file_menu.add_command(label="退出",command=root.quit)

menubar.add_cascade(label="文件",menu=file_menu)

train_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="训练",menu=train_menu)

test_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="测试",menu=test_menu)

detect_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="检测",menu=detect_menu)

root.config(menu=menubar)
#------------------画布-----------------------#
back = Canvas(root,width=400,height=600,bg="white")

back.place(x=225, y=5, width=270, height=390)

#back.pack(side=RIGHT,fill=BOTH,expand=True)
back.create_text(200,300,anchor=CENTER,text=help_text)

#------------------滚动条---------------------#
sb = Scrollbar(root)

sb.place(x=205, y=5, width=15, height=390)

#sb.pack(side=RIGHT,anchor=CENTER,fill=Y)
#-------------------列表框--------------------#
list1 = Listbox(root,yscrollcommand=sb.set)
list1.pack(side=LEFT,fill=Y)
list1.bind("<Button-1>",show_view)
sb.config(command=list1.yview())

root.mainloop()

qq1151985918 发表于 2021-8-31 22:36:32

黎明丿晓小 发表于 2021-8-31 21:35
我把你的一些尺寸数据套用了,我不会判断组件究竟怎么放置到自己想要的位置 ,这个假期刚起步 ...

from os import listdir
from tkinter import *
from tkinter import filedialog
from PIL import Image,ImageTk

files = {}
img_open = None
img = None

help_text="""
1.打开文件

2.选择打开文件或文件夹

3.单击显示图片
"""


root = Tk()
root.title("树叶计数")
root.geometry("600x600")
# -------------------命令----------------------#


def open_file():
    file_paths = filedialog.askopenfilenames()
    list1.delete(0,END)
    files.clear()

    file_list = []
    for file_path in file_paths:
      name = file_path.split("/")[-1]
      file_list.append(name)
      files = file_path
      list1.insert(END,name)


def open_dir():
    dir_path = filedialog.askdirectory()
    list1.delete(0,END)
    files.clear()

    file_names = []
    target_file_name = ["jpg","png","gif"]
    for name in listdir(dir_path):
      if name.split(".")[-1].lower() in target_file_name:
            file_names.append(name)
            files = dir_path+"/"+name
            list1.insert(END,name)


def show_view(event):
    global img_open
    global img
    try:
      back.delete("all") # 清空原画布所有内容
      get_file = list1.get(ACTIVE)
      file_path = files
    except:
      return
    back_width = back.winfo_width() # 获取当前画布宽度
    back_height = back.winfo_height() # 获取当前画布高度
    img_open = Image.open(file_path)
    img_open.thumbnail((back_width,back_height),Image.ANTIALIAS) # 以当前画布尺寸适应大小
    img = ImageTk.PhotoImage(img_open)
    back.create_image(back_width/2,back_height/2,anchor=CENTER,image=img) # 重新定义画布中心


def refresh(event):
    root_width = root.winfo_width() # 获取当前窗口尺寸
    root_height = root.winfo_height()
    back.config(width=root_width-200, height=root_height-10) # 重新设置画布尺寸
    show_view(1) # 重新显示当前图片 参数 1 必须但不唯一,可以是任何内容
    # 这里的参数 event 有必要解释一下,event 是事件,
    # 一般来说是tkinter当前控件的某种属性
    # 当使用bind方法绑定一个方法时必须指定的一个参数,但不一定要用到
    # 等你用多了就了解了
   
   
# -------------------菜单栏--------------------#


menubar = Menu(root)
file_menu = Menu(menubar,tearoff=0)
file_menu.add_command(label="打开文件",command=open_file)
file_menu.add_command(label="打开文件夹",command=open_dir)
file_menu.add_separator()
file_menu.add_command(label="退出",command=root.quit)

menubar.add_cascade(label="文件",menu=file_menu)

train_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="训练",menu=train_menu)

test_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="测试",menu=test_menu)

detect_menu = Menu(menubar,tearoff=0)
menubar.add_cascade(label="检测",menu=detect_menu)

root.config(menu=menubar)


# ------------------画布-----------------------#


back = Canvas(root,width=400,height=600,bg="white")
back.pack(side=RIGHT,fill=BOTH,expand=True)
back.create_text(200,300,anchor=CENTER,text=help_text)


# ------------------滚动条---------------------#


sb = Scrollbar(root)
sb.pack(side=RIGHT,anchor=CENTER,fill=Y)


# -------------------列表框--------------------#


list1 = Listbox(root,yscrollcommand=sb.set)
list1.pack(side=LEFT,fill=Y)
list1.bind("<Button-1>",show_view)
sb.config(command=list1.yview())


root.bind("<Configure>",refresh) # 绑定refersh函数为窗口属性变化事件
root.mainloop()


看代码不能只知其一不知其二,联系上下来看就容易理解得多
你回复中的代码太乱了我没用
用的是你帖子中的代码
对照一下吧,我给你加了注释

黎明丿晓小 发表于 2021-8-31 23:35:00

qq1151985918 发表于 2021-8-31 22:36
看代码不能只知其一不知其二,联系上下来看就容易理解得多
你回复中的代码太乱了我没用
用的是你 ...

好的,感谢{:10_254:}

黎明丿晓小 发表于 2021-8-31 23:46:51

qq1151985918 发表于 2021-8-31 22:36
看代码不能只知其一不知其二,联系上下来看就容易理解得多
你回复中的代码太乱了我没用
用的是你 ...

学习的路上任重而道远,修改后的代码又有新东西值得我去探讨和学习{:5_109:}

hornwong 发表于 2021-9-1 11:12:57

{:5_95:}

muder 发表于 2021-9-1 14:47:19

不大不小甲鱼 发表于 2021-9-1 15:29:42

{:10_269:}

黎明丿晓小 发表于 2021-9-1 18:40:11

qq1151985918 发表于 2021-8-31 22:36
看代码不能只知其一不知其二,联系上下来看就容易理解得多
你回复中的代码太乱了我没用
用的是你 ...

你好呀~是这样的,我这样理解你看对不对

def show_view(event):
    global img_open
    global img
    try:
      back.delete("all")
      get_file = list1.get(ACTIVE)
      file_path = files
    except:
      return
    back_width = back.winfo_width()
    back_height = back.winfo_height()
    img_open = Image.open(file_path)
    img_open.thumbnail((back_width, back_height), Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img_open)
    back.create_image(back_width / 2, back_height / 2, anchor=CENTER, image=img)

def refresh(event):
    root_width = root.winfo_width()
    root_height = root.winfo_height()
    back.config(width=root_width - 200, height=root_height - 10)
    show_view(1)

当窗口尺寸发生变化时调用refresh函数,然后refresh下的show_view(1)中的值为1表示调用show_view()函数下的try模块;否则窗口不变化就调用except中的return,返回一个空值,这个直接return直接接空我不是太理解。我之前尝试着把异常处理try,except去掉,直接输入代码,如下:

def show_view(event):
    global img_open
    global img
    back.delete(ALL)
    get_file = list1.get(ACTIVE)
    file_path = files

    back_width = back.winfo_width()
    back_height = back.winfo_height()
    img_open = Image.open(file_path)
    img_open.thumbnail((back_width,back_height),Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img_open)
    back.create_image(back_width / 2, back_height / 2,anchor=CENTER,image=img)

结果返回错误,如图,希望能够得到指点

黎明丿晓小 发表于 2021-9-1 18:56:38

我好像懂了,刚才又重新试了遍,如果没有try,except异常处理,可以正常运行,但就是一直报错,你这么做是为了把报错消除掉吧,只要一报错就运行except返回一个空值,他就不会报错了{:10_298:}

某一天 发表于 2021-9-2 02:28:37

楼主千金散尽还复来

trolwy 发表于 2021-9-2 06:54:45

挣鱼币做作业
页: [1] 2
查看完整版本: 关于如何使得Tkinter中在画布上的图片随画布的变化而变化