how to add text box in gtkmm:gtk::Listbox using c++

情到浓时终转凉″ 提交于 2020-01-16 01:05:12

问题


I want to add this type of text in Listbox using Gtkmm in c++.

Can you suggest me any way how to do it, please?


回答1:


For this very simple case, you might want to use gtkmm's ListViewText widget: https://developer.gnome.org/gtkmm/stable/classGtk_1_1ListViewText.html

Here is some example code: https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/treeview/listviewtext/examplewindow.cc

However, if you want to do anything more complex, you'd need to use the full Gtk::TreeView class.

I don't think Gtk::ListBox is appropriate for offering a simple list of values like that. In fact, you might want to use Gtk::ComboBox - maybe even the simple Gtk::ComboBoxText widget: https://developer.gnome.org/gtkmm/stable/classGtk_1_1ComboBoxText.html

Here is some Gtk::ComboBoxText example code: https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/combobox/text/examplewindow.cc




回答2:


Here's an Example that I created to make the ListBox as described above.

//=======================================================
// GTKMM3/C++11 ListBox Example / W.Moore
//=======================================================
#include <gtkmm.h>
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>

using namespace std;

//======================================================
// My List Row
//======================================================
class MyListRow : public Gtk::ListBoxRow
{
public:
    MyListRow(const string text)
      : label{text}
    {
       add(label);
       set_halign(Gtk::Align::ALIGN_START);
       label.set_size_request(150); 
       show_all_children();
    }
protected:
    Gtk::Label label;
};

//======================================================
// My List Box
//======================================================
class MyListBox : public Gtk::ListBox
{
public:
    MyListBox();
    MyListBox(initializer_list<string> list);
    void api_AddRow(string line);
    void api_Clear();
};

inline MyListBox::MyListBox()
{
}

inline MyListBox::MyListBox(initializer_list<string> list) {
  for (auto s : list) {
    api_AddRow(s);
  }
}

inline void MyListBox::api_AddRow(string text)
{
    auto row = Gtk::manage(new MyListRow{text});
    append(*row);
    row->show();
}

inline void MyListBox::api_Clear() {
    vector<Gtk::Widget* w> children = get_children();
    foreach (widget* w : children) {
        remove(*w);
        delete w;
    }
}

//======================================================
// My Window
//======================================================
class MyWindow : public Gtk::Window {
  public:
    MyWindow();

  protected:
    MyListBox listbox1 {
        "List Item 1",
        "List Item 2",
        "List Item 3",
        "List Item 4",
        "List Item 5",
        "List Item 6",
        "List Item 7"
    };

};

inline MyWindow::MyWindow() {
  add(listbox1);
  set_title("ListBox Example");
  set_border_width(6);
  set_default_size(300, 100);

  show_all_children();
}

//======================================================
// Main
//======================================================
int main(int argc, char** argv) {
    auto appMain = Gtk::Application::create(argc, argv, "org.gtkmm.example");
    MyWindow MyWindow1;
    appMain->run(MyWindow1);
    return 0;
}

The above is still not very useful however because it lacks scrollbars like a standard windows textbox and if you over fill it then it will make the window longer than the screen. Here's the code that gives it scrollbars:

//=======================================================
// GTKMM3/C++11 ListBox Example / W.Moore
//=======================================================
#include <gtkmm.h>
#include <iostream>
#include <string>
#include <sstream>
#include <initializer_list>

using namespace std;

//======================================================
// My List Row
//======================================================
class MyListRow : public Gtk::ListBoxRow
{
public:
    MyListRow(const string text)
      : c1{text}
    {
       add(c1);
       set_halign(Gtk::Align::ALIGN_START);
       show_all_children();
    }
    Gtk::Label c1;
};

//======================================================
// List Box with scrollbars
//======================================================
class ListBoxScroll : public Gtk::ScrolledWindow {
  public:
    ListBoxScroll();
    ListBoxScroll(initializer_list<string> list);
    void api_AddRow(string line);
    void api_AddRows(vector<string>& lines);
    void api_Clear();

    function<void(string label)> fun_selected;

protected:
    Gtk::Box               hbox {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::ListBox           listbox;

    void sig_row_selected(Gtk::ListBoxRow* listboxrow);
};

//======================================================
// ListBoxScroll
//======================================================
inline ListBoxScroll::ListBoxScroll()
{
    add(hbox);
    hbox.pack_start(listbox, Gtk::PackOptions::PACK_EXPAND_WIDGET);
    listbox.signal_row_selected().connect(sigc::mem_fun(*this, ListBoxScroll::sig_row_selected));
    show_all_children();
}

inline ListBoxScroll::ListBoxScroll(initializer_list<string> list) {
  for (auto s : list) {
    api_AddRow(s);
  }
}

inline void ListBoxScroll::api_Clear() {
  listbox.unselect_all();
  vector<Gtk::Widget*> children = listbox.get_children();
  for (Widget* w : children) {
    listbox.remove(*w);
    delete w;
  }
}

inline void ListBoxScroll::api_AddRow(string text)
{
    auto row = Gtk::manage(new MyListRow{text});
    listbox.append(*row);
    row->show();
}

inline void ListBoxScroll::api_AddRows(vector<string>& lines) {
  for (string& L : lines) {
    api_AddRow(L);
  }
}

inline void ListBoxScroll::sig_row_selected(Gtk::ListBoxRow* listboxrow) {
  if (fun_selected && (listboxrow != nullptr)) {
    MyListRow* listrow = (MyListRow*)listboxrow;
    Glib::ustring us = listrow->c1.get_text();
    fun_selected(us.c_str());
  }
}


class WnViewer : public Gtk::Window {
  public:
    WnViewer();
    ~WnViewer();

  private:
    Gtk::Box          m_vbox       {Gtk::ORIENTATION_VERTICAL};
    Gtk::Box          m_box        {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::Box          m_boxleft    {Gtk::ORIENTATION_VERTICAL};
    Gtk::Box          m_boxbtn     {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::Button       m_btnClear   {"Clear"};
    Gtk::Button       m_btnRefresh {"Refresh"};
    ListBoxScroll     m_listbox;
    Gtk::TextView     m_textview;
};

inline WnViewer::WnViewer() {
  set_title("Viewer");
  set_border_width(6);
  set_default_size(600, 600);

  add(m_vbox);
  m_vbox.pack_start(m_boxbtn, Gtk::PackOptions::PACK_SHRINK);
  m_vbox.pack_start(m_box);
  m_boxbtn.pack_start(m_btnClear,   Gtk::PackOptions::PACK_SHRINK);
  m_boxbtn.pack_start(m_btnRefresh, Gtk::PackOptions::PACK_SHRINK);

  m_box     .pack_start(m_boxleft,  Gtk::PackOptions::PACK_SHRINK);
  m_box     .pack_start(m_textview, Gtk::PackOptions::PACK_EXPAND_WIDGET);
  m_boxleft .pack_start(m_listbox,  Gtk::PackOptions::PACK_EXPAND_WIDGET);
  m_listbox.set_size_request(200);


  for(int i=0; i < 30; i++) {
    stringstream x;
    x << "Testing " << i << "\n";
    m_listbox.api_AddRow(x.str().c_str());
  }

  auto lamba_clear = [&]() {
      m_listbox.api_Clear();
  };

  auto lamba_refresh = [&]() {
    for(int i=0; i < 30; i++) {
      stringstream x;
      x << "Testing " << i << "\n";
      m_listbox.api_AddRow(x.str().c_str());
    }
  };

  m_btnClear   .signal_clicked().connect(lamba_clear);
  m_btnRefresh .signal_clicked().connect(lamba_refresh);

  m_listbox.fun_selected = [](string label) {
      cout << "selected:" << label << "\n";
  };

  show_all_children();
}

inline WnViewer::~WnViewer() {

}

//======================================================
// Main
//======================================================
int main(int argc, char** argv) {
    auto appMain = Gtk::Application::create(argc, argv, 
                       "org.gtkmm.example");
    WnViewer WnViewer1;
    appMain->run(WnViewer1);
    return 0;
}

I think gtkmm3 works really well. But you need to create wrappers around all of the components to get them to work like regular c# widgets because they are smaller building blocks than c# .net widget (in my opinion anyways).

A few loose ends:

  • How to get the label horizontal width to shrink to minimal label height in this example?
  • How to get the veritical scrollbars to always appear more like standard windows scrollbar?

(really wish the people at Gnome/Gtk would add composite widgets like below to gtk without needing to reinvent the wheel everytime somebody needs a simple listbox like c#/.net.)

Here's an Even more detailed example of above:

#ifndef WIDGET_LISTBOX_H
#define WIDGET_LISTBOX_H

//=======================================================
// GTKMM3 ListBox Example: C++11 / W.Moore
//=======================================================
#include <gtkmm.h>
#include <iostream>
#include <string>
#include <initializer_list>

using namespace std;

//======================================================
// List Row
//======================================================
class ListRow : public Gtk::ListBoxRow
{
public:
    ListRow(const string text) : c1{text} {
       add(c1);
       set_halign(Gtk::Align::ALIGN_START);
       show_all_children();
    }
    Gtk::Label c1;
};

//======================================================
// List Box with scrollbars
//======================================================
class ListBoxScroll : public Gtk::ScrolledWindow {
  public:
    ListBoxScroll();
    ListBoxScroll(initializer_list<string> list);

    void           api_AddRow(string line);
    void           api_AddRows(vector<string>& lines);
    void           api_Clear();
    void           api_Focus();
    vector<string> api_GetAll();
    int            api_GetCount();
    string         api_GetAt(int i);
    string         api_GetSelected();
    void           api_DelSelected();
    void           api_DelAll();

    function<void(string label)> fun_selected;   //single-click or cursor selection
    function<void(string label)> fun_activated;  //double-click

protected:
    Gtk::Box               hbox {Gtk::ORIENTATION_HORIZONTAL};
    Gtk::ListBox           listbox;
    void sig_row_selected  (Gtk::ListBoxRow* listboxrow);
    void sig_row_activated (Gtk::ListBoxRow* listboxrow);

};

inline void ListBoxScroll::api_Focus() {
  grab_focus();
  listbox.grab_focus();
}

//======================================================
// ListBoxScroll: Constructor 1
//======================================================
inline ListBoxScroll::ListBoxScroll()
{
    add(hbox);
    hbox.pack_start(listbox, Gtk::PackOptions::PACK_EXPAND_WIDGET);

    //make double click active row
    listbox.set_activate_on_single_click(false);

    listbox.signal_row_activated().connect(sigc::mem_fun(
                    *this,
                    ListBoxScroll::sig_row_activated)
    );
    listbox.signal_row_selected().connect(sigc::mem_fun(
                    *this,
                    ListBoxScroll::sig_row_selected)
    );
    listbox.set_can_focus();
    show_all_children();

}

//======================================================
// ListBoxScroll: Constructor 2
//======================================================
inline ListBoxScroll::ListBoxScroll(initializer_list<string> list) {
  for (auto s : list) {
    api_AddRow(s);
  }
}

//======================================================
// ListBoxScroll: Delete All
//======================================================
inline void ListBoxScroll::api_DelAll() {
  api_Clear();
}

//======================================================
// ListBoxScroll: Get All
//======================================================
inline vector<string> ListBoxScroll::api_GetAll() {
  vector<Gtk::Widget*> children = listbox.get_children();
  vector<string>       strlist;

  for (Widget* row : children) {
    ListRow* rowi = (ListRow*)row;
    strlist.push_back(rowi->c1.get_text().c_str());
  }

  return strlist;
}

//======================================================
// ListBoxScroll: Get At
//======================================================
inline string ListBoxScroll::api_GetAt(int i) {
  vector<Gtk::Widget*> children = listbox.get_children();
  Widget*  row  = children.at(i);
  ListRow* rowi = (ListRow*)row;
  return rowi->c1.get_text().c_str();
}

//======================================================
// ListBoxScroll: Get Count
//======================================================
inline int ListBoxScroll::api_GetCount() {
  vector<Gtk::Widget*> children = listbox.get_children();
  return (int) children.size();
}

//======================================================
// ListBoxScroll: Delete Selected
//======================================================
inline void ListBoxScroll::api_DelSelected() {
  ListRow* row_selected = (ListRow*) listbox.get_selected_row();

  //Hackishly find selected position since GTK lacks a better way...
  vector<Gtk::Widget*> wrow = listbox.get_children();
  int row_posi              = -1;
  int row_count             = (int) wrow.size();
  for(int i = 0; i <row_count; i++) {
    ListRow* row_i = (ListRow*)wrow[i];
    //cout << "row_i:" << i << " (" << row_i->c1.get_text() << ")\n";
    if (row_i == row_selected) {
        row_posi = i;
        break;
    }
  }
  //cout << "row_pos:" << row_posi << "\n";

  if (row_posi != -1) {

    // Unselect Current
    listbox.unselect_row();

    Gtk::ListBoxRow* select_next = nullptr;

    // Move Selection Line by One
    if ((row_posi + 1) < row_count) {
      select_next = (Gtk::ListBoxRow*)wrow[row_posi+1];
    }
    else if ((row_posi-1) >= 0) {
      select_next = (Gtk::ListBoxRow*)wrow[row_posi-1];
    }

    // Remove Initially Selected
    //const Glib::RefPtr<Gtk::Adjustment> hadj = get_hadjustment(); //save hpos before remove
    const Glib::RefPtr<Gtk::Adjustment> vadj = get_vadjustment(); //save hpos before remove
    double vvalue = vadj->get_value();

    listbox.remove(*row_selected);
    delete row_selected;

    // On Remove, for some reason...
    // the widget loses focus and vadjustment gets reset
    vadj->set_value(vvalue);
    listbox.grab_focus(); //need this?
    listbox.select_row(*select_next);
    select_next->grab_focus();
  }
}

//======================================================
// ListBoxScroll: Get Selected
//======================================================
inline string ListBoxScroll::api_GetSelected() {
  Gtk::ListBoxRow* row = listbox.get_selected_row();
  ListRow* rowi = (ListRow*) row;
  return rowi->c1.get_text().c_str();
}

//======================================================
// ListBoxScroll: Clear
//======================================================
inline void ListBoxScroll::api_Clear() {
  vector<Gtk::Widget*> children = listbox.get_children();
  listbox.unselect_all();
  for (Widget* w1 : children) {
    listbox.remove(*w1);
  }

  //Allow GUI to update
  while (gtk_events_pending()) {
    gtk_main_iteration_do(false);
  }

  for (Widget* w2 : children) {
    delete w2;
  }

}

//======================================================
// ListBoxScroll: AddRow
//======================================================
inline void ListBoxScroll::api_AddRow(string text)
{
    auto row = Gtk::manage(new ListRow{text});
    listbox.append(*row);
    row->show();
}

//======================================================
// ListBoxScroll: AddRows
//======================================================
inline void ListBoxScroll::api_AddRows(vector<string>& lines) {
  for (string& L : lines) {
    api_AddRow(L);
  }
}

//======================================================
// ListBoxScroll: sig_row_selected
//======================================================
inline void ListBoxScroll::sig_row_selected(Gtk::ListBoxRow* listboxrow) {
  if (fun_selected && (listboxrow != nullptr)) {
    //cout << "<selected>\n";
    ListRow* listrow = (ListRow*)listboxrow;
    Glib::ustring us = listrow->c1.get_text();
    fun_selected(us.c_str());
  }
}

//======================================================
// ListBoxScroll: sig_row_activated
//======================================================
inline void ListBoxScroll::sig_row_activated(Gtk::ListBoxRow* listboxrow) {
  if (fun_activated && (listboxrow != nullptr)) {
    //cout << "<activated>\n";
    ListRow* listrow = (ListRow*)listboxrow;
    Glib::ustring us = listrow->c1.get_text();
    fun_activated(us.c_str());
  }
}


#endif // WIDGET_LIST_BOX_H


来源:https://stackoverflow.com/questions/34253297/how-to-add-text-box-in-gtkmmgtklistbox-using-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!