tkinter库使用技巧之监听窗口变化自动刷新组件位置大小


前言

使用tkinter编写好的界面,有时需要改变界面的大小,而拖动改变窗口大小时,代码写好的组件布局不能够自动刷新改变位置和大小,特别是复杂界面,或者使用place布局时,在很长一段时间内我都放弃了对tkinter库写的界面允许改变界面大小,最近偶然发现place的新用法,实现了界面的自动刷新布局,这里记录一下。

一、place布局

tkinter的布局方式有三种,pack布局、grid布局以及place布局,我比较喜欢的、也使用的最多的是place布局,因为它可以准确的将控件放置在任何想要的位置,参数是x,y,width,height,分别表示控件的左上角点在父容器中的x、y坐标,和控件的宽、高。
一直以来我都只任务place只有这4个参数,因为定义死了它的位置和大小,当改变窗口大小时,想改变控件位置大小则需要重新计算相应的位置与宽高,当控件数量很多时是很麻烦是事情,代码量也增加很多,故很多次想实现自动刷新控件位置大小的功能都放弃了,最近仔细了解了一下place布局,发现它还有4个参数,配合之前4个参数使用,是真香啊。

二、直接上代码

养成好习惯,界面代码和逻辑代码分离,创建一个python文件tkUI.py,内容如下:

import tkinter as tk
from tkinter import ttk
# from PIL import Image,ImageTk
import ctypes                   #可让python与C语言混合使用
#告诉操作系统使用程序自身的dpi适配
ctypes.windll.shcore.SetProcessDpiAwareness(1)

class mytkinter(tk.Tk):
    width=800
    height=600
    ROW=10
    COL=10
    first_load=True
    # def __init__(self):
    #     super().__init__()


    def setupUi(self):
        self.config(bg='#666888', bd=0)
        self.title("YOLOv5 检测")
        screen_width = self.winfo_screenwidth()  # 电脑屏幕宽度
        screen_height = self.winfo_screenheight()
        print(screen_width, screen_height)
        center_geometry = [int(screen_width / 2 - self.width / 2), int(screen_height / 2 - self.height / 2)]
        geometry_str = "{}x{}+{}+{}".format(self.width, self.height, center_geometry[0], center_geometry[1])
        print(geometry_str)
        self.geometry(geometry_str)

        # 画布
        self.cv = tk.Canvas(self, bg='snow')

        # self.style_1=ttk.Style()
        # self.style_1.configure("TLabel",foreground='black',background='ivory')
        self.tab_main = ttk.Notebook(self.cv)
        # self.tab_main.pack(expand=1,fill='both')#这段代码很重要


        self.tab1 = tk.Frame(self.tab_main, bg='snow')
        self.tab1.place(relx=0.05, rely=0.1, relwidth=0.9, relheight=0.9)
        self.tab_main.add(self.tab1, text='图像检测')

        self.tab2 = tk.Frame(self.tab_main, bg='ivory')
        self.tab2.place(relx=0.05, rely=0.1, relwidth=0.9, relheight=0.9)
        self.tab_main.add(self.tab2, text='视频检测')

        self.tab3 = tk.Frame(self.tab_main, bg='#eeebbb')
        self.tab3.place(relx=0.05, rely=0.1, relwidth=0.9, relheight=0.9)
        self.tab_main.add(self.tab3, text='摄像头检测')

        self.tab4 = tk.Frame(self.tab_main, bg='#666888')
        self.tab4.place(relx=0.05, rely=0.1, relwidth=0.9, relheight=0.9)
        self.tab_main.add(self.tab4, text='设置')

        #tab1
        self.VLabel1 = self.myViewLabel(self.tab1, 0.005, 0.1, 0.49, 0.9)
        self.VLabel2 = self.myViewLabel(self.tab1, 0.505, 0.1, 0.49, 0.9)

        # tab2
        self.VLabel3 = self.myViewLabel(self.tab2, 0.005, 0.1, 0.49, 0.9)
        self.VLabel4 = self.myViewLabel(self.tab2, 0.505, 0.1, 0.49, 0.9)

        # tab3
        self.VLabel5 = self.myViewLabel(self.tab3, 0.005, 0.1, 0.49, 0.9)
        self.VLabel6 = self.myViewLabel(self.tab3, 0.505, 0.1, 0.49, 0.9)

        # tab4
        self.btn1=tk.Button(self.tab4,text='选择权重',bd=0,bg='black',fg='white')
        self.btn1.place(relx=0.01,rely=0.05,width=100,height=30)
        self.label1=tk.Label(self.tab4,text="yolov5s.pt")
        self.label1.place(relx=0.01,x=105,rely=0.05,relwidth=0.98,width=-105,height=30)

        self.label2 = tk.Label(self.tab4, text="图片大小",bd=0,bg='black',fg='white')
        self.label2.place(relx=0.01,rely=0.05,y=50,width=100,height=30)
        self.var2=tk.StringVar()
        self.entry2=tk.Entry(self.tab4,textvariable=self.var2)
        self.entry2.place(relx=0.01,x=105,rely=0.05,y=50,relwidth=0.48,width=-105,height=30)
        self.var2.set("640")

        self.label3 = tk.Label(self.tab4, text="置信度阈值", bd=0, bg='black', fg='white')
        self.label3.place(relx=0.51, rely=0.05, y=50, width=100, height=30)
        self.var3 = tk.StringVar()
        self.entry3 = tk.Entry(self.tab4, textvariable=self.var3)
        self.entry3.place(relx=0.51, x=105, rely=0.05, y=50, relwidth=0.48, width=-105, height=30)
        self.var3.set("0.25")

        self.label4 = tk.Label(self.tab4, text="iou阈值", bd=0, bg='black', fg='white')
        self.label4.place(relx=0.01, rely=0.05, y=100, width=100, height=30)
        self.var4 = tk.StringVar()
        self.entry4 = tk.Entry(self.tab4, textvariable=self.var4)
        self.entry4.place(relx=0.01, x=105, rely=0.05, y=100, relwidth=0.48, width=-105, height=30)
        self.var4.set("0.45")

        self.label5 = tk.Label(self.tab4, text="目标最大数", bd=0, bg='black', fg='white')
        self.label5.place(relx=0.51, rely=0.05, y=100, width=100, height=30)
        self.var5 = tk.StringVar()
        self.entry5 = tk.Entry(self.tab4, textvariable=self.var5)
        self.entry5.place(relx=0.51, x=105, rely=0.05, y=100, relwidth=0.48, width=-105, height=30)
        self.var5.set("100")

        self.label6 = tk.Label(self.tab4, text="检测设备选择", bd=0, bg='black', fg='white')
        self.label6.place(relx=0.01, rely=0.05, y=150, width=100, height=30)
        self.var6 = tk.StringVar()
        self.entry6 = tk.Entry(self.tab4, textvariable=self.var6)
        self.entry6.place(relx=0.01, x=105, rely=0.05, y=150, relwidth=0.48, width=-105, height=30)
        self.var6.set("0")
        self.btn2=tk.Button(self.tab4,text="保存设置", bd=0, bg='black', fg='white')
        self.btn2.place(relx=0.51, rely=0.05, y=150, relwidth=0.48, height=30)

    def myViewLabel(self,master,relx,rely,relwidth,relheight):#自定义标签,用于显示图片,可实现图片的放大缩小
        label=tk.Label(master,bg='#666888',bd=0)
        label.place(relx=relx,rely=rely,relwidth=relwidth,relheight=relheight)
        # self.label.bind("<Double-Button-1>",lambda a:mytkinter().show_toplevel(self))
        return label



# top=mytkinter()
# # top.config(bg='red')
# top.mainloop()

然后是逻辑代码,命名为main.py吧。重点是窗口绑定事件self.bind(‘’, self.window_resize)和刷新布局函数myplace(),先定义一个Canvas作为GUI的背景,然后所有的组件均在Canvas上布置,使用place布局中的relx,rely,relwidth,relheight四个参数,它们表示相对于父容器的位置和宽高,值在0.0~1.0之间,每次窗口变化时,触发window_resize()函数,修改变量width和height的值,再运行myplace()函数,重新布局Canvas的位置和大小,之后以Canvas为父容器的组件,在Canvas刷新之后自动根据place布局描述的位置大小自动刷新。实现逻辑代码如下:

from TkUI import mytkinter


class MyTk(mytkinter):
    
    def __init__(self):
        super().__init__()
        self.setupUi()
        self.tab_main.place(relx=0, rely=0, relwidth=1, relheight=1)

        self.myplace()
        # 监听窗口大小改变
        self.bind('<Configure>', self.window_resize)

    def myplace(self):#place布局,self.cv作为父控件,其尺寸改变,其子控件大小相应刷新
        self.cv.place(x=0,y=0,width=self.width,height=self.height)

    def window_resize(self,event=None):
        if event:
            # print(event)
            if self.winfo_width()==self.width and self.winfo_height()==self.height:
                return
            if self.first_load:
                self.first_load=False
                return
            self.width=self.winfo_width()
            self.height=self.winfo_height()
            self.myplace()
            # print(self.place_slaves(),self.place_slaves()[0].place_info())




if __name__=='__main__':
    top=MyTk()
    top.mainloop()

附一些截图。
正常大小:
在这里插入图片描述
缩小:
在这里插入图片描述
在这里插入图片描述

全屏:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜小昊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值