Python 的Tkinter包系列之六:好例子

Python 的Tkinter包系列之六:好例子

包括:按钮点击计数器、简易计算器、简单绘图、数学函数作图。

用Tkinter写一个桌面应用程序,只需要三步:

1)创建一个窗体

2)把需要的控件放到窗体上(控件布局:设置控件在窗体内的位置以及填充、间隔等属性,使用pack、grid 和 place方法),并告诉它们当有预期的事件发生时就执行预设的动作(Tkinter的灵魂是事件驱动机制:当某事件发生时,程序就会自动执行预先设定的动作。事件驱动机制有三个要素:事件、事件函数和事件绑定)。

3)启动循环监听事件。(用mainloop()方法使主窗口进入消息事件循环,mainloop()方法的位置一定是放在最后,如果没有使主窗口进入消息事件循环,那么主窗口就不会出现。【提示:没有mainloop()方法窗口也没消失?那你是在IDLE中运行,用双击py文件 或 右击py文件使用“打开方式→Python”快捷菜单命令运行时没有mainloop()方法,你不会看到窗口】

无论这个程序有多么简单或多么复杂,第1步和第3步是固定不变的,设计者只需要专注于第2步的实现。

按钮点击计数器

下面给出一个最简单的GUI应用程序——按钮点击计数器示例:

from tkinter import *

#事件函数, evt是事件对象
def on_button(evt):             
    counter.set(counter.get()+1)

#创建一个窗体
root = Tk()
root.title('按钮点击计数器')
root.geometry('320x160')
        
counter = IntVar() # 创建一个整型变量对象
counter.set(0) # 置其初值为0

label = Label(root, textvariable=counter, font=("Arial Bold", 50)) # 将Label和整型变量对象关联
label.pack(side='left', expand='yes', fill='both', padx=5, pady=5)

btn = Button(root, text='点我试试看', bg='#90F0F0')
btn.pack(side='right', anchor='center', fill='y', padx=5, pady=5)

btn.bind('<Button-1>', on_button) # 绑定事件和事件函数

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

from tkinter import *

def click_button():
    """事件函数"""    
    root.destroy() # 调用root的析构函数

运行效果:

现在点击按钮就可以看到效果了——单击一次按钮数字就加1

这就是Tkinter事件驱动机制在起作用!

熟悉OOP的读者,可能希望用面向对象的方式设计了一个按钮点击计数器。下面的代码就是: 

from tkinter import *

#继承Tk,创建自己的桌面应用程序类
class MyApp(Tk):
    #构造函数
    def __init__(self):         
        super().__init__()
        #创建一个窗体
        self.title('按钮点击计数器')
        self.geometry('320x160')
                
        self.counter = IntVar() # 创建一个整型变量对象
        self.counter.set(0) # 置其初值为0
        
        label = Label(self, textvariable=self.counter, font=("Arial Bold", 50)) # 将Label和整型变量对象关联
        label.pack(side='left', expand='yes', fill='both', padx=5, pady=5)
        
        btn = Button(self, text='点我试试看', bg='#90F0F0')
        btn.pack(side='right', anchor='center', fill='y', padx=5, pady=5)
        
        btn.bind('<Button-1>', self.on_button) # 绑定事件和事件函数

    #事件函数, evt是事件对象
    def on_button(self, evt):             
        self.counter.set(self.counter.get()+1)

app = MyApp()
#进入消息事件循环
app.mainloop()

运行效果和上图一样

python支持多种编程范式。

☆面向过程的程序设计(Process oriented programming),也称为结构化程序设计(Structured programming),有时会被视为是指令式编程(Imperative programming)的同义语。编写程序可以说是这样一个过程:从系统要实现的功能入手把复杂的任务分解成子任务,把子任务再分解成更简单的任务,层层分解来完成。可以采用函数(function)或过程(procedure)一步步细化调用实现。

☆面向对象程序设计(Object Oriented Programming),是围绕着问题域中的对象(Object)来设计,对象包含属性、方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关联的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。

【编程范式是编程语言的一种分类方式,它并不针对某种编程语言,是从编程思想这个角度分析解决问题。就编程语言而言,一种编程语言也可以支持适用多种编程范式。更多情况Python面向对象程序设计讲座_软件开发技术爱好者的博客-CSDN博客

简易计算器

下面给出Tkinter完成的例子

以“简易计算器”为例,用两种程序设计思想实现。

下面是采用面向过程技术的实现

#简易计算器(面向过程)
from tkinter import *
reset=True

def buttonCallBack(event): 
     global label 
     global reset 
     num=event.widget['text'] 
     if num=='C': 
         label['text']="0"
         return
     if num in "=": 
         label['text']=str(eval(label['text'])) 
         reset=True
         return
     s=label['text'] 
     if s=='0' or reset==True: 
         s="" 
         reset=False
     label['text']=s+num
 
#主窗口 
root=Tk() 
root.wm_title("简易计算器") 
#显示栏1 
label=Label(root,text="0",background="light gray",anchor="e") 
label['width']=35
label['height']=2
label.grid(row=1,columnspan=4,sticky=W) 
#按钮 
showText="789/456*123-0.C+"
for i in range(4): 
    for j in range(4): 
         b=Button(root,text=showText[i*4+j],width=7) 
         b.grid(row=i+2,column=j) 
         b.bind("<Button-1>",buttonCallBack) 
showText="()"
for i in range(2): 
    b=Button(root,text=showText[i],width=7) 
    b.grid(row=6,column=2+i) 
    b.bind("<Button-1>",buttonCallBack) 
b=Button(root,text="=") 
b.grid(row=6,columnspan=2,sticky="we") 
b.bind("<Button-1>",buttonCallBack) 
root.mainloop()

运行效果:

下面是采用面向对象技术的实现

# 简单计算器(采用类技术)
from tkinter import *
class App:
    def __init__(self, master):
        self.master = master
        self.initWidgets()
        self.hi = None
        
    def initWidgets(self):
        # 创建一个输入组件
        self.show = Label(relief=SUNKEN, font=('Courier New', 24),\
            width=23, bg='white', anchor=W)
        # 对该输入组件使用Pack布局,放在容器顶部
        self.show.pack(side=TOP, pady=10)
        p = Frame(self.master)
        p.pack(side=TOP)
        # 定义字符串的元组
        names = ("+", "1" , "2" , "3" , "C" 
            ,"-", "4" , "5" , "6" , "**" , "*", "7" , "8"
            , "9", "//", "/" , "." , "0" , "%", "=")
        # 遍历字符串元组
        for i in range(len(names)):
            # 创建Button,将Button放入p组件中
            b = Button(p, text=names[i], font=('Verdana', 20), width=5)
            b.grid(row=i // 5, column=i % 5)
            # 为鼠标左键的单击事件绑定事件处理方法
            b.bind('<Button-1>', self.click)
            # 为鼠标左键的双击事件绑定事件处理方法
            if b['text'] == 'C': b.bind('<Button-1>', self.clean)
        # 定义一个记录输入数字次数的变量
        self.i = 0
        
    def click(self, event):
        # 如果用户单击的是数字键或点号
        if(event.widget['text'] in ('0', '1', '2', '3',\
            '4', '5', '6', '7', '8', '9', '.')):
            # 判断self.i是否为0,0的话清空show['text']的值
            if self.i == 0 :
                self.show['text'] = ''
            self.show['text'] = self.show['text'] + event.widget['text']
            self.i = self.i + 1
            print(self.i)
        # 如果用户单击了运算符
        elif(event.widget['text'] in ('+', '-', '*', '/', '%', '**', '//')):
            # 把输入的数字与输入的字符相结合,组成一个数学运算式
            self.show['text'] = self.show['text'] + event.widget['text']
        elif(event.widget['text'] == '=' and self.show['text'] is not None):
            # 赋值给self.hi
            self.hi = self.show['text']
            # 其实这一步可以不要,主要作用是在调试时可以在后台看输入的数据
            print(self.hi)
            # 使用eval函数计算表达式的值
            self.show['text'] = str(eval(self.hi))
            self.hi = None
            self.i = 0
    # 点击C(恢复)按钮时,程序清空计算结果、将表达式设为None
    
    def clean(self, event):
        self.hi = None
        self.show['text'] = ''
        
root = Tk()
root.title("简单计算器")
App(root)
root.mainloop()

运行效果:

简单绘图

 下面是一个“简单绘图“采用面向对象技术源码:

from tkinter import *
from tkinter import messagebox
from tkinter.colorchooser import askcolor

win_width = 780
win_height = 520
bgcolor = '#FFFFFF'  

class Application(Frame):
    """一个经典的GUI写法"""

    def __init__(self, master=None):
        """初始化方法"""
        super().__init__(master)  # 调用父类的初始化方法
        self.x = 0
        self.y = 0
        self.fgcolor = 'black'
        self.lastdraw = 0
        self.start_flag = False
        self.master = master
        self.pack()
        self.createWidget()
        self.pen_width = 1  # 线的粗细

    def createWidget(self):
        """创建画图区域"""
        self.drawpad = Canvas(self, width=win_width, height=win_height, bg=bgcolor)
        self.drawpad.pack()
        # 创建按钮     
        self.btn_pen = Button(self, name='pen', text='画笔')
        self.btn_pen.pack(side='left', padx=10)
        self.btn_rect = Button(self, name='rect', text='矩形')
        self.btn_rect.pack(side='left', padx=10)        
        self.btn_oval = Button(self, name='oval', text='圆形')  # 新增按钮:画圆
        self.btn_oval.pack(side='left', padx=10)        
        self.btn_line = Button(self, name='line', text='直线')
        self.btn_line.pack(side='left', padx=10)
        self.btn_dashed_line = Button(self, name='dashed_line', text='虚直线')
        self.btn_dashed_line.pack(side='left', padx=10)
        self.btn_line_arrow = Button(self, name='line_arrow', text='箭头直线')
        self.btn_line_arrow.pack(side='left', padx=10)
        self.btn_color = Button(self, name='color', text='颜色')
        self.btn_color.pack(side='left', padx=10)
        self.btn_eraser = Button(self, name='eraser', text='橡皮擦')
        self.btn_eraser.pack(side='left', padx=10)
        self.btn_clear = Button(self, name='clear', text='清屏')
        self.btn_clear.pack(side='left', padx=10)
        self.scl_pen_width = Scale(self, from_=1, to=10, orient=HORIZONTAL, label='线条粗细')  # 新增:线条粗细调整
        self.scl_pen_width.pack(side='left', padx=10)
        
        self.lbl_current_tool = Label(self, text="工具:未选", font=("Arial", 10)) # 提示
        self.lbl_current_tool.pack(side='bottom', pady=10)
         
        # 绑定事件
        self.btn_line.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_line_arrow.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_rect.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_pen.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_eraser.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_clear.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_color.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_oval.bind('<Button-1>', self.eventManager)  # 点击按钮事件
        self.btn_dashed_line.bind('<Button-1>', self.eventManager)# 虚直线点击事件 
        self.drawpad.bind('<ButtonRelease-1>', self.stopDraw)  # 左键释放按钮

    def eventManager(self, event):
        name = event.widget.winfo_name()
        print(name)
        self.start_flag = True
        self.pen_width = self.scl_pen_width.get()  # 获取线条粗细值
        tool_name = "未选"
        if name == 'line':
            self.drawpad.bind('<B1-Motion>', self.myline)
            tool_name = "直线"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'dashed_line':
            self.drawpad.bind('<B1-Motion>', self.mydashedline)
            tool_name = "虚直线"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'line_arrow':
            self.drawpad.bind('<B1-Motion>', self.myline_arrow)
            tool_name = "箭头直线"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'rect':
            self.drawpad.bind('<B1-Motion>', self.myrect)
            tool_name = "矩形"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'oval':
            self.drawpad.bind('<B1-Motion>', self.myoval)
            tool_name = "圆形"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'pen':
            self.drawpad.bind('<B1-Motion>', self.mypen)
            tool_name = "画笔"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'eraser':
            self.drawpad.bind('<B1-Motion>', self.myeraser)
            tool_name = "橡皮擦"
            self.lbl_current_tool.config(text=f"当前: {tool_name}")
        elif name == 'clear':
            self.drawpad.delete('all')
            # tool_name = "清屏"
        elif name == 'color':
            c = askcolor(color=self.fgcolor, title='请选择颜色')
            print(c)
            self.fgcolor = c[1]
            # tool_name = "颜色选择"

    def startDraw(self, event):
        self.drawpad.delete(self.lastdraw)
        if self.start_flag:
            self.start_flag = False
            self.x = event.x
            self.y = event.y

    def stopDraw(self, event):
        self.start_flag = True
        self.lastdraw = 0

    # 直线
    def myline(self, event):
        self.startDraw(event)
        self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width)

    # 虚直线
    def mydashedline(self, event):
        self.startDraw(event)
        # dash参数定义了虚线的模式,比如(4, 4)表示线段长度为4,空白也为4
        self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width, dash=(4, 4))

    # 带箭头的线
    def myline_arrow(self, event):
        self.startDraw(event)
        self.lastdraw = self.drawpad.create_line(self.x, self.y, event.x, event.y, arrow=LAST, fill=self.fgcolor, width=self.pen_width)        

    # 矩形
    def myrect(self, event):
        self.startDraw(event)
        self.lastdraw = self.drawpad.create_rectangle(self.x, self.y, event.x, event.y, outline=self.fgcolor, width=self.pen_width)

    # 画笔
    def mypen(self, event):
        self.startDraw(event)
        # print('self.x=', self.x, ',self.y=', self.y)
        self.drawpad.create_line(self.x, self.y, event.x, event.y, fill=self.fgcolor, width=self.pen_width)
        self.x = event.x
        self.y = event.y

    # 橡皮擦
    def myeraser(self, event):
        self.startDraw(event)
        eraser_size = 10  # 定义橡皮擦的大小
        self.drawpad.create_rectangle(event.x - eraser_size/2, event.y - eraser_size/2, event.x + eraser_size/2, event.y + eraser_size/2, fill=bgcolor, outline=bgcolor)
        self.x = event.x
        self.y = event.y        

    # 圆
    def myoval(self, event):
        self.startDraw(event)
        self.lastdraw = self.drawpad.create_oval(self.x, self.y, event.x, event.y, outline=self.fgcolor, width=self.pen_width)        


if __name__ == '__main__':
    root = Tk()
    root.title('画图窗口')
    root.geometry('800x600+200+100')
    app = Application(master=root)
    root.mainloop()

运行效果:

下面的简单绘图例子支持“撤销”和“恢复”功能,并可以使用右键菜单

源码如下:

import tkinter as tk
from tkinter import ttk
import math

class tkinter_example(object):
    def __init__(self):
        self.win = tk.Tk()  # 创建主窗口
        self.win.title("tkinter Canvas实现鼠标画图板")  # 设置窗口标题

        self.create_widgets()  # 创建窗口内的组件
        self.center_window()  # 将窗口居中显示

        self.win.resizable(0, 0)  # 禁止窗口改变大小
        self.win.mainloop()  # 运行主事件循环

    def create_widgets(self):
        self.width, self.height = 600, 400  # 画布宽高

        # 创建放置按钮的框架
        self.button_frame = tk.Frame(self.win)
        self.button_frame.grid(row=0, column=0, sticky='ew')
        self.button_frame.columnconfigure(0, weight=1)  # 让按钮水平居中

        # 添加按钮
        self.undo_button = ttk.Button(self.button_frame, text='撤销', command=lambda: self.canvas_re(rev=1))
        self.undo_button.grid(row=0, column=0)
        self.redo_button = ttk.Button(self.button_frame, text='重做', command=lambda: self.canvas_re(rec=1))
        self.redo_button.grid(row=0, column=1)
        self.clear_button = ttk.Button(self.button_frame, text='清除', command=self.canvas_clear)
        self.clear_button.grid(row=0, column=2)

        self.pen_button = ttk.Button(self.button_frame, text='笔', command=self.use_pen)
        self.pen_button.grid(row=0, column=3)
        self.line_button = ttk.Button(self.button_frame, text='直线', command=self.use_line)
        self.line_button.grid(row=0, column=4)
        self.circle_button = ttk.Button(self.button_frame, text='圆', command=self.use_circle)
        self.circle_button.grid(row=0, column=5)

        # 创建画布
        self.canvas = tk.Canvas(self.win, width=self.width, height=self.height, highlightthickness=0, bg='white')
        self.canvas.grid(row=1, column=0)

        self.revoke = []  # 保存撤销操作的图形
        self.recover = []  # 保存恢复操作的图形

        self.canvas.bind("<Button-1>", self.canvas_click)  # 绑定鼠标点击事件
        self.canvas.bind("<B1-Motion>", self.canvas_draw)  # 绑定鼠标拖动事件
        self.canvas.bind("<ButtonRelease-1>", self.canvas_release)  # 绑定鼠标释放事件

        self.create_right_click_menu()  # 创建右键菜单

        self.tool = "pen"  # 默认使用笔工具

    def create_right_click_menu(self):
        menu = tk.Menu(self.win, tearoff=0)
        menu.add_command(label="撤销", command=lambda: self.canvas_re(rev=1))
        menu.add_command(label="重做", command=lambda: self.canvas_re(rec=1))
        menu.add_command(label="清除", command=self.canvas_clear)
        self.canvas.bind("<Button-3>", lambda event: menu.post(event.x_root, event.y_root))

    def canvas_click(self, event):
        if self.tool == "line" or self.tool == "circle":
            self.start_point = [event.x, event.y]
            self.canvas_store()
        elif self.tool == "pen":
            self.canvas_store()
            self.draw_point = [event.x, event.y]

    def canvas_draw(self, event):
        if self.tool == "pen":
            item = self.canvas.create_line(self.draw_point[0], self.draw_point[1], event.x, event.y, fill="#476042", width=1, tags="line")
            self.revoke[-1].append(("line", self.canvas.coords(item)))
            self.draw_point = [event.x, event.y]

    def canvas_release(self, event):
        if self.tool == "line":
            item = self.canvas.create_line(self.start_point[0], self.start_point[1], event.x, event.y, fill="#476042", width=1, tags="line")
            self.revoke[-1].append(("line", self.canvas.coords(item)))
        elif self.tool == "circle":
            radius = math.sqrt((event.x - self.start_point[0]) ** 2 + (event.y - self.start_point[1]) ** 2)
            item = self.canvas.create_oval(self.start_point[0] - radius, self.start_point[1] - radius,
                                           self.start_point[0] + radius, self.start_point[1] + radius,
                                           outline="#476042", width=1, tags="circle")
            self.revoke[-1].append(("circle", self.canvas.coords(item)))

    def canvas_store(self):
        if len(self.revoke) < len(self.recover):
            self.recover = self.recover[:len(self.revoke)]
        self.revoke.append([])

    def canvas_re(self, rev=0, rec=0):
        if rev and self.revoke:
            items = self.revoke.pop()
            self.recover.append(items)
            for item in items:
                if item[0] == "line":
                    self.canvas.delete(self.canvas.find_withtag("line")[-1])
                else:
                    self.canvas.delete(self.canvas.find_withtag("circle")[-1])
        elif rec and self.recover:
            items = self.recover.pop()
            self.revoke.append(items)
            for item in items:
                if item[0] == "line":
                    self.canvas.create_line(item[1], fill="#476042", width=1, tags="line")
                else:
                    self.canvas.create_oval(item[1], outline="#476042", width=1, tags="circle")

    def canvas_clear(self):
        self.canvas.delete("line", "circle")
        self.revoke = []
        self.recover = []

    def center_window(self):
        self.win.geometry('%dx%d+%d+%d' % (self.width, self.height + 40,  # 增加按钮框架高度
                                            (self.win.winfo_screenwidth() - self.width) / 2,
                                            (self.win.winfo_screenheight() - self.height - 40) / 2))  # 减去按钮框架高度

    def use_pen(self):
        self.tool = "pen"

    def use_line(self):
        self.tool = "line"

    def use_circle(self):
        self.tool = "circle"

tkinter_example()

运行效果:

数学函数作图

下面是一个数学函数作图——熠函数绘图工具。取自https://v-wb.youku.com/v_show/id_XNDYzMDc0MTYyOA==.html仅做少量修订。

先给出运行效果图:

特别提示:若显示的图像太小看不清,使用“+ ”按钮放大!

【使用说明:
1.点击左下角“新建”按钮",出现“新建函数”对话框,输入函数。
2.在绘图区显示函数图像。双击左侧函数列表中的函数可以在修改框中进行修改,回车确认。
注意:回车确认时,函数列表中的函数应处于选中状态。",
3.使用“+ -”可以放大缩小;“精度滑动条”可以调节精度。】

 源码如下:

#https://v-wb.youku.com/v_show/id_XNDYzMDc0MTYyOA==.html
from math import * #导入绘图模块
from tkinter import *
from tkinter.simpledialog import askstring
from tkinter.messagebox import askokcancel

text=["熠函数绘图工具,简易数学函数绘图。",
      "",
      "可以绘制简单的数学函数图像。",
      "",
      "1.点击左下角“新建”按钮,出现“新建函数”对话框,可以输入函数",
      "",
      "2.在绘图区显示函数图像。双击左侧函数列表中的函数可以在修改框中进行修改,回车确认。",
      "",
      "注意:回车确认时,函数列表中的函数应处于选中状态。",
      "",
      "3.使用“+ -”可以放大缩小;“精度滑动条”可以调节精度。",
      "",      
      "开发者:义乌东河小学学生孙璟熠。",
      ]
a=Tk()
a.title("")
a.geometry("900x620")
a.title("函数绘图 V1.4")
a.resizable(0,0)
size=10
mouse=[]
bc=80
help3=0
gb=0

def close():
    global a,help3
    if askokcancel("退出","你要退出吗?"):
        a.destroy()
        if help3!=0:
            help3.destroy()

def update(_=0):
    global c,size,s,bc,l,t4
    c.delete(ALL)
    j=s.get()
    functions=l.get(0,END)
    for z in range(-20,20):
        if z%4==0:
            c.create_line(z*20+375,0,z*20+375,500,fill="#202020")
        else:
            c.create_line(z*20+375,0,z*20+375,500,fill="#101010")
    for z in range(-16,16):
        if z%4==0:
            c.create_line(0,z*20+255,750,z*20+255,fill="#202020")
        else:
            c.create_line(0,z*20+255,750,z*20+255,fill="#101010")
    c.create_line(375,0,375,510,fill="#5a5a5a")
    c.create_line(0,255,750,255,fill="#5a5a5a")
    for z in functions:
        _i=True
        while _i:
             _i=False
             for z2 in range(len(z)):
                 try:
                     eval(z[z2])
                     if z[z2+1]=="x":                         
                         z=z[:z2+1]+"*"+z[z2+1:]
                         _i=True
                         break
                     if z[z2+1]=="π":
                         z=z[:z2+1]+"*"+z[z2+1:]
                         _i=True
                         break   
                 except:
                     ...
                 if z[z2]=="³":
                     if z2 != len(z)-1:
                         z=z[:z2]+"**3"+z[z2+1:]
                     else:
                         z=z[:z2]+"**3"
                     _i=True
                     break
                 if z[z2]=="²":
                     if z2 != len(z)-1:
                         z=z[:z2]+"**2"+z[z2+1:]
                     else:
                         z=z[:z2]+"**2"
                     _i=True
                     break
                 if z[z2]=="π":
                     z=z[:z2]+"3.1415926"+z[z2+1:]
                     _i=True
                     break
                 if z[z2]=="e":
                     z=z[:z2]+"2.7182818"+z[z2+1:]
                     _i=True
                     break
        print(z)
        lc=locals()
        txt=z.split("\n")[0]
        points=[]
        x=-3750/size
        try:
            while x<=3750/size:
                if x!=0:
                    exec(txt)
                    y=lc['y']
                    if type(y) !=complex:
                        points.append(x/10*size+375)
                        points.append(-y/10*size+255)
                x +=10/size*(101-j)
            exec(txt)
            y=lc['y']
            c.create_line(points,fill="#aaaaff",width=3)
        except:
            ...
    c.create_text(347,15,text="y",fill="#ff1010" ,font="time 20 bold" )
    c.create_text(730,240,text="x",fill="#ff1010" ,font="time 20 bold" )
    for z in range(-5,5):
        c.create_text(z*80+375,245,text=str(bc * z),fill="white")
    for z in range(-4,4):
        c.create_text(365,z*80+255,text=str(bc * -z),fill="white")

def add(event=0):
    global l
    text =str(askstring("新建函数",prompt="请输入你需要的函数",initialvalue="y=x"))
    if text !="None":
        l.insert(END,text)
    update()

def delete(event=0):
    global l,t4
    try:
        l.delete(ACTIVE)
        t4.delete("1.0",END)
    except:
        ...
    update()
    
def enlarge(event=0):
    global size,bc
    size *= 2
    bc /= 2
    update()

def narrow(event=0):
    global size,bc
    size =size/2
    bc *= 2
    update()
    
def show(event):
    global t4,l,gb
    try:
        t4.delete("1.0",END)
        t4.insert(INSERT,l.get(0,END)[l.curselection()[0]])        
        gb=l.curselection()[0]                  
    except:
        ...      
         
def save(event=0):
    global l,t4,gb
    try:
        s=l.curselection()[0]
        l.delete(s)
        t=t4.get("1.0",END)
        t=t.replace("\n","")
        t4.delete("1.0",END)
        t4.insert(INSERT,t)
        l.insert(s,t)
        l.selection_set(gb)
    except:
        ...
    update()

def help_close():
    global help3
    help3.destroy()
    help3=0

def help2(event=0):
    global help3,text
    if help3==0:
        help3=Tk()
        help3.title("帮助")
        frame3=Frame(help3,borderwidth=3)
        frame3.pack()
        frame2=Frame(frame3,borderwidth=3,relief=GROOVE)
        frame2.pack()
        frame=Frame(frame2,borderwidth=3)
        frame.pack()
        for z in range(len(text)):
            if z % 2 ==0:
                t = Label(frame,text=text[z],font=("",11))
            else:
                t = Label(frame,text=text[z],font=("",3))
            t.pack(anchor=W)
        help3.protocol("WM_DELETE_WINDOW",help_close)
        help3.mainloop()

def _2(event=0):
    global t4
    t4.insert(INSERT,"²")

def _3(event=0):
    global t4
    t4.insert(INSERT,"³")                          
        
def pi(event=0):
    global t4
    t4.insert(INSERT,"π")

menu = Menu()
menu1 = Menu(menu)
menu1.add_command(label="放大",command=enlarge,accelerator="Ctrl +")
menu1.add_command(label="缩小",command=narrow,accelerator="Ctrl -")
menu.add_cascade(label="缩显示",menu=menu1)
menu2 = Menu(menu)
menu2.add_command(label="平方 ²",command=_2,accelerator="Ctrl 2")
menu2.add_command(label="立方 ³",command=_3,accelerator="Ctrl 3")
menu2.add_command(label="π",command=pi,accelerator="Ctrl p")
menu.add_cascade(label="插入",menu=menu2)
menu3 = Menu()
menu.add_command(label="新建 Ctrl n",command=add)
menu.add_command(label="帮助 F1",command=help2)
a["menu"]=menu
a.bind_all("<Control-Key-2>",_2)
a.bind_all("<Control-Key-3>",_3)
a.bind_all("<Control-+>",enlarge)
a.bind_all("<Control-Key->",narrow)
a.bind_all("<Control-Key-n>",add)
a.bind_all("<Control-Key-p>",pi)
a.bind_all("<Return>",save)
a.bind_all("<F1>",help2)
f1=Frame(a,width=900,height=60,relief=SUNKEN,borderwidth=2)
f1.pack_propagate(0)
f1.pack()
f2=Frame(f1,width=900,height=35)
f2.pack_propagate(0)
f2.pack(side=TOP,anchor='sw')
f3=Frame(f1,width=900,height=25)
f3.pack_propagate(0)
f3.pack(side=TOP,anchor='sw',expand='yes')
b1=Button(f2,command=enlarge,width=2,height=2,text="+",font=("Times","18"))
b1.pack(side=LEFT)
b2=Button(f2,command=narrow,width=2,height=2,text="-",font=("Times","18"))
b2.pack(side=LEFT)
t1=Text(f3,width=4,height=2)
t1["wrap"]="none"
t1.insert(INSERT,"放大")
t1.config(state=DISABLED)
t1.pack(side=LEFT)
t2=Text(f3,width=5,height=2)
t2["wrap"]="none"
t2.insert(INSERT,"缩小")
t2.config(state=DISABLED)
t2.pack(side=LEFT)
s=Scale(f2,from_=1,to=100,orient=HORIZONTAL,resolution=1,length=800,tickinterval=10,width=20,command=update)
s.set(100)
s.pack(side=LEFT)
t3=Text(f3,width=500,height=2)
t3["wrap"]="none"
t3.insert(INSERT,"精度")
t3.config(state=DISABLED)
t3.pack(side=LEFT)
f4=Frame(a,width=150,height=540,relief=SUNKEN,borderwidth=2)
f4.pack_propagate(0)
f4.pack(side=LEFT)
l=Listbox(f4,height=27)
l.bind("<Double-Button-1>",show)
l.bind("<BackSpace>",delete)
l.pack()
f5=Frame(f4,width=150,height=40,relief=SUNKEN,borderwidth=2)
f5.pack_propagate(0)
f5.pack()
b3=Button(f5,width=5,height=2,text="新建",command=add)
b3.pack(side=LEFT)
b4=Button(f5,width=5,height=2,text="删除",command=delete)
b4.pack(side=LEFT)
b5=Button(f5,width=5,height=2,text="帮助",command=help2)
b5.pack(side=LEFT)
f6=Frame(a,width=750,height=540,relief=SUNKEN,borderwidth=3)
f6.pack_propagate(0)
f6.pack()
f7=Frame(f6,width=750,height=30,relief=SUNKEN,borderwidth=2)
f7.pack_propagate(0)
f7.pack()
f8=Frame(f6,width=750,height=510,relief=SUNKEN,borderwidth=2)
f8.pack_propagate(0)
f8.pack()
t4=Text(f7,width=120,height=2)
t4.pack(side=LEFT)
c=Canvas(f8,width=750,height=510,bg="black")
c.bind("Button-1",save)
c.pack()
update()
a.protocol("WM_DELETE_WINDOW",close)
a.mainloop()

更过例子可见 https://blog.csdn.net/cnds123/article/details/128091966

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学习&实践爱好者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值