需求计算竞对花费复制最新记录等式比如点击一次2元30天访客200则每日推广花费为200*2/3013.33Python代码import asyncio import re import flet as ft class Calculator: # 接收 Flet 的页面对象负责初始化页面标题和成员变量 优先执行 # init 是英文 initialization初始化 的缩写。 # 前后的双下划线 __俗称“魔术方法”或“dunder方法”是 Python 的约定表示这是系统内置的特殊方法。 # Python 看到这个写法就知道它不能像普通函数那样随便调用而是要在特定时机自动触发 def __init__(self, page: ft.Page): # self代表对象自身的引用 # 带 self. 的是对象属性永久附着在对象上 self.page page self.page.title 高级计算器 self.answer self.full_result self.create_widgets() def create_widgets(self): 构建界面控件 # 文本输入框 self.input_field ft.TextField( label输入算式, hint_text例如: (5030)*2/2, on_submitself.calculate, prefix_iconft.Icons.FUNCTIONS, ) border_side ft.BorderSide(1, ft.Colors.OUTLINE_VARIANT) # 容器 self.result_display ft.Container( # ft.Text 默认是不可选中的 selectableTrue 可选中 contentft.Text(value, size24, weightft.FontWeight.BOLD, selectableTrue), border_radius12, # 边框 borderft.Border(border_side, border_side, border_side, border_side), padding15 ) # 轮廓按钮Outlined Button控件 clear_btn ft.OutlinedButton(清空, iconft.Icons.CLEAR, on_clickself.clear_input) # 填充按钮 calc_btn ft.FilledTonalButton(计算结果, iconft.Icons.CALCULATE, on_clickself.calculate) # 列 self.history_list ft.Column( spacing4, scrollft.ScrollMode.ALWAYS ) self.page.add( ft.Column([ ft.Row( [ ft.Icon(ft.Icons.CALCULATE, size28, colorft.Colors.PRIMARY), ft.Text(计算竞对花费, size20, weightft.FontWeight.BOLD), ], spacing8, vertical_alignmentft.CrossAxisAlignment.CENTER), ft.Text(计算结果自动复制到剪贴板, size12, colorft.Colors.OUTLINE), ft.Divider(height8, colorft.Colors.TRANSPARENT), self.input_field, ft.Divider(height8, colorft.Colors.TRANSPARENT), # ft.Row([calc_btn], alignmentft.MainAxisAlignment.CENTER), ft.Row( [calc_btn, clear_btn], alignmentft.MainAxisAlignment.SPACE_BETWEEN, vertical_alignmentft.CrossAxisAlignment.CENTER ), ft.Divider(height8, colorft.Colors.TRANSPARENT), ft.Text(计算结果:, size12, weightft.FontWeight.W_600), ft.Divider(height3, colorft.Colors.TRANSPARENT), self.result_display, ft.Divider(height8, colorft.Colors.TRANSPARENT), ft.Row( [ ft.Text(历史记录:, size12, weightft.FontWeight.W_600), ft.TextButton(复制最新记录, iconft.Icons.COPY, on_clickself.copy_history), ], alignmentft.MainAxisAlignment.SPACE_BETWEEN, ), ft.Container( contentself.history_list, borderft.Border(border_side, border_side, border_side, border_side), border_radius8, padding8, expandTrue ) ], spacing0, expandTrue, horizontal_alignmentft.CrossAxisAlignment.STRETCH) ) def _snack(self, text): # 创建一个 SnackBar消息条控件。它通常出现在屏幕底部移动端或左下角桌面端几秒后自动消失不会打断用户当前的操作 # 这个 SnackBar 一旦被添加到页面上立刻自动弹出来不用我再手动去点‘打开’按钮 s ft.SnackBar(ft.Text(text), openTrue) self.page.overlay.append(s) self.page.update() # 清空 def clear_input(self, eNone): self.input_field.value # 在清空输入框后把键盘光标焦点重新放回输入框里让用户不用点鼠标直接就能敲键盘输入新内容 asyncio.get_running_loop().create_task(self.input_field.focus()) self.page.update() async def calculate(self, eNone): 处理用户输入的算式并计算结果 # 去空格 expr self.input_field.value.strip() if not expr: self._snack(请输入计算公式) return try: # 安全检查只允许数字和基本运算符 # 0-9 → 数字 # → 加号 # \- → 减号特别注意减号在方括号里有特殊含义用来表示范围如 a-z所以必须用反斜杠转义成 \- 才能表示“减号”本身 # * → 乘号 # / → 除号 # % → 百分号 # () → 左右 括号 # . → 小数点在方括号里不需要转义就表示点本身 # \s → 空格空白字符 # r...原始字符串 if re.search(r[^0-9\-*/%().\s], expr): raise ValueError(输入包含非法字符) # 算出一个数学结果 result eval(expr) # 检查 eval 算出来的结果是不是浮点数小数 if isinstance(result, float): # 四舍五入 将浮点数保留两位小数 result round(result, 2) # 检查四舍五入后的数字是不是一个整数比如 2.0、3.00如果是就把它强制转成 int整数类型去掉小数点 if result.is_integer(): result int(result) # 转字符串 self.answer str(result) # f...f-string格式化字符串 # {expr.strip()} # 去掉 expr 字符串首尾的空白字符空格、换行等 self.full_result f{expr.strip()}{result} # 赋值 self.result_display.content.value self.answer # 异步调用 _copy_result 方法并将计算出的结果复制到系统剪贴板 await self._copy_result() # 追加到历史记录 self.history_list.controls.append(ft.Text(self.full_result, size13, selectableTrue)) # 更新页面 self.page.update() except ZeroDivisionError: self._snack(除数不能为零) except SyntaxError: self._snack(语法错误请检查输入) # 传入了无效的值值错误 except ValueError as ve: self._snack(str(ve)) # “万能兜底捕获”语句 没想到的错误 except Exception as ex: self._snack(f计算错误: {ex}) # 复制 async def _copy_result(self): 将计算结果复制到剪贴板 if self.answer: # ft.Clipboard() 是 Flet 框架提供的剪贴板操作客户端系统粘贴板接口 await ft.Clipboard().set(self.answer) self._snack(答案已复制) # 异步函数 async def copy_history(self, eNone): 将历史记录全部复制到剪贴板 # 生成一个列表赋值给变量 lines。这个列表里装的都是字符串历史记录的文本 # 遍历 self.history_list 这个容器里的所有子控件 # ft.Text 管“显示啥” # 查看控件列表是否为空 if not self.history_list: self._snack(没有历史记录) # 列表转字符串 return else: last_history self.history_list.controls[-1] if isinstance(last_history, ft.Text): await ft.Clipboard().set(last_history.value) self._snack(已复制最新记录) async def main(page: ft.Page): # 窗口大小 page.window.width 450 page.window.min_width 400 page.window.height 500 page.window.min_height 460 page.theme ft.Theme( color_schemeft.ColorScheme( primaryft.Colors.GREEN_700 ) ) Calculator(page) await page.window.center() page.window.visible True page.update() if __name__ __main__: ft.run(main, viewft.AppView.FLET_APP_HIDDEN)运行界面