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