Fltk取消 esc 关闭窗口的回调设置

 
Category: C_C++

写在前面

之前用 FLTK 时候就注意到了 FLTK 生成的界面按一下ESC 就退出了, 虽然不是大问题, 但是还是不算好, 最近搜到了一篇论坛文章, 完美解决了这个问题, 这里其实就是对文章的一个翻译了.

Article #378: Why Does the Escape Key Close My Window? - Fast Light Toolkit (FLTK);

下面以一个简单的例子来说明回调函数的作用.

#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Window.H>

int main(int argc, char *argv[]) {
  Fl_Window *window;
  Fl_Box *box;
  window = new Fl_Window(300, 180);
  window->label("HelloWorld!");
  box = new Fl_Box(20, 40, 260, 100, "Hello World!");
  box->box(FL_UP_BOX);
  box->labelsize(36);
  box->labelfont(FL_BOLD + FL_ITALIC);
  box->labeltype(FL_SHADOW_LABEL);
  window->end();

  window->show(argc, argv);
  return Fl::run();
}

来自官方的 helloworld 例子

2 - FLTK Basics; 下面是 Makefile

  CXX      = $(shell fltk-config --cxx)
  DEBUG    = 
  CXXFLAGS = $(shell fltk-config --cxxflags ) -I.
  LDFLAGS  = $(shell fltk-config --ldflags )
  TARGET = helloworld
  SRCS =  main.cpp
   
  $(TARGET): $(SRCS)
  	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(DEBUG) -o $(TARGET) $<
  
  all: $(TARGET)
  
  clean: $(TARGET) 
  	rm -f $(TARGET) 2> /dev/null

大家可以试一下, 直接按 ESC 会发生什么

方法一: 使用全局事件控制器

这个方法比较容易, 但是会吞掉所有传入主窗口的快捷键, 如果不需要设置快捷键可以用这个, 我这里设置了 lambda 一行解决问题

  // method 1: easy to set, but eat all shortcut keys
  Fl::add_handler([](int event) -> int { return event == FL_SHORTCUT; });

其实这里执行了隐式类型转换, lambda 转换成参数和返回值都是 int 类型的函数指针.

方法二: 使用句柄函数

这个的定制型更强一些, 当然也要多写几行代码了

  // method 2
  window->callback(my_callback);

回调函数只针对当前窗口, 即

[[maybe_unused]] void my_callback(Fl_Widget *, void *) {
  if (Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
    return; // just ignore Escape
}

上面的回调意味着仅忽略 ESC 键的影响, 如果要在 ESC 或者按下关闭按钮两种情况下都弹出关闭确认对话框, 还需要下面的操作:

// #include <FL/Fl_File_Chooser.H> // fl_choice

if (!fl_choice(
          "Are you really absolutely positively certain you want to quit?",
          "yes", "no", 0))
    exit(0);

上面的 fl_choice 的默认值是yes, 通过逻辑非变成 no.