# main2.vp — ViperFLProject fltk GUI 测试(回调 + 控件展示) # # 构建需 TPV/TPC 支持 project.vpj linker.static_libs 静态链接 # (本工程已配置链接 ../includes/fltk/cfltk/build 下的 cfltk2 + FLTK 静态库)。 # # 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(TPV 自动把函数名 # bitcast 为函数指针)。回调签名统一为 def cb(w: bytes, data: bytes), # 其中 w 是触发回调的控件指针,data 是注册时传入的用户数据。 import t, c import stdlib import viperlib import fltk # 模块级全局:供回调访问 main() 中创建的控件指针(回调是 C 层直接调用, # 拿不到 main 的局部变量);空指针用 None(C null),不能用整数 0。 term_ptr: t.CPtr = None status_ptr: t.CPtr = None scheme_idx: int = 0 theme_idx: int = 0 def on_btn_click(w: bytes, data: bytes): """按钮点击回调:改按钮文字 + 状态栏显示""" fltk.Fl_Widget_set_label(w, "Clicked!") fltk.Fl_Widget_redraw(w) fltk.Fl_Output_set_value(status_ptr, "Button clicked") def on_check(w: bytes, data: bytes): """复选框回调:状态栏显示勾选状态""" v: int = fltk.Fl_Check_Button_is_checked(w) if v != 0: fltk.Fl_Output_set_value(status_ptr, "Checked") else: fltk.Fl_Output_set_value(status_ptr, "Unchecked") def on_slider(w: bytes, data: bytes): """滑动条回调:状态栏实时显示数值""" v: t.CDouble = fltk.Fl_Slider_value(w) buf: bytes = stdlib.malloc(32) if buf is not None: viperlib.snprintf(buf, 32, "Slider = %.2f", v) fltk.Fl_Output_set_value(status_ptr, buf) stdlib.free(buf) def on_go(w: bytes, data: bytes): """按钮回调:读取输入框文本 → 终端打印""" txt: str = fltk.Fl_Input_value(data) fltk.Fl_Terminal_append(term_ptr, "input: ") fltk.Fl_Terminal_append(term_ptr, txt) fltk.Fl_Terminal_append(term_ptr, "\n") def on_menu_open(w: bytes, data: bytes): fltk.Fl_Output_set_value(status_ptr, "Menu: File/Open") def on_menu_about(w: bytes, data: bytes): fltk.Fl_Output_set_value(status_ptr, "Menu: Help/About") def on_style(w: bytes, data: bytes): """风格切换回调:base→plastic→gtk+→gleam→oxy 循环""" global scheme_idx scheme_idx = scheme_idx + 1 if scheme_idx == 1: fltk.Fl.set_scheme("plastic") elif scheme_idx == 2: fltk.Fl.set_scheme("gtk+") elif scheme_idx == 3: fltk.Fl.set_scheme("gleam") elif scheme_idx == 4: fltk.Fl.set_scheme("oxy") else: fltk.Fl.set_scheme("base") scheme_idx = 0 fltk.Fl_Output_set_value(status_ptr, f"Scheme: {fltk.Fl.scheme_string()}") def on_theme(w: bytes, data: bytes): """Fl_Theme 主题切换:base→Dark→Metro 循环""" global theme_idx theme_idx = theme_idx + 1 if theme_idx == 1: fltk.Fl.set_theme_dark() elif theme_idx == 2: fltk.Fl.set_theme_metro() else: fltk.Fl.set_scheme("base") fltk.Fl.reload_scheme() theme_idx = 0 fltk.Fl_Output_set_value(status_ptr, f"Theme: {theme_idx}") def on_tick(w: bytes, data: bytes): """定时器回调:每秒终端打印一次并续订""" fltk.Fl_Terminal_append(term_ptr, "tick\n") fltk.Fl.add_timeout(1.0, on_tick, 0) def main() -> int: global term_ptr, status_ptr fltk.Fl_init_all() win = fltk.Fl_Window(600, 460, "Viper FLTK Demo") menubar = fltk.Fl_Menu_Bar(0, 0, 600, 25) status = fltk.Fl_Output(10, 30, 580, 25) btn = fltk.Fl_Button(10, 70, 120, 30, "Click Me") check = fltk.Fl_Check_Button(150, 70, 100, 30, "Enable") slider = fltk.Fl_Slider(280, 70, 200, 30) input_ = fltk.Fl_Input(10, 110, 210, 30, "Type here") go = fltk.Fl_Button(230, 110, 55, 30, "Go") style = fltk.Fl_Button(295, 110, 55, 30, "Style") theme = fltk.Fl_Button(360, 110, 55, 30, "Theme") spinner = fltk.Fl_Spinner(425, 110, 100, 30) browser = fltk.Fl_Browser(10, 150, 280, 140) tree = fltk.Fl_Tree(300, 150, 280, 140) term = fltk.Fl_Terminal(10, 300, 570, 120, "Terminal") win.end() # 保存全局指针(回调用) term_ptr = t.CPtr(term._ptr) status_ptr = t.CPtr(status._ptr) # 菜单(回调 + 快捷键 Ctrl+O:0x4000 | 'o'(111)) menubar.add("File/Open", 0x4000 | 111, 0, on_menu_open) menubar.add("Help/About", 0, 0, on_menu_about) # 回调注册 btn.set_callback(on_btn_click, 0) check.set_callback(on_check, 0) slider.set_callback(on_slider, 0) go.set_callback(on_go, input_._ptr) style.set_callback(on_style, 0) theme.set_callback(on_theme, 0) # 数值微调框 spinner.set_minimum(0.0) spinner.set_maximum(100.0) spinner.set_step(1.0) spinner.set_value(42.0) # 列表 + 树 browser.add("Item 1") browser.add("Item 2") browser.add("Item 3") tree.add("Root/Child A/Leaf 1") tree.add("Root/Child B") # 定时器 fltk.Fl.add_timeout(1.0, on_tick, 0) win.show() fltk.Fl.run() return 0