Re: DND in TreeView



Jonathon Jongsma <jonathon quotidian org> writes:

> Deng Xiyue wrote:
>> Deng Xiyue <manphiz gmail com> writes:
>>
>>> Hi gtkmm maintainers:
>>>
>>> I'm having some problem on handling DND in a TreeView.  I tried to
>>> handle DND with signals in Gtk::TreeModel:
>>> Gtk::TreeModel::signal_row_deleted() and
>>> Gtk::TreeModel::signal_row_inserted().  In most cases they work well,
>>> except on the last row: when dragging the last row away,
>>> signal_row_deleted() is never emitted; when dragging a row to the place
>>> after the current last row, signal_row_inserted() gives the Path of row
>>> 0.  The test is done in gtkmm 2.14.3.
>>>
>>> I wonder whether it is a bug in GTK+/gtkmm or I'm using the wrong
>>> signals for in TreeView DND handling.  I'm aware of the DND example in
>>> gtkmm tutorial, but seems to describe a general way to handle an widget
>>> as a source/destination to coordinate with another widget, instead of a
>>> DND within TreeView rows, or at least not an optimum way for that.
>>> Correct me if I'm wrong.
>>>
>>> Regards,
>>> Deng Xiyue
>>>
>>> (PS: I'm using gmane to access various mailing lists so it should be
>>> safe to not CC me, but I wouldn't mind if you do so by mailing list
>>> policy.)
>>
>> Hi there, any news on this?  Any pointer to docs is appreciated, even
>> GTK+ ones.
>>
>> Thanks in advance.
>>
>
> Hi Deng,
> I don't actually have any experience with DND in a treeview so I don't
> have a lot of advice to give.  You might try to create a minimal
> example in C/Gtk+ just to verify whether the behavior is the same in
> gtk+ and gtkmm
>

Sorry for the delay in preparing a testcase for being busy in the past
weeks.  The test program is based on one of the examples with callbacks
connected to the aforementioned signals, cout the deleted and inserted
rows to stdout.  By DND from and to the last row the abnormal behavior
will be observed.  As the implementation of TreeView in GTKMM, I guess
the same behavior is expected with pure GTK+ code.  But I still like to
know whether this is the way to handle DND within TreeView before filing
bug report.  Thanks.

Regards,
Deng Xiyue

#include <iostream>
#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  virtual void on_button_quit();
  virtual void on_row_deleted(Gtk::TreeModel::Path const& path);
  virtual void on_row_inserted(Gtk::TreePath const&, Gtk::TreeIter const&);

  //Tree model columns:
  class ModelColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:

    ModelColumns()
    { add(m_col_id); }

    Gtk::TreeModelColumn<unsigned int> m_col_id;
  };

  ModelColumns m_Columns;

  //Child widgets:
  Gtk::VBox m_VBox;

  Gtk::ScrolledWindow m_ScrolledWindow;
  Gtk::TreeView m_TreeView;
  Glib::RefPtr<Gtk::ListStore> m_refTreeModel;

  Gtk::HButtonBox m_ButtonBox;
  Gtk::Button m_Button_Quit;

  int inserted_pos_;
};

ExampleWindow::ExampleWindow()
  : m_Button_Quit("Quit")
{
  set_title("TreeView DND bug test");
  set_border_width(5);
  set_default_size(400, 200);

  add(m_VBox);

  //Add the TreeView, inside a ScrolledWindow, with the button underneath:
  m_ScrolledWindow.add(m_TreeView);

  //Only show the scrollbars when they are necessary:
  m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

  m_VBox.pack_start(m_ScrolledWindow);
  m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

  m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
  m_ButtonBox.set_border_width(5);
  m_ButtonBox.set_layout(Gtk::BUTTONBOX_END);
  m_Button_Quit.signal_clicked().connect( sigc::mem_fun(*this,
                                                        &ExampleWindow::on_button_quit) );

  //Create the Tree model:
  m_refTreeModel = Gtk::ListStore::create(m_Columns);
  m_TreeView.set_model(m_refTreeModel);
  m_TreeView.set_reorderable(true);

  //Fill the TreeView's model
  Gtk::TreeModel::Row row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 1;

  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 2;

  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 3;

  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = 4;

  //Add the TreeView's view columns:
  //This number will be shown with the default numeric formatting.
  m_TreeView.append_column("ID", m_Columns.m_col_id);

  m_refTreeModel->signal_row_inserted().connect
    (sigc::mem_fun(*this, &ExampleWindow::on_row_inserted));
  m_refTreeModel->signal_row_deleted().connect
    (sigc::mem_fun(*this, &ExampleWindow::on_row_deleted));
  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_quit()
{
  hide();
}

void ExampleWindow::on_row_deleted(Gtk::TreeModel::Path const& path)
{
  Gtk::TreeModel::iterator iter_deleted =
    m_refTreeModel->get_iter(path);
  if (iter_deleted)
    {
      Gtk::TreeModel::Row row = *iter_deleted;
      int deleted_pos = row[m_Columns.m_col_id] - 1;

      if (deleted_pos < inserted_pos_)
        {
          --inserted_pos_;
        }

      if (deleted_pos != inserted_pos_)
        {
          std::cout << "Deleted row: " << deleted_pos << std::endl
            << "Inserted row: " << inserted_pos_ << std::endl << std::endl;
        }
    }
}

void ExampleWindow::on_row_inserted(Gtk::TreeModel::Path const& path,
                                              Gtk::TreeModel::iterator const& iter)
{
  Gtk::TreeModel::iterator iter_inserted =
    m_refTreeModel->get_iter(path);
  if (iter_inserted)
    {
      Gtk::TreeModel::Row row = *(++iter_inserted);
      inserted_pos_ = row[m_Columns.m_col_id];
    }
}

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

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}


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