【tkinter】的使用详解,做一个简单实用的万能可视化界面!

  • 写在前头,感谢洪卫大佬的文章,但我没找到原文链接,只找到了转载文章,只能从代码中知道真正的作者是谁(链接放在文末)。本文为我对照大佬博客的学习笔记,所以前面会有很多相似之处。后面我会再学习过程中,将我遇到的问题,学习到的新的使用函数的方法都更新到这一篇博客当中,作一个tkinter的万金油博客,遇到问题翻阅这一篇博客就几乎能解决所有问题。

一、tkinter类介绍

  • Tkinter支持16个核心的窗口部件,这个16个核心窗口部件类简要描述如下:
tkinter类简要说明
Button一个简单的按钮,用来执行一个命令或别的操作。
Canvas组织图形。这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件。
Checkbutton代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换。
Entry文本输入域。
Frame一个容器窗口部件。帧可以有边框和背景,当创建一个应用程序或dialog(对话)版面时,帧被用来组织其它的窗口部件。
Label显示一个文本或图象。
Listbox显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。
Menu菜单条。用来实现下拉和弹出式菜单。
Menubutton菜单按钮。用来实现下拉式菜单。
Message显示一文本。类似label窗口部件,但是能够自动地调整文本到给定的宽度或比率。
Radiobutton代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。
Scale允许你通过滑块来设置一数字值。
Scrollbar为配合使用canvas, entry, listbox, and text窗口部件的标准滚动条。
Text格式化文本显示。允许你用不同的样式和属性来显示和编辑文本。同时支持内嵌图象和窗口。
Toplevel一个容器窗口部件,作为一个单独的、最上面的窗口显示。
messageBox消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox)
  • 注意在Tkinter中窗口部件类没有分级;所有的窗口部件类在树中都是兄弟关系。

  • 所有这些窗口部件提供了Misc和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel类也提供窗口管理接口。这意味一个典型的窗口部件类提供了大约150种方法。
    在这里插入图片描述

二、在例子中学会用法!

1、一个简单的开始

  • 注意,此处l.pack()默认是从窗口最上方的中心开始往下放置
import tkinter as tk  # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x
 
# 第4步,在图形界面上设定标签
l = tk.Label(window, text='你好!this is Tkinter', bg='green', font=('Arial', 12), width=30, height=2)
# 说明: bg为背景,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高
 
# 第5步,放置标签
l.pack()    # Label内容content区域放置位置,自动调节尺寸
# 放置lable的方法有:1)l.pack(); 2)l.place();
 
# 第6步,主窗口循环显示
window.mainloop()
# 注意,loop因为是循环的意思,window.mainloop就会让window不断的刷新,如果没有mainloop,就是一个静态的window,传入进去
# 的值就不会有循环,mainloop就相当于一个很大的while循环,有个while,每点击一次就会更新一次,所以我们必须要有循环
# 所有的窗口文件都必须有类似的mainloop函数,mainloop是窗口文件的关键的关键。

在这里插入图片描述

2、学会使用button

  • 注意,此处l.pack()默认是从窗口最上方的中心开始往下放置
import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上设定标签
var = tk.StringVar()  # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
l = tk.Label(window, textvariable=var, bg='green', fg='white', font=('Arial', 12), width=30, height=2)
# 说明: bg为背景,fg为字体颜色,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高
l.pack()

# 定义一个函数功能(内容自己自由编写),供点击Button按键时调用,调用命令参数command=函数名
on_hit = False


def hit_me():
    global on_hit
    if on_hit == False:
        on_hit = True
        var.set('瞅你咋地')
    else:
        on_hit = False
        var.set('')


# 第5步,在窗口界面设置放置Button按键
b = tk.Button(window, text='你再瞅我', font=('Arial', 12), width=10, height=1, command=hit_me)
b.pack()

# 第6步,主窗口循环显示
window.mainloop()

3、Entry窗口部件

1、简单使用

简单说明:

  • Entry是tkinter类中提供的的一个单行文本输入域,用来输入显示一行文本,收集键盘输入(类似 HTML 中的 text)。

什么时候用:

  • 需要用户输入用户信息时,比如我们平时使用软件、登录网页时,用户交互界面让我们登录账户信息等时候可以用到。

示例代码:

  • 注意,此处l.pack()默认是从窗口最上方的中心开始往下放置
import tkinter as tk  # 使用Tkinter前需要先导入

# Entry是tkinter类中提供的的一个单行文本输入域,用来输入显示一行文本,收集键盘输入(类似 HTML 中的 text)。

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上设定输入框控件entry并放置控件
e1 = tk.Entry(window, show='*', font=('Arial', 14))  # 显示成密文形式
e2 = tk.Entry(window, show=None, font=('Arial', 14))  # 显示成明文形式
e1.pack()
e2.pack()

# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

2、动态改变entry内部的值

from tkinter import *


class Main():
    def __init__(self, root):
        self.main = root

        # INTEGER
        self.int_entry = IntVar()  # use IntVar() instead int
        self.int_entry.set(0)  # init value

        # BUTTONS
        self.button0 = Button(self.main, text='Quit', command=self.main.destroy)
        self.button0.pack()
        self.button1 = Button(self.main, text='+', command=self.plus_one)
        self.button1.pack()
        self.button2 = Button(self.main, text='-', command=self.take_one)
        self.button2.pack()

        # ENTRY
        self.entry0 = Entry(self.main, textvariable=self.int_entry,
                            justify=CENTER, width=4)
        self.entry0.pack()
        self.entry0.bind("<Enter>", self.change_value)  # set value and press Enter

    def change_value(self, event):
        self.int_entry.set(self.entry0.get())

    def plus_one(self):
        s = int(self.entry0.get())  # cast to integer because Entry widget is always string object
        self.int_entry.set(s + 1)

    def take_one(self):
        s = int(self.entry0.get())
        self.int_entry.set(s - 1)


if __name__ == "__main__":
    root = Tk()
    Main(root)
    root.mainloop()

在这里插入图片描述

4、Text窗口部件

(1)Text的简单使用

简单说明:

  • Text是tkinter类中提供的的一个多行文本区域,显示多行文本,可用来收集(或显示)用户输入的文字(类似 HTML 中的 textarea),格式化文本显示,允许你用不同的样式和属性来显示和编辑文本,同时支持内嵌图象和窗口。

什么时候用:

  • 在需要显示编辑用户、产品多行信息时,比如显示用户详细描述文字,产品简介等等,支持随时编辑。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上设定输入框控件entry框并放置
e = tk.Entry(window, show=None)  # 显示成明文形式
e.pack()


# 第5步,定义两个触发事件时的函数insert_point和insert_end(注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面)
def insert_point():  # 在鼠标焦点处插入输入内容
    var = e.get()
    t.insert(tk.END, var)


def insert_end():  # 在文本框内容最后接着插入输入内容
    var = e.get()
    t.insert(tk.END, var)


# 第6步,创建并放置两个按钮分别触发两种情况
b1 = tk.Button(window, text='insert point', width=10,
               height=2, command=insert_point)
b1.pack()
b2 = tk.Button(window, text='insert end', width=10,
               height=2, command=insert_end)
b2.pack()

# 第7步,创建并放置一个多行文本框text用以显示,指定height=3为文本框是三个字符高度
t = tk.Text(window, height=3)
t.pack()

# 第8步,主窗口循环显示
window.mainloop()

<\center>

(2)Text框实时输出

  • 首先GUI中不同函数的局部变量的问题。

  • 发现不同button定义的函数得到的变量无法通用。

  • 通过global 函数内的变量可以解决这个问题

def openfiles2():
    global s2fname
    s2fname = filedialog.askopenfilename(title='打开S2文件', filetypes=[('S2out', '*.out'), ('All Files', '*')])
    text.insert(tkinter.END, 'S2打开成功\n'+s2fname+'\n')
def openfilecgns():
    global cgnsfname
    cgnsfname = filedialog.askopenfilename(title='打开CGNS文件',filetypes=[('CGNSdat', '*.dat'), ('All Files', '*')] )
    text.insert(tkinter.END, 'CGNS dat 打开成功\n'+cgnsfname+'\n')
def show():
  • Text文本框的定义和输出

  • 定义:

text=tkinter.Text(root,width=20,height=20)
text.pack(fill=tkinter.X,side=tkinter.BOTTOM  )
  • 用到fill 可以填充某个方向,这次填充X方向,使得界面更好看。 side可以放置在不同的位置。但是这次用起来很多错误。

  • 以后可以尝试不用import tkinter 可以用from tkinter import * 虽然更危险,但是网上大部分的代码都是这样导出的。更容易参考。

text.insert(tkinter.END, 'this Row finished...\n')  # INSERT表示在光标位置插入
text.see(tkinter.END)
text.update()
  • 如果不update就是 等到计算函数计算完之后才可以得到新的insert的数据。

  • 用update可以解决这个问题。

  • 利用see(END) 解决文本框滚动的问题。自动显示最新的一行信息。类似于各种商业软件求解器。

(3)给text加滚动条

"""
文本控件:用于显示多行文本
"""
import tkinter

win = tkinter.Tk()
win.title('带滚动条text控件')
# win.geometry('400x400')

text = tkinter.Text(win, width=50, height=8)
scroll = tkinter.Scrollbar()
# 放到窗口的右侧, 填充Y竖直方向
scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)

# 两个控件关联
scroll.config(command=text.yview)
text.config(yscrollcommand=scroll.set)

text.pack()
str1 = 'ahh ta yu duan jian jie shi ke xi,\n' \
       'mei yi ge meng xiang dou zhi de yong yi\n' \
       'shi de ni shuo de dui ji le\n' \
       'wo jin ran wu fa fan bo \n' \
       'zaijian ba qin aid \n' \
       'na zhi shi ge meihao de guo qu\n' \
       'ni shi wode xiao pg \n' \
       'zm ai ni dou bu xian duo\n' \
       ' hong h d xiao lian wen n wode xin wo\n'

text.insert(tkinter.INSERT, str1)

win.mainloop()

在这里插入图片描述

(4)Message组件实现自动换行并呈现两端对齐

import tkinter as tk 

# 【01】Label VS Message
root = tk.Tk()

word='摇摇晃晃进入青春岁月,如此般奢侈的年华,如此般摇曳的时光,\
如此般年轻的我们,有着太多美好的时光,有着太多的无奈。'

l1 = tk.Label(root, text=word)
l1.pack()

m1 = tk.Message(root, text=word)
m1.pack()

root.mainloop()

在这里插入图片描述

  • 当我们需要在一定宽度下显示大段文本的时候,就比较适合用Message。
  • 总结一下Message组件常用的而一些参数以及用法。

在这里插入图片描述

(5)将滚动条放到text里面

  • 直接用带滚动条的文本框ScrolledText就行了
from tkinter.scrolledtext import ScrolledText
self.comment = ScrolledText(self.init_window_name, width=40, height=40, font=('宋体',12))

5、Listbox窗口部件

简单说明:

  • Text是tkinter类中提供的的列表框部件,显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。

什么时候用:

  • 在有一个很多内容选项组成的列表提供用户选择时会用到。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
var1 = tk.StringVar()  # 创建变量,用var1用来接收鼠标点击具体选项的内容
l = tk.Label(window, bg='green', fg='yellow',font=('Arial', 12), width=10, textvariable=var1)
l.pack()

# 第6步,创建一个方法用于按钮的点击事件
def print_selection():
    value = lb.get(lb.curselection())   # 获取当前选中的文本
    var1.set(value)  # 为label设置值

# 第5步,创建一个按钮并放置,点击按钮调用print_selection函数
b1 = tk.Button(window, text='print selection', width=15, height=2, command=print_selection)
b1.pack()

# 第7步,创建Listbox并为其添加内容
var2 = tk.StringVar()
var2.set((1,2,3,4)) # 为变量var2设置值
# 创建Listbox
lb = tk.Listbox(window, listvariable=var2)  #将var2的值赋给Listbox
# 创建一个list并将值循环添加到Listbox控件中
list_items = [11,22,33,44]
for item in list_items:
    lb.insert('end', item)  # 从最后一个位置开始加入值
lb.insert(1, 'first')       # 在第一个位置加入'first'字符
lb.insert(2, 'second')      # 在第二个位置加入'second'字符
lb.delete(2)                # 删除第二个位置的字符
lb.pack()

# 第8步,主窗口循环显示
window.mainloop()

在这里插入图片描述

6、Radiobutton窗口部件

简单说明:

  • Radiobutton:代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。

什么时候用:

  • 在有一个很多内容选项组成的选项列表提供用户选择时会用到,用户一次只能选择其中一个,不能多选。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
var = tk.StringVar()  # 定义一个var用来将radiobutton的值和Label的值联系在一起.
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()


# 第6步,定义选项触发函数功能
def print_selection():
    l.config(text='you have selected ' + var.get())


# 第5步,创建三个radiobutton选项,其中variable=var, value='A'的意思就是,当我们鼠标选中了其中一个选项,把value的值A放到变量var中,然后赋值给variable
r1 = tk.Radiobutton(window, text='Option A', variable=var, value='A', command=print_selection)
r1.pack()
r2 = tk.Radiobutton(window, text='Option B', variable=var, value='B', command=print_selection)
r2.pack()
r3 = tk.Radiobutton(window, text='Option C', variable=var, value='C', command=print_selection)
r3.pack()

# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

7、Checkbutton窗口部件

简单说明:

  • Checkbutton:代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换,选择和取消选择。

什么时候用:

  • 在有一个很多内容选项组成的选项列表提供用户选择时会用到,用户一次可以选择多个。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()


# 第6步,定义触发函数功能
def print_selection():
    if (var1.get() == 1) & (var2.get() == 0):  # 如果选中第一个选项,未选中第二个选项
        l.config(text='I love only Python ')
    elif (var1.get() == 0) & (var2.get() == 1):  # 如果选中第二个选项,未选中第一个选项
        l.config(text='I love only C++')
    elif (var1.get() == 0) & (var2.get() == 0):  # 如果两个选项都未选中
        l.config(text='I do not love either')
    else:
        l.config(text='I love both')  # 如果两个选项都选中


# 第5步,定义两个Checkbutton选项并放置
var1 = tk.IntVar()  # 定义var1和var2整型变量用来存放选择行为返回值
var2 = tk.IntVar()
c1 = tk.Checkbutton(window, text='Python', variable=var1, onvalue=1, offvalue=0,
                    command=print_selection)  # 传值原理类似于radiobutton部件
c1.pack()
c2 = tk.Checkbutton(window, text='C++', variable=var2, onvalue=1, offvalue=0, command=print_selection)
c2.pack()

# 第7步,主窗口循环显示
window.mainloop()

<\center>

8、Scale窗口部件

简单说明:

  • Scale: 尺度(拉动条),允许你通过滑块来设置一数字值。

什么时候用:

  • 在需要用户给出评价等级,或者给出一个评价分数,或者拉动滑动条提供一个具体的数值等等。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='green', fg='white', width=20, text='empty')
l.pack()

# 第6步,定义一个触发函数功能
def print_selection(v):
    l.config(text='you have selected ' + v)

# 第5步,创建一个尺度滑条,长度200字符,从0开始10结束,以2为刻度,精度为0.01,触发调用print_selection函数
s = tk.Scale(window, label='try me', from_=0, to=10, orient=tk.HORIZONTAL, length=200, showvalue=0,tickinterval=2, resolution=0.01, command=print_selection)
s.pack()

# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

9、Canvas窗口部件

(1)简单使用

简单说明:

  • Canvas:画布,提供绘图功能(直线、椭圆、多边形、矩形) 可以包含图形或位图,用来绘制图表和图,创建图形编辑器,实现定制窗口部件。

什么时候用:

  • 在比如像用户交互界面等,需要提供设计的图标、图形、logo等信息是可以用到画布。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建 500 * 200 大小的画布并放置各种元素
canvas = tk.Canvas(window, bg='green', height=200, width=500)
# 说明图片位置,并导入图片到画布上
image_file = tk.PhotoImage(file='pic.gif')  # 图片位置(相对路径,与.py文件同一文件夹下,也可以用绝对路径,需要给定图片具体绝对路径)
image = canvas.create_image(250, 0, anchor='n', image=image_file)  # 图片锚定点(n图片顶端的中间点位置)放在画布(250,0)坐标处
# 定义多边形参数,然后在画布上画出指定图形
x0, y0, x1, y1 = 100, 100, 150, 150
line = canvas.create_line(x0 - 50, y0 - 50, x1 - 50, y1 - 50)  # 画直线
oval = canvas.create_oval(x0 + 120, y0 + 50, x1 + 120, y1 + 50, fill='yellow')  # 画圆 用黄色填充
arc = canvas.create_arc(x0, y0 + 50, x1, y1 + 50, start=0, extent=180)  # 画扇形 从0度打开收到180度结束
rect = canvas.create_rectangle(330, 30, 330 + 20, 30 + 20)  # 画矩形正方形
canvas.pack()


# 第6步,触发函数,用来一定指定图形
def moveit():
    canvas.move(rect, 2, 2)  # 移动正方形rect(也可以改成其他图形名字用以移动一起图形、元素),按每次(x=2, y=2)步长进行移动


# 第5步,定义一个按钮用来移动指定图形的在画布上的位置
b = tk.Button(window, text='move item', command=moveit).pack()

# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

(2)canvas加滚动条

from tkinter import *

master = Tk()
master.geometry('600x600')
FrameBIG = Frame(master)

Main = Canvas(FrameBIG, background="blue", height=400, width=400)
Main.configure(scrollregion=Main.bbox("all"))

scroll = Scrollbar(FrameBIG, orient="vertical", command=Main.yview)
Main.configure(yscrollcommand=scroll.set)

scroll.pack(side="right", fill="y")


Main.pack(side=BOTTOM, anchor=NW, fill="x")
FrameBIG.pack(anchor=W)

Main.create_line(0, 0, 500, 1000)
Main.configure(scrollregion=Main.bbox("all"))

master.mainloop()

在这里插入图片描述

10、Menu窗口部件

简单说明:

  • Menu:菜单条,用来实现下拉和弹出式菜单,点下菜单后弹出的一个选项列表,用户可以从中选择

什么时候用:

  • 在比如像软件或网页交互界面等,需要提供菜单选项功能提供用户选择菜单选项功能时用到。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签用以显示内容并放置
l = tk.Label(window, text='      ', bg='green')
l.pack()

# 第10步,定义一个函数功能,用来代表菜单选项的功能,这里为了操作简单,定义的功能比较简单
counter = 0
def do_job():
    global counter
    l.config(text='do '+ str(counter))
    counter += 1

# 第5步,创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(window)

# 第6步,创建一个File菜单项(默认不下拉,下拉内容包括New,Open,Save,Exit功能项)
filemenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为File,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='File', menu=filemenu)

# 在File中加入New、Open、Save等小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
filemenu.add_command(label='New', command=do_job)
filemenu.add_command(label='Open', command=do_job)
filemenu.add_command(label='Save', command=do_job)
filemenu.add_separator()    # 添加一条分隔线
filemenu.add_command(label='Exit', command=window.quit) # 用tkinter里面自带的quit()函数

# 第7步,创建一个Edit菜单项(默认不下拉,下拉内容包括Cut,Copy,Paste功能项)
editmenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为 Edit,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='Edit', menu=editmenu)

# 同样的在 Edit 中加入Cut、Copy、Paste等小命令功能单元,如果点击这些单元, 就会触发do_job的功能
editmenu.add_command(label='Cut', command=do_job)
editmenu.add_command(label='Copy', command=do_job)
editmenu.add_command(label='Paste', command=do_job)

# 第8步,创建第二级菜单,即菜单项里面的菜单
submenu = tk.Menu(filemenu) # 和上面定义菜单一样,不过此处实在File上创建一个空的菜单
filemenu.add_cascade(label='Import', menu=submenu, underline=0) # 给放入的菜单submenu命名为Import

# 第9步,创建第三级菜单命令,即菜单项里面的菜单项里面的菜单命令(有点拗口,笑~~~)
submenu.add_command(label='Submenu_1', command=do_job)   # 这里和上面创建原理也一样,在Import菜单项中加入一个小菜单命令Submenu_1

# 第11步,创建菜单栏完成后,配置让菜单栏menubar显示出来
window.config(menu=menubar)

# 第12步,主窗口循环显示
window.mainloop()

在这里插入图片描述

11、Frame 窗口部件

简单说明:

  • Frame:框架,用来承载放置其他GUI元素,就是一个容器,是一个在 Windows 上分离小区域的部件, 它能将 Windows 分成不同的区,然后存放不同的其他部件. 同时一个 Frame 上也能再分成两个 Frame, Frame 可以认为是一种容器.

什么时候用:

  • 在比如像软件或网页交互界面等,有不同的界面逻辑层级和功能区域划分时可以用到,让交互界面逻辑更加清晰。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Label(window, text='on the window', bg='red', font=('Arial', 16)).pack()  # 和前面部件分开创建和放置不同,其实可以创建和放置一步完成

# 第5步,创建一个主frame,长在主window窗口上
frame = tk.Frame(window)
frame.pack()

# 第6步,创建第二层框架frame,长在主框架frame上面
frame_l = tk.Frame(frame)  # 第二层frame,左frame,长在主frame上
frame_r = tk.Frame(frame)  # 第二层frame,右frame,长在主frame上
frame_l.pack(side='left')
frame_r.pack(side='right')

# 第7步,创建三组标签,为第二层frame上面的内容,分为左区域和右区域,用不同颜色标识
tk.Label(frame_l, text='on the frame_l1', bg='green').pack()
tk.Label(frame_l, text='on the frame_l2', bg='green').pack()
tk.Label(frame_l, text='on the frame_l3', bg='green').pack()
tk.Label(frame_r, text='on the frame_r1', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r2', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r3', bg='yellow').pack()

# 第8步,主窗口循环显示
window.mainloop()

在这里插入图片描述

12、messageBox窗口部件

简单说明:

  • messageBox:消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox),其实这里的messageBox就是我们平时看到的弹窗。 我们首先需要定义一个触发功能,来触发这个弹窗,这里我们就放上以前学过的button按钮,通过触发功能,调用messagebox吧,点击button按钮就会弹出提示对话框。下面给出messagebox提示信息的几种形式:
tkinter.messagebox.showinfo(title='Hi', message='你好!')            # 提示信息对话窗
tkinter.messagebox.showwarning(title='Hi', message='有警告!')       # 提出警告对话窗
tkinter.messagebox.showerror(title='Hi', message='出错了!')         # 提出错误对话窗
print(tkinter.messagebox.askquestion(title='Hi', message='你好!'))  # 询问选择对话窗return 'yes', 'no'
print(tkinter.messagebox.askyesno(title='Hi', message='你好!'))     # return 'True', 'False'
print(tkinter.messagebox.askokcancel(title='Hi', message='你好!'))  # return 'True', 'False'

什么时候用:

  • 在比如像软件或网页交互界面等,有不同的界面逻辑层级和功能区域划分时可以用到,让交互界面逻辑更加清晰。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入
import tkinter.messagebox  # 要使用messagebox先要导入模块

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x


# 第5步,定义触发函数功能
def hit_me():
    tkinter.messagebox.showinfo(title='Hi', message='你好!')  # 提示信息对话窗
    # tkinter.messagebox.showwarning(title='Hi', message='有警告!')       # 提出警告对话窗
    # tkinter.messagebox.showerror(title='Hi', message='出错了!')         # 提出错误对话窗
    # print(tkinter.messagebox.askquestion(title='Hi', message='你好!'))  # 询问选择对话窗return 'yes', 'no'
    # print(tkinter.messagebox.askyesno(title='Hi', message='你好!'))     # return 'True', 'False'
    # print(tkinter.messagebox.askokcancel(title='Hi', message='你好!'))  # return 'True', 'False'


# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Button(window, text='hit me', bg='green', font=('Arial', 14), command=hit_me).pack()

# 第6步,主窗口循环显示
window.mainloop()

在这里插入图片描述

13、窗口部件三种放置方式pack/grid/place

  • 参考来源:
The Grid Geometry Manager
The Pack Geometry Manager
The Place Geometry Manager

1. Grid:The Grid Geometry Manager

grid 是方格, 所以所有的内容会被放在这些规律的方格中。例如:

for i in range(3):
    for j in range(3):
        tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)

以上的代码就是创建一个三行三列的表格,其实 grid 就是用表格的形式定位的。这里的参数 row 为行,colum 为列,padx 就是单元格左右间距,pady 就是单元格上下间距,ipadx是单元格内部元素与单元格的左右间距,ipady是单元格内部元素与单元格的上下间距。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,grid 放置方法
for i in range(3):
    for j in range(3):
        tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)

# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

2. Pack:The Pack Geometry Manager

我们常用的pack(), 他会按照上下左右的方式排列.例如:

tk.Label(window, text='P', fg='red').pack(side='top')    # 上
tk.Label(window, text='P', fg='red').pack(side='bottom') # 下
tk.Label(window, text='P', fg='red').pack(side='left')   # 左
tk.Label(window, text='P', fg='red').pack(side='right')  # 右

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,pack 放置方法
tk.Label(window, text='P', fg='red').pack(side='top')    # 上
tk.Label(window, text='P', fg='red').pack(side='bottom') # 下
tk.Label(window, text='P', fg='red').pack(side='left')   # 左
tk.Label(window, text='P', fg='red').pack(side='right')  # 右

# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3. Place:The Place Geometry Manager

再接下来我们来看place(), 这个比较容易理解,就是给精确的坐标来定位,如此处给的(50, 100),就是将这个部件放在坐标为(x=50, y=100)的这个位置, 后面的参数 anchor=‘nw’,就是前面所讲的锚定点是西北角。例如:

tk.Label(window, text='Pl', font=('Arial', 20), ).place(x=50, y=100, anchor='nw')

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('My Window')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300')  # 这里的乘是小x

# 第4步,place 放置方法(精准的放置到指定坐标点的位置上)
tk.Label(window, text='Pl', font=('Arial', 20), ).place(x=50, y=100, anchor='nw')

# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

14、综合练习,用户登录窗口例子

编写一个用户登录界面,用户可以登录账户信息,如果账户已经存在,可以直接登录,登录名或者登录密码输入错误会提示,如果账户不存在,提示用户注册,点击注册进去注册页面,输入注册信息,确定后便可以返回登录界面进行登录。

示例代码:

import tkinter as tk  # 使用Tkinter前需要先导入
import tkinter.messagebox
import pickle

# 第1步,实例化object,建立窗口window
window = tk.Tk()

# 第2步,给窗口的可视化起名字
window.title('Wellcome to Hongwei Website')

# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x300')  # 这里的乘是小x

# 第4步,加载 wellcome image
canvas = tk.Canvas(window, width=400, height=135, bg='green')
image_file = tk.PhotoImage(file='pic.gif')
image = canvas.create_image(200, 0, anchor='n', image=image_file)
canvas.pack(side='top')
tk.Label(window, text='Wellcome',font=('Arial', 16)).pack()

# 第5步,用户信息
tk.Label(window, text='User name:', font=('Arial', 14)).place(x=10, y=170)
tk.Label(window, text='Password:', font=('Arial', 14)).place(x=10, y=210)

# 第6步,用户登录输入框entry
# 用户名
var_usr_name = tk.StringVar()
var_usr_name.set('example@python.com')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name, font=('Arial', 14))
entry_usr_name.place(x=120,y=175)
# 用户密码
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, font=('Arial', 14), show='*')
entry_usr_pwd.place(x=120,y=215)

# 第8步,定义用户登录功能
def usr_login():
    # 这两行代码就是获取用户输入的usr_name和usr_pwd
    usr_name = var_usr_name.get()
    usr_pwd = var_usr_pwd.get()

    # 这里设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以这里设置异常捕获。
    # 中间的两行就是我们的匹配,即程序将输入的信息和文件中的信息匹配。
    try:
        with open('usrs_info.pickle', 'rb') as usr_file:
            usrs_info = pickle.load(usr_file)
    except FileNotFoundError:
        # 这里就是我们在没有读取到`usr_file`的时候,程序会创建一个`usr_file`这个文件,并将管理员
        # 的用户和密码写入,即用户名为`admin`密码为`admin`。
        with open('usrs_info.pickle', 'wb') as usr_file:
            usrs_info = {'admin': 'admin'}
            pickle.dump(usrs_info, usr_file)
            usr_file.close()    # 必须先关闭,否则pickle.load()会出现EOFError: Ran out of input

    # 如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗how are you? 加上你的用户名。
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:
            tkinter.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)
        # 如果用户名匹配成功,而密码输入错误,则会弹出'Error, your password is wrong, try again.'
        else:
            tkinter.messagebox.showerror(message='Error, your password is wrong, try again.')
    else:  # 如果发现用户名不存在
        is_sign_up = tkinter.messagebox.askyesno('Welcome! ', 'You have not sign up yet. Sign up now?')
        # 提示需不需要注册新用户
        if is_sign_up:
            usr_sign_up()

# 第9步,定义用户注册功能
def usr_sign_up():
    def sign_to_Hongwei_Website():
        # 以下三行就是获取我们注册时所输入的信息
        np = new_pwd.get()
        npf = new_pwd_confirm.get()
        nn = new_name.get()

        # 这里是打开我们记录数据的文件,将注册信息读出
        with open('usrs_info.pickle', 'rb') as usr_file:
            exist_usr_info = pickle.load(usr_file)
        # 这里就是判断,如果两次密码输入不一致,则提示Error, Password and confirm password must be the same!
        if np != npf:
            tkinter.messagebox.showerror('Error', 'Password and confirm password must be the same!')

        # 如果用户名已经在我们的数据文件中,则提示Error, The user has already signed up!
        elif nn in exist_usr_info:
            tkinter.messagebox.showerror('Error', 'The user has already signed up!')

        # 最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功Welcome!,You have successfully signed up!,然后销毁窗口。
        else:
            exist_usr_info[nn] = np
            with open('usrs_info.pickle', 'wb') as usr_file:
                pickle.dump(exist_usr_info, usr_file)
            tkinter.messagebox.showinfo('Welcome', 'You have successfully signed up!')
            # 然后销毁窗口。
            window_sign_up.destroy()

    # 定义长在窗口上的窗口
    window_sign_up = tk.Toplevel(window)
    window_sign_up.geometry('300x200')
    window_sign_up.title('Sign up window')

    new_name = tk.StringVar()  # 将输入的注册名赋值给变量
    new_name.set('example@python.com')  # 将最初显示定为'example@python.com'
    tk.Label(window_sign_up, text='User name: ').place(x=10, y=10)  # 将`User name:`放置在坐标(10,10)。
    entry_new_name = tk.Entry(window_sign_up, textvariable=new_name)  # 创建一个注册名的`entry`,变量为`new_name`
    entry_new_name.place(x=130, y=10)  # `entry`放置在坐标(150,10).

    new_pwd = tk.StringVar()
    tk.Label(window_sign_up, text='Password: ').place(x=10, y=50)
    entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show='*')
    entry_usr_pwd.place(x=130, y=50)

    new_pwd_confirm = tk.StringVar()
    tk.Label(window_sign_up, text='Confirm password: ').place(x=10, y=90)
    entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*')
    entry_usr_pwd_confirm.place(x=130, y=90)

    # 下面的 sign_to_Hongwei_Website
    btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Hongwei_Website)
    btn_comfirm_sign_up.place(x=180, y=120)

# 第7步,login and sign up 按钮
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=120, y=240)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=200, y=240)

# 第10步,主窗口循环显示
window.mainloop()
<\center>

15、设置窗体、按钮等背景为图片

import tkinter
import tkinter.messagebox
from PIL import Image, ImageTk

bg_width = 960
bg_height = 540
bt_width = 200
bt_height = 80


# 打开指定图片,缩放至自定尺寸
def get_image(filename, width, height):
    im = Image.open(filename).resize((width, height))
    return ImageTk.PhotoImage(im)


window = tkinter.Tk()
window.title('背景图片')
window.geometry('960x540+300+150')
window.resizable(False, False)

# 创建画布,设置要显示的图片,把画布添加至应用程序窗口
canvas_root = tkinter.Canvas(window, width=bg_width, height=bg_height)
im_root = get_image('窗口图片.jpg', bg_width, bg_height)
canvas_root.create_image(bg_width/2, bg_height/2, image=im_root)
canvas_root.pack()

# 为label设置图片
im_label = get_image('标签图片.jpg', bt_width, bt_height)
lbImage = tkinter.Label(window, text='我是个标签', image=im_label)
lbImage.place(x=3, y=3, width=bt_width, height=bt_height)


# 为按钮设置背景图片
def onclick():
    tkinter.messagebox.showinfo('提示', '您单击了确定按钮')


im_button = get_image('按钮图片.jpg', bt_width, bt_height)
btnOk = tkinter.Button(window, text='确定', font=('Arial', 32), image=im_button, compound=tkinter.CENTER,  # 这个参数很重要
                       command=onclick)
btnOk.place(x=int(bt_width*1.2), y=3, width=bt_width, height=bt_height)

# 为复选框设置背景图片,注意图片尺寸
variable_checkbutton = tkinter.IntVar(window, value=1)
im_checkbutton = get_image('复选框图片.jpg', int(bt_width*0.8), bt_height)


def checkChanged():
    msg = '选中' if variable_checkbutton.get() == 1 else '未选中'
    tkinter.messagebox.showinfo('提示', f'复选框处于{msg}状态')


cbtnTest = tkinter.Checkbutton(window, text='测试', font=('Arial', 32), variable=variable_checkbutton, onvalue=1, offvalue=0,
                               compound=tkinter.CENTER,  # 设置为背景图片
                               image=im_checkbutton, command=checkChanged)
cbtnTest.place(x=int(bt_width*2.4), y=3, width=int(bt_width), height=bt_height)

window.mainloop()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16、创建多个窗口

from tkinter import Tk, ttk, Toplevel


class RootWindow:
    def __init__(self, master):
        self.master = master
        self.frame = ttk.Frame(self.master)
        self.new_button('点击此处打开窗口1', '1', Win2)
        self.new_button('点击此处打开窗口2', '2', Win3)
        self.frame.pack()

    def new_button(self, text, number, _class):
        ttk.Button(self.frame, text=text, command=lambda: self.new_window(number, _class)).pack()

    def new_window(self, number, class_):
        self.new = Toplevel(self.master)
        class_(self.new, number)


class Win2:
    def __init__(self, master, number):
        self.master = master
        self.master.geometry("400x400+200+200")
        self.frame = ttk.Frame(self.master)
        self.quit = ttk.Button(self.frame, text=f"退出窗口{number}", command=self.close_window)
        self.frame.pack()
        self.quit.pack()

    def close_window(self):
        self.master.destroy()


class Win3(Win2):
    def __init__(self, master, number):
        super().__init__(master, number)
        self.master.geometry("400x400+200+200")
        self.label = ttk.Label(self.frame, text="这里是第三个窗口")
        self.label.pack()


root = Tk()
root.geometry("300x200")
self = RootWindow(root)
root.mainloop()

在这里插入图片描述
在这里插入图片描述

17、获取文件、文件夹路径

from tkinter import filedialog as fd

file = fd.askdirectory()
print(file)

file = fd.askopenfilename()
print(file)
  • 结果
D:/cuda
D:/cuda/cuda位置.png

三、模板

1、word和excel输入输出的例子

import tkinter
import time
import threading
from tkinter import ttk

event = threading.Event()
once = 0


def start():
    global once
    if once == 1:
        # event.set()
        # print('继续')
        pass
    else:

        event.set()
        t1 = threading.Thread(target=thread)
        # print(threading.currentThread())  //获取线程id
        t1.setDaemon(True)
        # validate()
        t1.start()
        print("开始")
        once += 1


def stop():
    event.clear()
    print('暂停')


def conti():
    event.set()
    print('继续')


def main():
    try:
        print(s1.get(), s2.get())
        for i in range(0, 30):
            mpb["value"] = i
            text.see(tkinter.END)  # 一直查看文本的最后位置~
            text.insert('end', "验证不通过,请查看!" + str(i) + "\r\n")
            # scale.config(mode='determinate', maximum=11.0, value=i)
            text.update()  # 一直更新输出
            print(i)
            time.sleep(0.1)
            event.wait()
            window.update()

        text.insert('end', "程序运行完成!" + "\r\n")
        text.update()
        text.see(tkinter.END)
        print("验证不通过!")
        pass
    except:
        pass


def thread():
    # while True:
    main()


window = tkinter.Tk()
window.title('测试')

#

l1 = tkinter.Label(text="word输出文件路径")
l1.grid(row=0, column=0)

# e1=tkinter.Entry("")
s1 = tkinter.StringVar()
entry1 = tkinter.Entry(window, textvariable=s1)
entry1.grid(row=0, column=1)

l2 = tkinter.Label(text="Excel文件路径")
l2.grid(row=1, column=0)

# e2=tkinter.Entry("")
s2 = tkinter.StringVar()
entry2 = tkinter.Entry(window, textvariable=s2)
entry2.grid(row=1, column=1)

i = 0
mpb = ttk.Progressbar(window, orient="horizontal", length=200, value=0, mode="determinate")
mpb.grid(row=2, column=0, columnspan=2)

button1 = tkinter.Button(window, text='开始', command=start)
button1.grid(row=0, column=2)
button2 = tkinter.Button(window, text='暂停', command=stop)
button2.grid(row=1, column=2)
button3 = tkinter.Button(window, text='继续', command=conti)
button3.grid(row=2, column=2)

from tkinter import scrolledtext  # 导入滚动文本框的模块

scrolW = 50  # 设置文本框的长度
scrolH = 18  # 设置文本框的高度
text = scrolledtext.ScrolledText(window, width=scrolW, height=scrolH, wrap=tkinter.WORD)
text.grid(row=10, columnspan=8, sticky=tkinter.E)

tkinter.mainloop()

在这里插入图片描述

Reference

  1. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了)
  2. tkinter 手册
  3. Python+tkinter应用程序设置背景图片
  4. Python GUI中 text框里实时输出
  5. 【TKINTER组件专栏】MESSAGE:轻松自动换行的文本显示
  6. 【tkinter】把tkinter滚动条加到text中
  • 32
    点赞
  • 208
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
服务端: 服务端程序启动之后弹出窗口,管理员输入IP、端口等信息之后点击启动按钮,服务器启动,服务端窗口自动关闭,之后跳转至服务端信息展示界面,包含用户上线提醒,用户发送信息记录展示。 客户端: 客户端程序启动之后,需要弹出登录界面,当用户成功输入昵称、密码、端口、IP等信息(考虑到用户权限问题,本程序在后台默认有固定IP、端口,)用户只需输入昵称、密码(密码用于后期连接数据库时用来匹配数据库存储的用户信息)。当用户成功输入用户名。昵称、密码等信息客户端登录成功跳转至用户进行端对端的聊天界面。聊天界面大致分为聊天记录展示界面,在线好友信息界面以及用户发送信息处。用户在发送消息处输入想要发送的文本消息,选择在线好友中的好友昵称点击选择好友即可选中您要发给的好友昵称,然后点击发送按钮,即可将消息发送给所选择的好友,同时将信息展示在自己的聊天界面中的聊天记录处 2.2. 功能要求 §2.2.1服务端功能要求: 当管理员输入服务器IP、以及端口等信息之后点击启动按钮之后,服务端正常启动之后,需要保持一直开机状态满足所有用户不论在何时登录之后都能进行与好友之间的聊天交流等,同时服务端还要满足监控用户登录信息,不同用户登录客户端之后,服务器后台能够看到某某客户上线了等提示信息。用于服务端查看好友在线状态同时作为服务器,还要能够监控用户的聊天记录,用于监控用户不能发送一些不利言论,从而将其用户及时作封号处理。阻止其传播一些不健康的言论。 §2.2.2客户端要求: 用户在登录界面输入昵称、密码等信息之后成功登录之后,进行窗口之间的跳转,由登录窗口跳转至进行用户之间的聊天窗口,之前的登录窗口也要随之消失。在聊天窗口之中用户需要根据好友在线信息情况选择自己想要与其进行聊天的对象。用户点击在线好友的昵称点击选择好友即可向该好友发送信息,发送成功之后同时要将其发送的信息以及时间信息展示在自己的窗口之中,同时也要在指定好友的窗口之中有所显示以及时间信息

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值