Re: TreeView::append_column_numeric() format?



 > pks timing com writes:
 > 
 > I'll try to cook up implementation this weekend.

I cooked it up. It should demonstrate why I (and if I
may speak for Carl, we) were quick to suggest a generic
implementation.  It

*) formats numbers via printf() using both a manually
   instantiated functor, and using created by a convenience
   function

*) it reverses strings, and translates and enum to show
   just how extensible it is ...

*) it shows that the "difficult, templated" part goes
   into the library, not a string converter the end user
   might write - we could easily explain the mysterious
   F template parameter (see the example)

Please don't get caught up in the details of this implementation.
(I point out in comments what the library likely should not do)

It is simply one implementation that supports "the convenience
formatting" routine (one that accepts a functor) that came to my
mind when you first started the thread.  If you hadn't mentioned
TreeViewColumn::set_cell_data_func() then,  my first stab at
such an implementation would likely not have used it  (I've never
used it in the past).

A printf() based convenience function that hides even the functor
is easily implemented once this "framework", as it has been
referred in previous messages, is in place - the example does
implement it after all.

This type of interface would help minimize end users' template
specialization inside the Gtk namespace.  And the (probably
negligible) overhead of additional properties which are
linked back to the text property. I've run into another thread
about EPICUI::numeric (if I remember correctly).

I don't know what else to contribute to the discussion.
It has been interesting!  Thanks to you both again!

Patrick


#include <gtkmm/main.h>
#include <gtkmm/window.h>
#include <gtkmm/treemodel.h>
#include <gtkmm/liststore.h>
#include <gtkmm/treeview.h>
#include <iostream>

//------------------------------------------------------------------
// quick and ___dirty___ printf() based functor
// derives nothing, and templated because all kinds of
// things can be passed to printf()
template<typename T>
struct Printf
{
    Printf(const char * const fmt) : m_Fmt(fmt) {}

    Glib::ustring operator()(const T &src)
    {
        char buf[2048];
        snprintf(buf, 2048, m_Fmt, src);
        return buf;
    }

    const char * const m_Fmt;
};    

//------------------------------------------------------------------
// string reverser example from the previous posts ... a more
// likely functor would convert to upper case or something ...
// derives nothing, not templated
struct StringReverse
{
    Glib::ustring operator()(const Glib::ustring &src)
    {
        Glib::ustring result = "";
        for (int i = src.size() - 1; i >= 0; i--)
            result += src[i];
        return result;
    }
};

//------------------------------------------------------------------
// a contrived enumerated type and a string conversion functor to
// reiterate the extensibility to most all types ...
// derives nothing, not templated

typedef enum { great, good, bad } Contrived;

struct ContrivedString
{
    ContrivedString(bool german = false) : m_German(german) {}

    Glib::ustring operator()(const Contrived &src)
    {
        switch (src)
        {
        case great: return m_German ? "Spitze !!!" : "Excellent !!!";
        case good:  return m_German ? "Gut Genug"  : "Good Enough";
        case bad:   return m_German ? "Schlecht!"  : "Horrible!";
        }

        return "Unknown Contrived Enumeration";
    }

    bool m_German;
};

//------------------------------------------------------------------
// I do not mean to recommend a derived tree view column.  Deriving
// was just an easy way to associate the model column and cell
// renderer with the view column, to get the point across with a
// concise, but concrete example.
//
// the important association clearly is that of the model column
// and cell renderer ... more of the "example code excuse"

template <typename T, typename F>
class FunctorColumn : public Gtk::TreeViewColumn
{
public:

    FunctorColumn(const Glib::ustring &title,
                  Gtk::TreeModelColumn<T> &col,
                  const F &functor)
        : Gtk::TreeViewColumn(title),
          m_ColRef(col),
          m_Functor(functor)
    {
        pack_start(m_Renderer);

        // functor performs property_text() conversion in callback
        set_cell_data_func(
            m_Renderer,
            SigC::slot(*this, &FunctorColumn::CellDataFunc));
    }

private:

    Gtk::CellRendererText m_Renderer;
    Gtk::TreeModelColumn<T> &m_ColRef;
    F m_Functor;

    void CellDataFunc(Gtk::CellRenderer *r, const Gtk::TreeModel::iterator &i)
    {
        // set text to what the functor returns for column
        m_Renderer.property_text() = m_Functor((*i)[m_ColRef]);
    }
};

//------------------------------------------------------------------
// again, no intent to recommend a tree view subclass ...
// append_functor_column<> would go into Gtk::TreeView

class FunctorView : public Gtk::TreeView
{
public:

    FunctorView() : Gtk::TreeView() {};

    // function that appends columns with string conversion
    // functors for any all types ... could well be private
    // if you don't want to allow "yet another way to format"
    template<typename T, typename F>
    int append_functor_column(const Glib::ustring &title,
                              Gtk::TreeModelColumn<T> &col,
                              const F &f)
    {
        // this column is likely leaked! (more example code)
        FunctorColumn<T, F> *vc;
        vc = new FunctorColumn<T, F>(title, col, f);
        return append_column(*vc);
    }

    // the convenience function which started the whole
    // thread ... implemented in the "yet another way"
    // by means of the printf functor ...
    template<typename T>
    int append_column_numeric(const Glib::ustring &title,
                              Gtk::TreeModelColumn<T> &col,
                              const char * const fmt)
    {
        Printf<T> functor(fmt);
        return append_functor_column(title, col, functor);
    }
};

//------------------------------------------------------------------
// sample application that puts it all together

class DemoWin : public Gtk::Window
{
public:

    DemoWin();

    // used with printf fmt string convienience function
    Gtk::TreeModelColumn<double> m_cDouble;

    // demonstrates flexibility this could offer
    Gtk::TreeModelColumn<Glib::ustring> m_cString;
    Gtk::TreeModelColumn<float> m_cFloat;
    Gtk::TreeModelColumn<Contrived> m_cContrived;

    // standard tree view code ...
    Gtk::TreeModel::ColumnRecord m_Columns;
    Glib::RefPtr<Gtk::ListStore> m_Store;
    FunctorView m_TView;
};

DemoWin::DemoWin()
    : Gtk::Window()
{
    // initialize model and store as usual (thanks for pointing
    // out that column record need not be derived!)
    m_Columns.add(m_cDouble);
    m_Columns.add(m_cFloat);
    m_Columns.add(m_cString);
    m_Columns.add(m_cContrived);
    m_Store = Gtk::ListStore::create(m_Columns);
    
    // add some data to model
    Gtk::TreeModel::Row row;

    row = *(m_Store->append());
    row[m_cDouble] = 1234.5678;
    row[m_cFloat] = 3.33;
    row[m_cString] = "displayed normally";
    row[m_cContrived] = great;

    row = *(m_Store->append());
    row[m_cDouble] = 8765.4321;
    row[m_cFloat] = 4.44;
    row[m_cString] = "and backwards";
    row[m_cContrived] = good;

    m_TView.set_model(m_Store);

    // the convenience column
    m_TView.append_column_numeric("Convenience Formatted", m_cDouble, "%.2f");

    // type flexibility demo columns
    m_TView.append_functor_column("Float", m_cFloat, Printf<float>("%.4f"));
    m_TView.append_functor_column("Contrived Enum", m_cContrived, ContrivedString());
    m_TView.append_functor_column("Auf Deutsch", m_cContrived, ContrivedString(true));
    m_TView.append_column("String", m_cString);
    m_TView.append_functor_column("Reversed", m_cString, StringReverse());

    add(m_TView);
    show_all_children();
}

int
main(int argc, char *argv[])
{
    Gtk::Main kit(argc, argv);

    DemoWin win;
    win.set_title("TreeView String Functors");
    kit.run(win);

    return 0;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]