Tkinter大作业必备,超实用方法总结

获取当前项目路径

from pathlib import Path

FILE = Path(__file__).resolve()
ROOT = FILE.parents[0]
# ROOT = FILE.parents[1]

图片笔记

image图片存储格式

img[h,w,c]

openCV存储图片的通道为BRG,PIL图片存储的通道为RGB。

img = img[:,:,::-1]     rgb-->bgr  或者 bgr-->rgb
img = img[:,::-1,:] 	水平翻转
img = img[::-1,:,:]     上下翻转

目标框的四个点顺时针标记box[x1,y1,x2,y2,x3,y3,x4,y4], 水平翻转后目标框位置变换代码:

w = img.shape[1]
box[:, [0, 2, 4, 6]] = w - box[:, [2, 0, 6, 4]] # 仅针对4个点变换

PIL图片与OpenCV图片格式相互转换

import cv2
import numpy as np
from PIL import Image
cv2.imread(file)	# opencv图片读取
Image.open(file)	# PIL图片读取
Image.fromarray(cv2.cvtColor(img_cv,cv2.COLOR_BGR2RGB))
cv2.cvtColor(np.asarray(img_pil),cv2.COLOR_RGB2BGR)
'''
通过cv2加载的图片,默认色道格式为BGR,可通过cv2.cvtColor函数进行转换;
通过PIL加载的图片,默认色道格式为RGB,可通过图像的convert方法进行转换。
'''

opencv图片显示

tkinter图片显示需要导入相关的库,图片大小调整不是很重要,先把原图转成RGB格式,然后再将图像转换成Image对象,再接着转变成Tkinter能显示的PhotoImage。通过这种方法,tkinter也能显示jpg格式的图片。

from tkinter import *
import cv2
from PIL import Image, ImageTk

def readImage(file_name):
    image_origin = cv2.imread(file_name) # 读取图片
    up_width = 100
    up_height = 80
    up_points = (up_width, up_height)
    # 调整图片大小
    resized_up = cv2.resize(image_origin, up_points, interpolation=cv2.INTER_LINEAR) 

    imgCV2 = cv2.cvtColor(resized_up, cv2.COLOR_BGR2RGBA)  # 转换颜色从BGR到RGBA
    current_image = Image.fromarray(imgCV2)  # 将图像转换成Image对象
    # current_image = Image.open("2.jpg")
    logo = ImageTk.PhotoImage(current_image)
    return logo

图片在tkinter界面上显示,核心代码如下

imgLogo = readImage("123.jpg")
imgLabel = Label(frame, image=imgLogo)  # 图片标签显示在面板上
imgLabel.image = imgLogo
imgLabel.pack(side=LEFT)

图片显示效果如下。
在这里插入图片描述
如果要读取文件的路径含有中文文字,可以将openCV库中的imread函数替换成imdecode函数,这样也就不容易报错。

image = cv2.imdecode(np.fromfile(file_name, dtype=np.uint8), -1)

frame组件大小固定

如果我们直接将图片放到面板上,面板的大小会随着图片的大小而变化,展示效果是这样的。
在这里插入图片描述
为了能在一个面板上添加更多的组件,达到自己想要的布局效果,我们可以在面板上再添加两个细长的面板,这两个细长的面板就相当于边框,使原面板大小固定下来,这样我们就可以再在原面板上添加更多的组件,组件随意放置,大小随意更改。示例代码如下:

	frame1 = Frame(root, width=600, height=400, borderwidth=3, relief="sunken", bg="lightgreen")
    frame1.place(x=20, y=30)
    frame1x = Frame(frame1, width=600, height=1, bg="red")        # 面板边框x, 为了固定frame1大小
    frame1x.pack(side=TOP)
    frame1y = Frame(frame1, width=1, height=400, bg="red")        # 面板边框y
    frame1y.pack(side=LEFT)

    imgLogo = readImage1("123.jpg")     # 读取图片
    imgLabel = Label(frame1, image=imgLogo)             # 在面板frame1添加图片标签
    imgLabel.image = imgLogo
    imgLabel.place(x=40, y=100)         # 设置图片存放位置

    button1 = Button(frame1, text='按钮1')    # 按钮组件也放在面板frame1
    button1.place(x=300, y=100)

展示图红色的线就是面板边框,非常细小,为了显示特意改成红色背景方便观看,可以根据需要改成和frame1一样的颜色。
在这里插入图片描述

frame+canvas+scrollbar 让frame滚动起来

要想在面板加上滚动条,达到滚动条滚动浏览面板内容的效果,我们首先创建一个面板放到窗口root上面,然后在该面板上添加画布和滚动条,画布里再加上一个面板,并作为画布的窗口。画布中的面板绑定响应的事件。接着再在画布中的面板里以流布局的方式再加上自己设计的大小的面板,面板高度比较长,可以通过滚动条滚动浏览。以流布局的方式可以加入多个面板,根据自己的情况设置页面。运行代码如下:

def readImage1(file_name):
    image_origin = cv2.imread(file_name)
    up_width = 200
    up_height = 160
    up_points = (up_width, up_height)
    resized_up = cv2.resize(image_origin, up_points, interpolation=cv2.INTER_LINEAR)

    imgCV2 = cv2.cvtColor(resized_up, cv2.COLOR_BGR2RGBA)  # 转换颜色从BGR到RGBA
    current_image = Image.fromarray(imgCV2)  # 将图像转换成Image对象
    # current_image = Image.open("2.jpg")
    logo = ImageTk.PhotoImage(current_image)
    return logo

# 中间适配器
def HandlerAdaptor(fun, **kwds):
    return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)

# 幕布响应事件
def myfunction(event, canvas):
    canvas.configure(scrollregion=canvas.bbox("all"),width=600,height=400)  # 宽高修改滚动屏幕的大小

def RootShow(root):

    myframe = Frame(root, relief=GROOVE, width=600, height=400, bd=1)
    myframe.place(x=0, y=0)

    canvas = Canvas(myframe)
    frame_canvas = Frame(canvas)
    frame_scrollbar = Scrollbar(myframe, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=frame_scrollbar.set)

    frame_scrollbar.pack(side="right", fill="y")
    canvas.pack(side="left")
    canvas.create_window((0, 0), window=frame_canvas, anchor='nw')
    frame_canvas.bind("<Configure>", HandlerAdaptor(myfunction, canvas=canvas))

    # 流布局放置面板到frame_canvas面板上
    frame1 = Frame(frame_canvas, width=600, height=900, borderwidth=3, relief="sunken", bg="lightgreen")
    frame1.grid(row=0, column=0)
    frame1x = Frame(frame1, width=600, height=1, bg="red")        # 面板边框x, 为了固定frame1大小
    frame1x.pack(side=TOP)
    frame1y = Frame(frame1, width=1, height=900, bg="red")        # 面板边框y
    frame1y.pack(side=LEFT)

    imgLogo = readImage1("123.jpg")     # 读取图片
    imgLabel = Label(frame1, image=imgLogo)             # 在面板frame1添加图片标签
    imgLabel.image = imgLogo
    imgLabel.place(x=40, y=100)         # 设置图片存放位置

    button1 = Button(frame1, text='按钮1')    # 按钮组件也放在面板frame1
    button1.place(x=300, y=100)

if __name__=='__main__':
    root = Tk()
    root.geometry("1000x600+183+60")
    root.resizable(width=False, height=False)

    RootShow(root)
    root.mainloop()

运行效果如图所示
在这里插入图片描述

事件绑定多参数传递

多个参数传递有两种方法,一种是创建组件加上command = lambda,另一种是bind方法。
以按钮响应事件为例:
创建组件加上command = lambda核心代码如下


def buttonFunction1(frame1, text_number, text_str):
    newEssayWin = Toplevel(frame1)
    newEssayWin.wm_geometry('500x200+280+60')
    newEssayWin.title("按钮1 " + str(text_number) + "   " + text_str)

text_number = 10
text_str = "python tkinter"
button1 = Button(frame1, text='按钮1', command = lambda: buttonFunction1(frame1, text_number, text_str))    # 按钮组件也放在面板frame1
button1.place(x=300, y=100)

按钮添加bind函数核心代码如下:

# 中间适配器
def HandlerAdaptor(fun, **kwds):
    return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)
    
def buttonFunction2(event, frame1, text_number, text_str):
    newEssayWin = Toplevel(frame1)
    newEssayWin.wm_geometry('500x200+280+60')
    newEssayWin.title("按钮2 " + str(text_number) + "   " + text_str)

text_number2 = 8
text_str2 = "tkinter tkinter"
button2 = Button(frame1, text="按钮2")
button2.place(x=300, y = 150)
button2.bind("<Button-1>", HandlerAdaptor(buttonFunction2, frame1=frame1, text_number=text_number2, text_str=text_str2))

显示效果如图所示:
在这里插入图片描述
在这里插入图片描述

plt绘图显示中文乱码问题

加上这两行代码可以可以让中文文字乱码显示得以解决。

	plt.rcParams["font.sans-serif"] = 'SimHei'  # 解决中文乱码问题
	plt.rcParams['axes.unicode_minus'] = False  # 解决负号无法显示的问题

完整代码

from tkinter import *
import cv2
from PIL import Image,ImageTk

def readImage1(file_name):
    image_origin = cv2.imread(file_name)
    up_width = 200
    up_height = 160
    up_points = (up_width, up_height)
    resized_up = cv2.resize(image_origin, up_points, interpolation=cv2.INTER_LINEAR)

    imgCV2 = cv2.cvtColor(resized_up, cv2.COLOR_BGR2RGBA)  # 转换颜色从BGR到RGBA
    current_image = Image.fromarray(imgCV2)  # 将图像转换成Image对象
    # current_image = Image.open("2.jpg")
    logo = ImageTk.PhotoImage(current_image)
    return logo

# 中间适配器
def HandlerAdaptor(fun, **kwds):
    return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)

# 幕布响应事件
def myfunction(event, canvas):
    canvas.configure(scrollregion=canvas.bbox("all"),width=600,height=400)  # 修改滚动屏幕的大小

def buttonFunction1(frame1, text_number, text_str):
    newEssayWin = Toplevel(frame1)
    newEssayWin.wm_geometry('500x200+280+60')
    newEssayWin.title("按钮1 " + str(text_number) + "   " + text_str)

def buttonFunction2(event, frame1, text_number, text_str):
    newEssayWin = Toplevel(frame1)
    newEssayWin.wm_geometry('500x200+280+60')
    newEssayWin.title("按钮2 " + str(text_number) + "   " + text_str)


def RootShow(root):

    myframe = Frame(root, relief=GROOVE, width=600, height=400, bd=1)
    myframe.place(x=0, y=0)

    canvas = Canvas(myframe)
    frame_canvas = Frame(canvas)
    frame_scrollbar = Scrollbar(myframe, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=frame_scrollbar.set)

    frame_scrollbar.pack(side="right", fill="y")
    canvas.pack(side="left")
    canvas.create_window((0, 0), window=frame_canvas, anchor='nw')
    frame_canvas.bind("<Configure>", HandlerAdaptor(myfunction, canvas=canvas))

    # 流布局放置面板到frame_canvas面板上
    frame1 = Frame(frame_canvas, width=600, height=900, borderwidth=3, relief="sunken", bg="lightgreen")
    frame1.grid(row=0, column=0)
    frame1x = Frame(frame1, width=600, height=1, bg="red")        # 面板边框x, 为了固定frame1大小
    frame1x.pack(side=TOP)
    frame1y = Frame(frame1, width=1, height=900, bg="red")        # 面板边框y
    frame1y.pack(side=LEFT)

    imgLogo = readImage1("123.jpg")     # 读取图片
    imgLabel = Label(frame1, image=imgLogo)             # 在面板frame1添加图片标签
    imgLabel.image = imgLogo
    imgLabel.place(x=40, y=100)         # 设置图片存放位置

    text_number = 10
    text_str = "python tkinter"
    button1 = Button(frame1, text='按钮1', command = lambda: buttonFunction1(frame1, text_number, text_str))    # 按钮组件也放在面板frame1
    button1.place(x=300, y=100)

    text_number2 = 8
    text_str2 = "tkinter tkinter"
    button2 = Button(frame1, text="按钮2")
    button2.place(x=300, y = 150)
    button2.bind("<Button-1>", HandlerAdaptor(buttonFunction2, frame1=frame1, text_number=text_number2, text_str=text_str2))

if __name__=='__main__':
    root = Tk()
    root.geometry("1000x600+183+60")
    root.resizable(width=False, height=False)
    RootShow(root)
    root.mainloop()

以上方法是我用tkinter展示界面遇到的一些问题,解决方法有些是搜索博客找到的,我有些做了一些修改,并对它们进行总结,希望能减少tkinter初学者查找解决方法的时间,对读者有一定的帮助。

参考连接:
https://blog.youkuaiyun.com/C_Creator/article/details/108856973
https://blog.youkuaiyun.com/tinym87/article/details/6957438

PIL图片与OpenCV图片的相互转换.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值