2014-09-24 83 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