1+ import ui
2+ import re
3+
4+ # 只允许安全的计算表达式
5+ _allowed_pattern = re .compile (r'^[0-9+\-*/().\s]+$' )
6+
7+ def safe_eval (expr : str ):
8+ expr = expr .strip ()
9+ if not expr :
10+ return ''
11+ if not _allowed_pattern .match (expr ):
12+ return 'Error'
13+ try :
14+ result = eval (expr , {"__builtins__" : None }, {})
15+ if isinstance (result , float ):
16+ return str (int (result )) if result .is_integer () else str (result )
17+ return str (result )
18+ except Exception :
19+ return 'Error'
20+
21+
22+ class SimpleCalculator (ui .View ):
23+ def __init__ (self , * args , ** kwargs ):
24+ # 模拟“正常用户”:给一个典型根尺寸 320x480
25+ super ().__init__ (frame = (0 , 0 , 320 , 480 ), * args , ** kwargs )
26+
27+ self .background_color = 'white'
28+ self .name = '计算器(测试UI居中)'
29+ self .expr = '0'
30+
31+ # 顶部显示区域 —— 占一点高度,不压得太高,也不太低
32+ self .display = ui .Label ()
33+ self .display .frame = (16 , 40 , self .width - 32 , 60 )
34+ self .display .alignment = ui .ALIGN_RIGHT
35+ self .display .font = ('<System>' , 32 )
36+ self .display .text = '0'
37+ self .display .text_color = 'black'
38+ self .display .background_color = None
39+ self .add_subview (self .display )
40+
41+ # 按钮布局:整体放在中部偏下,但不是挤到最下面
42+ buttons = [
43+ ['C' , '+/-' , '%' , '/' ],
44+ ['7' , '8' , '9' , '*' ],
45+ ['4' , '5' , '6' , '-' ],
46+ ['1' , '2' , '3' , '+' ],
47+ ['0' , '' , '.' , '=' ],
48+ ]
49+
50+ margin = 10
51+ btn_w = (self .width - margin * 5 ) / 4.0
52+ btn_h = 60
53+ # 比你之前的 140 再往上提一点,整体更居中
54+ start_y = 120
55+
56+ for row_index , row in enumerate (buttons ):
57+ for col_index , title in enumerate (row ):
58+ if title == '' :
59+ continue
60+
61+ x = margin + col_index * (btn_w + margin )
62+ y = start_y + row_index * (btn_h + margin )
63+
64+ # 0 键双倍宽度
65+ if title == '0' and row_index == 4 and col_index == 0 :
66+ width = btn_w * 2 + margin
67+ else :
68+ width = btn_w
69+
70+ btn = ui .Button (title = title )
71+ btn .frame = (x , y , width , btn_h )
72+ btn .font = ('<System>' , 24 )
73+ btn .corner_radius = 12
74+
75+ if title in ['C' , '+/-' , '%' ]:
76+ btn .background_color = '#a5a5a5'
77+ btn .tint_color = 'black'
78+ elif title in ['/' , '*' , '-' , '+' , '=' ]:
79+ btn .background_color = '#ff9f0a'
80+ btn .tint_color = 'white'
81+ else :
82+ btn .background_color = '#333333'
83+ btn .tint_color = 'white'
84+
85+ btn .action = self .button_tapped
86+ self .add_subview (btn )
87+
88+ # 更新显示
89+ def update_display (self ):
90+ self .display .text = self .expr
91+
92+ # 按钮事件
93+ def button_tapped (self , sender ):
94+ text = sender .title
95+
96+ if text == 'C' :
97+ self .expr = '0'
98+ self .update_display ()
99+ return
100+
101+ if text == '+/-' :
102+ if self .expr .startswith ('-' ):
103+ self .expr = self .expr [1 :]
104+ else :
105+ if self .expr != '0' :
106+ self .expr = '-' + self .expr
107+ self .update_display ()
108+ return
109+
110+ if text == '%' :
111+ val = safe_eval (self .expr )
112+ if val not in ('Error' , '' ):
113+ try :
114+ num = float (val ) / 100.0
115+ self .expr = str (int (num )) if num .is_integer () else str (num )
116+ except Exception :
117+ self .expr = 'Error'
118+ else :
119+ self .expr = 'Error'
120+ self .update_display ()
121+ return
122+
123+ if text == '=' :
124+ result = safe_eval (self .expr )
125+ self .expr = result if result != '' else '0'
126+ self .update_display ()
127+ return
128+
129+ # 普通数字/符号输入
130+ if self .expr == '0' and text in '0123456789' :
131+ self .expr = text
132+ else :
133+ self .expr += text
134+
135+ self .update_display ()
136+
137+
138+ def main ():
139+ v = SimpleCalculator ()
140+ v .present ('sheet' )
141+
142+
143+ if __name__ == '__main__' :
144+ main ()
0 commit comments