python反射&tkinter

最近学了python反射,要知道在java中,反射是可以做很多有意思的事,把java中那套设计思想拿过来,可以把最近学到的一些细节整合为一个界面程序

效果图:

看起来像一个计算器,gif中操作了两个文件:

test0.py

test1.py

看懂了,就能解释为什么gif中看起来像计算器了,因为这两个文件的main方法中都是对数据进行操作,而gif中的操作实现的是利用反射运行test0.py与test1.py中的main方法。

是不是很简单,只要知道反射谁都可以做出来,而该程序最大的特点是可以读取任何python文件,规范是:

1、所有要被程序加载的python文件必须放在与程序同级目录下的source文件夹中(如下图:reflex.py是程序文件,要被加载的python文件test0.py等均放于source文件夹中)

2、每一个要被程序加载的python文件中都必须拥有main()方法,该main方法的作用相当于__name__=='__main__'语句,将会被程序直接反射调用,如test0.py与test1.py(这个设计可能很糟糕,因为直接写死了只能反射main方法。之所以这么设计,主要是觉得根据单一职责原则来讲,一个python文件也应该只有一种实现(java中带过来的思想,已成强迫症),所以在main方法中直接调用本程序的唯一实现,就会很合理,这样说可能有点懵,举个例子:比如,写一个快速排序与一个冒泡排序,应该将其分别放于两个python文件中,而不是全部写在一个文件中,一个文件中包含多种实现会显得职责混乱,使得代码不易读

当了解了上面的规范后,新增一个python文件:(quick_sort.py  实现快速排序)

第一步:在source文件夹中创建quick_sort.py

第二步:编写排序算法,并添加main方法实现对排序算法的调用

#quick sort
def quick_sort(list,start,end):
	left=start
	right=end
	base=list[(right-left)//2+left]#标准值,大于该值放右边,小于该值放左边
	while left<=right:
		while left<=right and list[right]>base:#找到右边有小于标准值时停止循环
			right-=1
		while left<=right and list[left]<base:#找到左边有大于标准值时停止循环
			left+=1
		if left<=right:#交换
			temp=list[right]
			list[right]=list[left]
			list[left]=temp
			left+=1
			right-=1
	if left>start:#递归排序标准值左边的数组
		quick_sort(list,start,right)
	if right<end:#递归排序标准值右边的数组
		quick_sort(list,left,end)
	return list
def main(list):
	list=list[1:-1].split(',')#由于界面传入的值为str类型,需要转list
	print(quick_sort(list,0,len(list)-1))

第三步:在反射程序中调用该算法

如gif所示,该反射程序完全可以调用刚写的排序程序。


写得好无聊,接下来看看源码,这个就不想一步一步的说了,大多数都是有注释的,直接贴吧(这个源码没有任何需要格外下载的第三方库,直接贴到自己电脑上就能运行,但记得一定要创建一个source文件夹(原因上面有说)):

import os
import tkinter as tk
import tkinter.messagebox
from tkinter import ttk
from tkinter.filedialog import askdirectory

class Main_Win:
	#1、创建窗口
	def __init__(self,master):
		self.win_root=master
		self.canvas=None#画布
		self.dir_path="%s\\source"%os.getcwd()#默认文件夹路径,当前目录下的source文件夹
		self.file_name=tk.StringVar()#文件名
		self.attr_value_list=[]#方法的参数集(列表),如f(a,b,c)参数集为[a,b,c]
		self.source_text=None#源码显示框
	#2、初始化窗口布局
	def init_win(self):
		#设置窗口标题
		self.win_root.title('反射 '+self.dir_path)
		#设置窗口大小并居中显示
		w=400
		h=338
		center_window(self.win_root,w,h)
		#创建画布设置窗口的大小宽x高+偏移量
		bg_color='beige'
		self.canvas=tk.Canvas(self.win_root,width=w,height=h-18,bd=0,bg=bg_color,highlightthickness=0)
		self.canvas.pack()
		#防止用户调整尺寸
		self.win_root.resizable(0,0)
		
		#############添加组件#############
		
		#文件名列表选择框
		file_name_list_combobox=ttk.Combobox(self.win_root,textvariable=self.file_name)
		self.combobox_set_values(file_name_list_combobox,self.get_file_name_list(),0,self.get_file_name)
		#修改目录路径按钮
		select_dir_button = tk.Button(self.win_root, text ="修改目录",font=('Arial', 12), command =lambda:self.select_dir(file_name_list_combobox))
		#源码显示框以及滚动条
		scroll = tk.Scrollbar(self.win_root, orient = 'horizontal')
		scroll.pack(side = 'bottom', fill = 'x')
		self.source_text = tk.Text(self.win_root,font=('Arial', 8),bg=bg_color,xscrollcommand = scroll.set, wrap = 'none')
		scroll.config(command = self.source_text.xview)
		#反射执行main函数按钮
		run_button=tk.Button(self.win_root,text='运行',font=('Arial',12),command =lambda:self.run_function())
		
		#############添加组件到画布中#############
		
		self.canvas.create_window(w-60,30,width=100,height=30,window=select_dir_button)
		self.canvas.create_window(103,70,width=200,height=30,window=file_name_list_combobox)
		self.canvas.create_window(w//2,203,width=w,height=236,window=self.source_text)
		self.canvas.create_window(w-60,70,width=50,height=30,window=run_button)
		
		#############进行消息循环#############
		self.win_root.mainloop()
		
	#3、回调函数
	
	def combobox_set_values(self,combobox,list,default_selected,callback):
		combobox["values"]=tuple(list)
		combobox.current(int(default_selected))  #默认选择
		combobox.bind("<<ComboboxSelected>>",callback)  #绑定事件
	def get_file_name_list(self):
		files=['选择文件',]
		if self.dir_path:
			files=files+os.listdir(self.dir_path)
		return files
	def get_file_name(self,event):
		file_name=self.file_name.get()
		self.source_text.delete('1.0','end')
		if '.py' in file_name:
			file_path=self.dir_path+'\\%s'%file_name
			file=open(file_path,mode='r+',encoding='utf-8')
			for text in file:
				self.source_text.insert('end',text)
	def select_dir(self,combobox):
		self.dir_path = askdirectory(initialdir =self.dir_path)
		self.win_root.title('python测试工具 '+self.dir_path)
		self.combobox_set_values(combobox,self.get_file_name_list(),0,self.get_file_name)
	def run_function(self):
		file_name=self.file_name.get()
		if '.py' in file_name:
			file_name=file_name[0:-3]
			try:
				model=__import__(r'source.'+file_name,fromlist=True)#反射添加模块
				f=getattr(model,'main',None)#反射获得方法
				if f:
					parameter_count = f.__code__.co_argcount#获得参数个数
					if parameter_count:
						list=[]
						parameter_namelist=f.__code__.co_varnames#反射获得所有变量的名字
						for i in range(parameter_count):
							list.append(parameter_namelist[i])
						self.set_attr_values(list,f)
					else:
						f()
				else:
					self.error_print('main()不存在')
			except:
				self.error_print(file_name+'加载失败!\n\n请确保模块在程序同级目录下的\nsource文件夹中')
	def set_attr_values(self,list,f):
		self.attr_value_list=list
		win_up = tk.Toplevel(self.win_root)
		win_up.title('请输入参数:')
		i=0
		for i in range(len(list)):
			tk.Label(win_up, text=str(list[i])).place(x=10, y=10+40*i)
			self.attr_value_list[i]=tk.StringVar()# 将输入的值给变量
			entry_attr = tk.Entry(win_up,textvariable=self.attr_value_list[i])#输入框
			entry_attr.place(x=130, y=10+40*i)
		btn_comfirm = tk.Button(win_up, width=10,font=('Arial',12),text='提交', command=lambda:self.submit_deal(f,win_up))
		btn_comfirm.place(x=150, y=10+40*(i+1))
		center_window(win_up,300,45+40*(i+1))
	def submit_deal(self,f,destroy_win):
		for i in range(len(self.attr_value_list)):
			attr_value=self.attr_value_list[i].get()#获取输入参数
			if attr_value=='':#如果输入值为空,关闭窗口,退出本方法
				destroy_win.destroy()
				return
			self.attr_value_list[i]=attr_value
		f(*self.attr_value_list)
		destroy_win.destroy()
	def error_print(self,err_text):
		tkinter.messagebox.showinfo(title='提示', message=str(err_text))
		
#屏幕居中
def center_window(win,w, h):
		#获取屏幕宽、高
		ws = win.winfo_screenwidth()
		hs = win.winfo_screenheight()
		#计算x、y位置
		x = (ws/2) - (w/2)
		y = (hs/2) - (h/2)
		win.geometry('%dx%d+%d+%d' % (w, h, x, y))
def main():
	root=tk.Tk()
	win=Main_Win(root)
	win.init_win()
if __name__=='__main__':
	main()
		

:要问自己做这个东西有什么意义,没意义,只是针对这几天对python反射以及tkinter模块的学习进行的一个总结,而写这个软件时最吸引我的地方就是“设计”,它实现了类似于一个框架的功能,以后不管是写哪方面的实现代码,只要遵循了上面的两条规范,就可以在这个软件中实现对其代码的调用。。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的Tkinter是一个内置的图形用户界面库,非常适合用于创建简单的计算器应用程序。以下是一个基本的步骤来使用Tkinter创建一个简单的四则运算计算器: 1. 导入必要的库: ```python import tkinter as tk from tkinter import messagebox ``` 2. 定义函数来处理用户的输入和计算: ```python def calculate(event): try: num1 = float(entry1.get()) num2 = float(entry2.get()) operator = operator_var.get() if operator == '+': result = num1 + num2 elif operator == '-': result = num1 - num2 elif operator == '*': result = num1 * num2 elif operator == '/': result = num1 / num2 else: messagebox.showerror('Error', 'Invalid operator') return entry3.delete(0, tk.END) entry3.insert(tk.END, str(result)) except ValueError: messagebox.showerror('Error', 'Please enter a valid number') # 更多变量定义和事件绑定... ``` 3. 创建主窗口和布局: ```python root = tk.Tk() root.title("Simple Calculator") operator_var = tk.StringVar() # 用于保存运算符的选择 # 创建输入框和按钮 entry1 = tk.Entry(root) entry2 = tk.Entry(root) entry3 = tk.Entry(root, state='disabled') # 初始结果框 button1 = tk.Button(root, text='+', command=lambda: operator_var.set('+')) button2 = tk.Button(root, text='-', command=lambda: operator_var.set('-')) # ...添加更多数字、运算符和等于按钮 # 将输入框和按钮放在合适的布局中 # ... # 绑定键盘回车事件到calculate函数 entry1.bind('<Return>', calculate) entry2.bind('<Return>', calculate) ``` 4. 运行主循环: ```python root.mainloop() ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值