Advanced operation of tkinter module (1) - transparent button, transparent text box, custom button and custom text box

【Written in front】

—— As we all know, the Button class that comes with the tkinter module cannot make it transparent (at least I can't)

[tip: Transparency means to let the background color or picture show through the button]

—— After searching all the parameters and operations of the Button class, this problem cannot be solved!

-- but! Is there really no way to make a transparent button?

—— If you think that you can’t do it with only the tkinter module, please see the picture below!

Shock! The buttons inside are actually transparent! ! !

This is a small game I made, completely made with tkinter module, no other modules are used! ! !

The link is placed here: Tkinter module GUI graphical programming practice (8) - Chinese chess (including super detailed explanation and complete source code, complete program free download link) - Xiaokang 2022 Blog - CSDN Blog

——It turns out that it is possible to make transparent buttons with the tkinter module!

- And transparent text boxes! (the principle is the same)

Look! It's a transparent text box! ! !

This is another unfinished work I made, there is no link yet

——I don’t know if you have already thought of what method the blogger used to do it?

[tip: Look at the title of the article and you will know the method]


[The feature film begins]

【Principle Explanation】

Only using the built-in Button class in the tkinter module really can’t change the fact that it is opaque, and it is a packaged class. Even if you inherit it and recreate a class of your own, it is not easy to change this fact (because The principle is different), for the button (Button class), its outer frame and the inner part are a whole, which cannot be separated, let alone the connection between the inner part and the external picture. unless……

——Some people think, isn’t it just a transparent button? Who wouldn't do this, I put a picture on the background, then crop the picture to the correct position, and finally insert the cropped picture on the Button class, isn't it "transparent"?

—— Blogger: No way, no way, no one would really do this, right? (in shock...)

—— Blogger: Then I want 100 million buttons like this now? Are you going to crop 100 million times? ? ?

In fact, the above is also a method to make the button transparent, but this kind of transparency is "false transparency", not real transparency.

——Some people think, I don't care if it is really transparent! Can it be used?

—— Blogger: Let’s not talk about whether you are wasting memory, can the following operation “false transparency” be realized?

True Transparent Button

Seeing this, those who have known the tkinter module should already know the principle.

This transparency is real, but the button is fake!

The button is "drawn" on the Canvas control by ourselves, and then use the bind function to associate some events with it, so we get a "false button" similar to the button.

Compared with the "false transparent" button, its advantage is that we can design the style of the button ourselves, but the "false transparent" button cannot do it, because it is actually inherited from the Button class and cannot be re-modified. , the disadvantage, it will be very obvious later, that is, the setting of the button style is very annoying, because the processing of the coordinate position is very troublesome (T_T)

Not much to say, let's post the code below!

[code demo]

[Target Requirement] Make a rectangular "true transparent" button and add a little style appropriately

【Function Realization】Click to print "Hello Python!"

Here I first give the background image (as follows)

Background image (from the Internet)

 Come! On the code! ! !

from tkinter import *# 引入模块

root = Tk()# 创建Tk控件
root.geometry('960x480+200+100')# 设置窗口大小及位置
root.title('透明按钮')# 设置窗口标题

canvas = Canvas(root,highlightthickness=0)# 创建Canvas控件,并设置边框厚度为0
canvas.place(width=960,height=480)# 设置Canvas控件大小及位置
bg = PhotoImage(file='background.png')# 【这里记得要改成对应的路径】

canvas.create_image(480,240,image=bg)# 添加背景图片
r1 = canvas.create_rectangle(380,350,580,400,width=2,outline='black')# 按钮外框
r2 = canvas.create_rectangle(380+3,350+3,580-3,400-3,width=2,outline='black')# 按钮内框
t = canvas.create_text(480,375,text='点 我',font=('楷体',20,'bold'),fill='black')# 按钮显示文本

canvas.bind('<Button-1>',lambda event:bind_1(event))# 关联鼠标点击事件
canvas.bind('<Motion>',lambda event:bind_2(event))# 关联鼠标经过事件

def bind_1(event):# 点击响应函数
    if 380<=event.x<=580 and 350<=event.y<=400:# 响应的位置
        print('Hello Python!')# 打印

def bind_2(event):# 鼠标经过响应函数
    if 380<=event.x<=580 and 350<=event.y<=400:# 响应的位置
        canvas.itemconfigure(r1,outline='white')# 重设外框颜色
        canvas.itemconfigure(r2,outline='white')# 重设内框颜色
        canvas.itemconfigure(t,fill='white')# 重设显示文本颜色
    else:
        canvas.itemconfigure(r1,outline='black')# 恢复外框默认颜色
        canvas.itemconfigure(r2,outline='black')# 恢复内框默认颜色
        canvas.itemconfigure(t,fill='black')# 恢复显示文本默认颜色

root.mainloop()# 窗口进入消息事件循环

The effect is as follows

Transparent button effect display

There are more styles that we can develop by ourselves! (Perfect interpretation of what is called customization !)

For example, the following style (although it is not transparent, its shape can never be done with the Button class!)

[tip: The style of the mouse changes when passing the button!

Custom button effect display

The code is as follows (in fact, compared to the above code, only a little changed) 

from tkinter import *# 引入模块

root = Tk()# 创建Tk控件
root.geometry('960x480+200+100')# 设置窗口大小及位置
root.title('自定义按钮')# 设置窗口标题

canvas = Canvas(root,highlightthickness=0)# 创建Canvas控件,并设置边框厚度为0
canvas.place(width=960,height=480)# 设置Canvas控件大小及位置
bg = PhotoImage(file='background.png')# 【这里记得要改成对应的路径】

canvas.create_image(480,240,image=bg)# 添加背景图片
r = canvas.create_rectangle(380,350-1,580,400+1,width=0,fill='yellow')# 按钮外框
c1 = canvas.create_oval(355,350,405,400,width=0,fill='yellow')# 按钮左圆
c2 = canvas.create_oval(555,350,605,400,width=0,fill='yellow')# 按钮右圆
t = canvas.create_text(480,375,text='点 我',font=('楷体',20,'bold'),fill='black')# 按钮显示文本

canvas.bind('<Button-1>',lambda event:bind_1(event))# 关联鼠标点击事件
canvas.bind('<Motion>',lambda event:bind_2(event))# 关联鼠标经过事件

def bind_1(event):# 点击响应函数
    if 380<=event.x<=580 and 350<=event.y<=400:# 响应的位置
        print('Hello Python!')# 打印

def bind_2(event):# 鼠标经过响应函数
    if 380<=event.x<=580 and 350<=event.y<=400:# 响应的位置
        canvas.itemconfigure(r,fill='orange')# 重设外框颜色
        canvas.itemconfigure(c1,fill='orange')# 重设左圆颜色
        canvas.itemconfigure(c2,fill='orange')# 重设右圆颜色
        canvas.itemconfigure(t,fill='white')# 重设显示文本颜色
        canvas.configure(cursor='hand2')# 重设鼠标样式
    else:
        canvas.itemconfigure(r,fill='yellow')# 恢复外框默认颜色
        canvas.itemconfigure(c1,fill='yellow')# 恢复左圆默认颜色
        canvas.itemconfigure(c2,fill='yellow')# 恢复右圆默认颜色
        canvas.itemconfigure(t,fill='black')# 恢复显示文本默认颜色
        canvas.configure(cursor='arrow')# 恢复鼠标样式

root.mainloop()# 窗口进入消息事件循环

So, after seeing this, everyone should know how the transparent text box is made, right? Simply put, it was "painted"!

Custom transparent text box effect display

Warm reminder, the Entry_Canvas class in the code below is included in the [Gift Package] below!

from tkinter import *

class Entry_Canvas:
    ## ------- 画布文本框类 ------- ##
    def __init__(self,canvas:Canvas,x:int,y:int,r_width:int,r_height:int,text1:str,text2:str,pw_mode:bool=False,d_outline:str='gray',d_fill:str='gray',fontsize:int=15):
        self.canvas = canvas#父控件
        self.focus = False#是否获取到当前焦点
        self.mode = pw_mode#密码模式
 
        self.value = ''#真实值
        self.info = ''#表面值
 
        self.x1 = x-r_width#左上角x坐标
        self.y1 = y-r_height#左上角y坐标
        self.x2 = x+r_width#右下角x坐标
        self.y2 = y+r_height#右下角y坐标
        self.info1 = text1#未获取焦点时文本显示
        self.info2 = text2#半获取焦点时文本显示
        self.d_outline = d_outline#默认外框颜色
        self.d_fill = d_fill#默认文字颜色
 
        self.rec = self.canvas.create_rectangle(x-r_width,y-r_height,x+r_width,y+r_height,width=2,outline=d_outline)
        self.tex = self.canvas.create_text(x,y,text=self.info1,font=('楷体',fontsize),fill=d_fill)
 
    def focus_on(self,color:str):
        ## ------ 焦点已获取状态 ------ ##
        self.focus = True
        self.canvas.itemconfig(self.rec,outline=color)
        self.canvas.itemconfig(self.tex,text=self.info+'|')
 
    def focus_off(self):
        ## ------ 焦点未获取状态 ------ ##
        self.focus = False
        self.canvas.itemconfig(self.rec,outline=self.d_outline)
 
        if self.info == '':
            self.canvas.itemconfig(self.tex,text=self.info1)
        else:
            self.canvas.itemconfig(self.tex,text=self.info)
    
    def Focus(self,event:Event,color:str='white'):
        ## ------- 焦点获取状态检测 ------- ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.focus_on(color)
        else:
            self.focus_off()
 
    def move_on(self,color:str):
        ## ------ 焦点半获取状态 ------ ##
        if self.focus == False:
            self.canvas.itemconfig(self.rec,outline=color)
            if self.canvas.itemcget(self.tex,'text') == self.info1:
                self.canvas.itemconfig(self.tex,text=self.info2)
    
    def move_off(self):
        ## ------ 焦点非半获取状态 ------ ##
        if self.focus == False:
            self.canvas.itemconfig(self.rec,outline=self.d_fill)
            if self.canvas.itemcget(self.tex,'text') == self.info2:
                self.canvas.itemconfig(self.tex,text=self.info1)
 
    def Move(self,event:Event,color:str='white'):
        ## ------- 焦点半获取状态检测 ------- ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.move_on(color)
        else:
            self.move_off()
 
    def input(self,char:str,length:int=10):
        ## ------ 文本输入 ------ ##
        if self.focus == True:
            
            value = ord(char)
            if value == 8:
                self.value = self.value[:-1]
            elif value<=47 or 58<=value<=64 or 91<=value<=96 or 123<=value<=256:
                pass
            else:
                if len(self.value) < length and not char.isspace():
                    self.value += char
 
            if self.mode == True:
                self.info = '•'*len(self.value)
            else:
                self.info = self.value
 
            self.canvas.itemconfig(self.tex,text=self.info+'|')

## 窗口初始化部分
root = Tk()
root.title('透明文本框')
root.geometry('960x480+150+100')
root.resizable(0,0)
canvas = Canvas(root,highlightthickness=0)
background = PhotoImage(file='background.png')#【记得改路径哦】
canvas.create_image(480,240,image=background)
canvas.place(width=960,height=480)

## 自定义透明输入框对象实例化
My_Entry = Entry_Canvas(canvas,480,400,100,15,'密码','点击输入密码',True)
#参数解释(按顺序):父画布控件,文本框中心的横坐标,中心的纵坐标,半长(类似于半径),半宽,显示文本,鼠标移动上去时显示的文本,是否密码模式(True或者False)【还有一些参数,自己看看,选择性取用】
root.bind('<Button-1>',lambda event:My_Entry.Focus(event))#关联点击
root.bind('<Motion>',lambda event:My_Entry.Move(event))#关联鼠标移动
root.bind('<Any-Key>',lambda event:My_Entry.input(event.char))#关联键盘输入

## 窗口进入消息事件循环
root.mainloop()

Of course, to solve the demand for a large number of transparent buttons and transparent text boxes, we must not do this. Each button or text box has to set its position, style, etc. (too much repetitive work), so we can Implement it with classes! There is no need for everyone to write the class, I have specially prepared a big gift package for you here! (As follows) But you can also modify the following classes to meet your own design requirements!

On the code!

【Big gift package】

[Canvas button class]

class Button_Canvas:
    ## ------- 画布按钮类 ------- ##
    def __init__(self,canvas:Canvas,x1:int,y1:int,x2:int,y2:int,text:str,fontsize:int=15,d_outline:str='gray',d_fill:str='gray',image:PhotoImage=None):
        self.canvas = canvas#父控件
        self.value = text
        self.tag = text

        self.x1 = x1#左上角x坐标
        self.y1 = y1#左上角y坐标
        self.x2 = x2#右下角x坐标
        self.y2 = y2#右下角y坐标
        self.d_outline = d_outline#默认外框颜色
        self.d_fill = d_fill#默认文字颜色

        self.rec = self.canvas.create_rectangle(x1,y1,x2,y2,width=2,outline=self.d_outline,tag=self.tag)
        self.tex = self.canvas.create_text((x1+x2)//2,(y1+y2)//2,text=self.value,font=('楷体',fontsize),justify='center',fill=self.d_fill,tag=self.tag)

        if image != None:
            self.canvas.create_image((x1+x2)//2,(y1+y2)//2,image=image)

    def focus_on(self,color:str):
        ## ------ 焦点已获取状态 ------ ##
        self.canvas.itemconfig(self.rec,fill=color)

    def focus_off(self):
        ## ------ 焦点未获取状态 ------ ##
        self.canvas.itemconfig(self.rec,fill='')

    def Focus(self,event:Event,color:str):
        ## ------ 焦点获取状态检测 ------ ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.focus_on(color)
        else:
            self.focus_off()

    def move_on(self,color:str):
        ## ------ 焦点半获取状态 ------ ##
        self.canvas.itemconfig(self.rec,outline=color)
        self.canvas.itemconfig(self.tex,fill=color)
    
    def move_off(self):
        ## ------ 焦点非半获取状态 ------ ##
        self.canvas.itemconfig(self.rec,outline=self.d_outline)
        self.canvas.itemconfig(self.tex,fill=self.d_fill)
    
    def Move(self,event:Event,color:str):
        ## ------ 焦点半获取状态检测 ------ ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.move_on(color)
        else:
            self.move_off()

    def execute(self,event:Event,function=None):
        ## ------- 执行关联函数 ------- ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.focus_off()
            self.move_off()
            
            if function != None:
                return function()

    def value_change(self,value:str):
        ## ------ 显示值改变 ------ ##
        self.value = value
        self.canvas.itemconfig(self.tex,text=self.value)

    def destroy(self):
        ## ------ 按钮删除 ------ ##
        self.canvas.delete(self.tag)

[Canvas Text Box Class]

class Entry_Canvas:
    ## ------- 画布文本框类 ------- ##
    def __init__(self,canvas:Canvas,x:int,y:int,r_width:int,r_height:int,text1:str,text2:str,pw_mode:bool=False,d_outline:str='gray',d_fill:str='gray',fontsize:int=15):
        self.canvas = canvas#父控件
        self.focus = False#是否获取到当前焦点
        self.mode = pw_mode#密码模式

        self.value = ''#真实值
        self.info = ''#表面值

        self.x1 = x-r_width#左上角x坐标
        self.y1 = y-r_height#左上角y坐标
        self.x2 = x+r_width#右下角x坐标
        self.y2 = y+r_height#右下角y坐标
        self.info1 = text1#未获取焦点时文本显示
        self.info2 = text2#半获取焦点时文本显示
        self.d_outline = d_outline#默认外框颜色
        self.d_fill = d_fill#默认文字颜色

        self.rec = self.canvas.create_rectangle(x-r_width,y-r_height,x+r_width,y+r_height,width=2,outline=d_outline)
        self.tex = self.canvas.create_text(x,y,text=self.info1,font=('楷体',fontsize),fill=d_fill)

    def focus_on(self,color:str):
        ## ------ 焦点已获取状态 ------ ##
        self.focus = True
        self.canvas.itemconfig(self.rec,outline=color)
        self.canvas.itemconfig(self.tex,text=self.info+'|')

    def focus_off(self):
        ## ------ 焦点未获取状态 ------ ##
        self.focus = False
        self.canvas.itemconfig(self.rec,outline=self.d_outline)

        if self.info == '':
            self.canvas.itemconfig(self.tex,text=self.info1)
        else:
            self.canvas.itemconfig(self.tex,text=self.info)
    
    def Focus(self,event:Event,color:str='white'):
        ## ------- 焦点获取状态检测 ------- ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.focus_on(color)
        else:
            self.focus_off()

    def move_on(self,color:str):
        ## ------ 焦点半获取状态 ------ ##
        if self.focus == False:
            self.canvas.itemconfig(self.rec,outline=color)
            if self.canvas.itemcget(self.tex,'text') == self.info1:
                self.canvas.itemconfig(self.tex,text=self.info2)
    
    def move_off(self):
        ## ------ 焦点非半获取状态 ------ ##
        if self.focus == False:
            self.canvas.itemconfig(self.rec,outline=self.d_fill)
            if self.canvas.itemcget(self.tex,'text') == self.info2:
                self.canvas.itemconfig(self.tex,text=self.info1)

    def Move(self,event:Event,color:str='white'):
        ## ------- 焦点半获取状态检测 ------- ##
        if self.x1<=event.x<=self.x2 and self.y1<=event.y<=self.y2:
            self.move_on(color)
        else:
            self.move_off()

    def input(self,char:str,length:int=10):
        ## ------ 文本输入 ------ ##
        if self.focus == True:
            
            value = ord(char)
            if value == 8:
                self.value = self.value[:-1]
            elif value<=47 or 58<=value<=64 or 91<=value<=96 or 123<=value<=256:
                pass
            else:
                if len(self.value) < length and not char.isspace():
                    self.value += char

            if self.mode == True:
                self.info = '•'*len(self.value)
            else:
                self.info = self.value

            self.canvas.itemconfig(self.tex,text=self.info+'|')

[Take it and use it! Thank you very much! Give a like and favorite and I will be satisfied!

Guess you like

Origin blog.csdn.net/weixin_62651706/article/details/125911027