2014-09-24 82 views
1

我正在制作一个应用程序,处理平面布局,因此希望有一个图层对话框,允许用户打开/关闭平面图中的不同图层。在C++的FLTK运行时添加/删除小部件

我想有一个弹出式窗口,因此在运行时加载的floorplan中的每个图层都有一个复选框。每个复选框都是一个小部件,我只有在编译时指定/创建的经验。但是,在这里,我不知道我需要多少个复选框,直到特定的平面图被加载。

我向前迈进的问题是如何在FLTK中创建这样的功能(我正在使用的)。我可以想象,当层对话框出现时(每个对象都拥有一个通用的回调函数),在回调的循环中创建复选框小部件,但我不知道如何指示FLTK放置复选框小部件的位置。即我如何在运行时指示FLTK层对话窗口应该是父窗口小部件?或者我可以动态地创建整个窗口,但是我担心确保窗口在隐藏时被销毁(删除)。

N.B.我会想象在窗口关闭(隐藏)时删除窗口小部件。在这一点上,我也不清楚:我是否以通常的新/删除C++方式删除小部件,还是使用Fl :: delete_widget()对话框(http://www.fltk.org/doc-1.3/group__fl__del__widget.html#ga609413ac47ba433d1e7da8678a27164f

OR:有没有更好的方法所有这些方面所有这些问题的所有步骤?

+0

关闭窗口小部件删除:当关闭对话框时,所有窗口小部件都会被销毁。如果您尝试删除小部件并且不告诉对话框,它也会尝试删除并因此导致应用程序崩溃。如果你有数据附加到小部件,只是删除你的数据,让FLTK处理小部件。 – cup 2014-09-26 19:48:06

回答

1

下面是如何根据图层数量进行尺寸调整的一个模糊的例子。要注意的主要问题是,如果使用矢量,则随着矢量增长重新分配矢量,因此保持指针在矢量中显示数据可能会导致屏幕上出现垃圾。

如果您在某个const文件中设置窗口小部件的大小,则可以将其用于调整大小。

#include <FL/Fl.h> 
#include <FL/fl_draw.H> 
#include <FL/Fl_Window.H> 
#include <FL/Fl_Box.H> 
#include <FL/Fl_Button.H> 
#include <FL/Fl_Check_Button.H> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <list> 
#include <vector> 

const int hsep = 10, vsep = 10, btnwid = 100, btnhgt = 20; 

// The canvas layer 
class Canvas : public Fl_Box 
{ 
    Fl_Offscreen& m_buffer; 
public: 
    Canvas(int x, int y, int w, int h, Fl_Offscreen& buffer) 
     : Fl_Box(x, y, w, h) 
     , m_buffer(buffer) 
    { 
    } 

    void Clear() 
    { 
     fl_begin_offscreen(m_buffer); 
     fl_color(FL_WHITE); 
     fl_rectf(0, 0, w(), h()); 
     fl_end_offscreen(); 
    } 
    void draw() 
    { 
     fl_copy_offscreen(x(), y(), w(), h(), m_buffer, 0, 0); 
    } 
}; 

// This structure exists because there is no callback that takes 
// two client parameters. Also, the tag must exist for the life of 
// the dialog. 
class LayerWin; 
class LayerCheck 
{ 
public: 
    int m_layer; 
    std::string m_tag; 
    LayerWin* m_parent; 
}; 

// The layer window 
class LayerWin 
{ 
    int m_layers; 
    Fl_Window* m_dlg; 
    std::string m_title; 
    std::list<LayerCheck> m_tag; 
    Canvas* m_canvas; 
    Fl_Offscreen m_buffer; 
    std::vector<bool> m_layer; 
public: 
    LayerWin(int layers) 
     : m_layers(layers) 
     , m_dlg(0) 
    { 
    } 
    ~LayerWin() 
    { 
     delete m_dlg; 
    } 

    void Create() 
    { 
     int dlgwid = 400, dlghgt = 300; 
     std::ostringstream oss; 

     oss << m_layers << " Layers"; 
     m_title = oss.str(); 
     m_dlg = new Fl_Window(dlgwid, dlghgt, m_title.c_str()); 
     m_dlg->set_modal(); 
     int x = hsep, y = vsep; 
     for (int ll = 0; ll < m_layers; ++ll) 
     { 
      oss.str(""); 
      oss << "Layer " << ll + 1; 
      LayerCheck dummy; 
      m_tag.push_back(dummy); 
      LayerCheck& actual = m_tag.back(); 
      actual.m_tag = oss.str(); 
      actual.m_layer = ll; 
      actual.m_parent = this; 
      Fl_Check_Button* btnCheck = new Fl_Check_Button(x, y, btnwid, btnhgt, actual.m_tag.c_str()); 
      btnCheck->callback(_LayerCB, &actual); 
      m_layer.push_back(false); 
      y += vsep + btnhgt; 
     } 

     x = hsep + btnwid + hsep; 
     y = vsep; 
     int canw = dlgwid - x - 2 * hsep; 
     int canh = dlghgt - 3 * vsep; 
     m_buffer = fl_create_offscreen(canw, canh); 
     m_canvas = new Canvas(x, y, canw, canh, m_buffer); 
     m_canvas->Clear(); 

     Fl_Button* btnClose = new Fl_Button(hsep, dlghgt - vsep - btnhgt, btnwid, btnhgt, "Close"); 
     btnClose->callback(_CloseCB, this); 
     m_dlg->end(); 
     m_dlg->show(); 

     Fl::wait(); 
    } 

    static void _CloseCB(Fl_Widget* w, void* client) 
    { 
     LayerWin* self = (LayerWin*)client; 
     delete self; 
    } 
    static void _LayerCB(Fl_Widget* w, void* client) 
    { 
     Fl_Check_Button* btn = (Fl_Check_Button*)w; 
     LayerCheck* check = (LayerCheck*)client; 
     check->m_parent->LayerCB(check->m_layer, !!btn->value()); 
    } 
    void LayerCB(int layer, bool set) 
    { 
     std::cout << "Layer " << layer+1 << "=" << set << std::endl; 
     m_layer[layer] = set; 

     // Redo the canvas 
     m_canvas->Clear(); 
     fl_begin_offscreen(m_buffer); 
     for (int ll = 0; ll < m_layer.size(); ++ll) 
     { 
      if (m_layer[ll]) 
      { 
       switch (ll) 
       { 
       case 0: 
        fl_color(FL_RED); 
        fl_circle(20, 40, 100); 
        break; 
       case 1: 
        fl_color(FL_DARK_GREEN); 
        fl_rectf(50, 70, 20, 40); 
        break; 
       case 2: 
        fl_color(FL_BLUE); 
        fl_circle(100, 100, 50); 
        break; 
       case 3: 
        fl_color(FL_DARK_MAGENTA); 
        fl_circle(200, 200, 70); 
        break; 
       case 4: 
        fl_color(FL_DARK_CYAN); 
        fl_rectf(100, 200, 60, 90); 
        break; 
       default: 
        std::cout << "Don't know what to do for layer " << ll + 1; 
        break; 
       } 
      } 
     } 
     fl_end_offscreen(); 
     m_canvas->redraw(); 
    } 
}; 

void LayerCB(Fl_Widget* w, long layers) 
{ 
    // Create a modal dialog with layers checkbuttons 
    LayerWin* dlg = new LayerWin(layers); 
    dlg->Create(); 
} 

int main() 
{ 
    // Work out the sizes 
    int scrwid = btnwid + 2 * hsep, scrhgt = 2 * vsep + 3 * (vsep + btnhgt); 

    // Create the main dialog 
    Fl_Window mainwin(scrwid, scrhgt, "Layers"); 
    int x = hsep; 
    int y = vsep; 
    Fl_Button* button = new Fl_Button(x, y, btnwid, btnhgt, "3 layers"); 
    button->callback(LayerCB, 3); 

    y += vsep + btnhgt; 
    button = new Fl_Button(x, y, btnwid, btnhgt, "4 layers"); 
    button->callback(LayerCB, 4); 

    y += vsep + btnhgt; 
    button = new Fl_Button(x, y, btnwid, btnhgt, "5 layers"); 
    button->callback(LayerCB, 5); 
    mainwin.end(); 
    mainwin.show(); 
    return Fl::run(); 
} 
+0

谢谢。我最终做了类似的事情,虽然可能不那么优雅。有趣的是,我确实遇到了你立即指出的确切事物:注意向量在调整大小时会改变的地址。问题出现在为指向任意数量的检查按钮的回调而不是指向按钮本身的指针的数据指针。我最终确定在使用地址之前不再分配它,但是也许迭代器会是更好的方法? – user3353819 2014-09-30 17:35:57

+0

当你需要多于一位的数据时,回调总是有问题。有时候你可以从widget的值()中推断出它。您还可以将数据保存在小部件的user_data成员中。稍微比我创建结构并将其传递给回调的技巧更优雅。 – cup 2014-09-30 19:38:04

+0

只是通过详细的内容试图消除内存泄漏。我不确定,但因为用户可以关闭窗口而不点击btnClose(而不是使用窗口顶部的主关闭按钮),我认为您需要添加 m_dlg-> callback(_CloseCB,this); 否则,用户可以不断创建LayerWin的实例并关闭它,而不会释放内存。 – user3353819 2014-10-01 11:14:55