2012-12-14 2 views
11

私は、PyGTK(GTK2)からPyGObjectイントロスペクション(GTK3)に向けて、指向性非循環グラフを扱うためのライブラリであるliblarchを移植しています。私はGtkTreeViewで問題に遭遇しました。GtkTreeViewをGTK3でドラッグアンドドロップしてソートする方法は?

liblarchを使用するアプリケーションでは、GtkTreeViewを列でソートする必要がありますが、同時にユーザーは行をドラッグアンドドロップして別の行の下に行を移動できます。そのために私は手動でdnd_data_get()dnd_data_receive()を処理しなければなりませんでしたが、これは大丈夫です。

PyGTKで動作するGtkTreeViewの最小限の設定があります。行がソートされ、ユーザーは行を移動できます。

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

import gtk 

window = gtk.Window() 
window.set_size_request(300, 200) 
window.connect('delete_event', lambda w,e: gtk.main_quit()) 

# Define Liblarch Tree 

store = gtk.TreeStore(str, str) 
store.insert(None, -1, ["A", "Task A"]) 
store.insert(None, -1, ["B", "Task B"]) 
store.insert(None, -1, ["C", "Task C"]) 
d_parent = store.insert(None, -1, ["D", "Task D"]) 
store.insert(d_parent, -1, ["E", "Task E"]) 

# Define TreeView in similar way as it happens in GTG/Liblarch_gtk 
tv = gtk.TreeView() 

col = gtk.TreeViewColumn() 
col.set_title("Title") 
render_text = gtk.CellRendererText() 
col.pack_start(render_text, expand=True) 
col.add_attribute(render_text, 'markup', 1) 
col.set_resizable(True) 
col.set_expand(True) 
col.set_sort_column_id(0) 
tv.append_column(col) 
tv.set_property("expander-column", col) 

treemodel = store 

def _sort_func(model, iter1, iter2): 
    """ Sort two iterators by function which gets node objects. 
    This is a simple wrapper which prepares node objects and then 
    call comparing function. In other case return default value -1 
    """ 
    node_a = model.get_value(iter1, 0) 
    node_b = model.get_value(iter2, 0) 
    if node_a and node_b: 
     sort = cmp(node_a, node_b) 
    else: 
     sort = -1 
    return sort 

treemodel.set_sort_func(1, _sort_func) 
tv.set_model(treemodel) 

def on_child_toggled(treemodel2, path, iter, param=None): 
    """ Expand row """ 
    if not tv.row_expanded(path): 
     tv.expand_row(path, True) 

treemodel.connect('row-has-child-toggled', on_child_toggled) 

tv.set_search_column(1) 
tv.set_property("enable-tree-lines", False) 
tv.set_rules_hint(False) 


#### Drag and drop stuff 

dnd_internal_target = '' 
dnd_external_targets = {} 

def on_drag_fail(widget, dc, result): 
    print "Failed dragging", widget, dc, result 

def __init_dnd(): 
    """ Initialize Drag'n'Drop support 

    Firstly build list of DND targets: 
     * name 
     * scope - just the same widget/same application 
     * id 

    Enable DND by calling enable_model_drag_dest(), 
    enable_model-drag_source() 

    It didnt use support from gtk.Widget(drag_source_set(), 
    drag_dest_set()). To know difference, look in PyGTK FAQ: 
    http://faq.pygtk.org/index.py?file=faq13.033.htp&req=show 
    """ 
    #defer_select = False 

    if dnd_internal_target == '': 
     error = 'Cannot initialize DND without a valid name\n' 
     error += 'Use set_dnd_name() first' 
     raise Exception(error) 

    dnd_targets = [(dnd_internal_target, gtk.TARGET_SAME_WIDGET, 0)] 
    for target in dnd_external_targets: 
     name = dnd_external_targets[target][0] 
     dnd_targets.append((name, gtk.TARGET_SAME_APP, target)) 

    tv.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, 
     dnd_targets, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE) 

    tv.enable_model_drag_dest(\ 
     dnd_targets, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE) 


def on_drag_data_get(treeview, context, selection, info, timestamp): 
    """ Extract data from the source of the DnD operation. 

    Serialize iterators of selected tasks in format 
    <iter>,<iter>,...,<iter> and set it as parameter of DND """ 
    print "on_drag_data_get(", treeview, context, selection, info, timestamp 

    treeselection = treeview.get_selection() 
    model, paths = treeselection.get_selected_rows() 
    iters = [model.get_iter(path) for path in paths] 
    iter_str = ','.join([model.get_string_from_iter(iter) for iter in iters]) 
    selection.set(dnd_internal_target, 0, iter_str) 
    print "Sending", iter_str 

def on_drag_data_received(treeview, context, x, y, selection, info,\ 
          timestamp): 
    """ Handle a drop situation. 

    First of all, we need to get id of node which should accept 
    all draged nodes as their new children. If there is no node, 
    drop to root node. 

    Deserialize iterators of dragged nodes (see self.on_drag_data_get()) 
    Info parameter determines which target was used: 
     * info == 0 => internal DND within this TreeView 
     * info > 0 => external DND 

    In case of internal DND we just use Tree.move_node(). 
    In case of external DND we call function associated with that DND 
    set by self.set_dnd_external() 
    """ 
    print "on_drag_data_received", treeview, context, x, y, selection, info, timestamp 

    model = treeview.get_model() 
    destination_iter = None 
    destination_tid = None 
    drop_info = treeview.get_dest_row_at_pos(x, y) 
    if drop_info: 
     path, position = drop_info 
     destination_iter = model.get_iter(path) 
     if destination_iter: 
      destination_tid = model.get_value(destination_iter, 0) 

    # Get dragged iter as a TaskTreeModel iter 
    # If there is no selected task (empty selection.data), 
    # explictly skip handling it (set to empty list) 
    if selection.data == '': 
     iters = [] 
    else: 
     iters = selection.data.split(',') 

    dragged_iters = [] 
    for iter in iters: 
     print "Info", info 
     if info == 0: 
      try: 
       dragged_iters.append(model.get_iter_from_string(iter)) 
      except ValueError: 
       #I hate to silently fail but we have no choice. 
       #It means that the iter is not good. 
       #Thanks shitty gtk API for not allowing us to test the string 
       print "Shitty iter", iter 
       dragged_iter = None 

     elif info in dnd_external_targets and destination_tid: 
      f = dnd_external_targets[info][1] 

      src_model = context.get_source_widget().get_model() 
      dragged_iters.append(src_model.get_iter_from_string(iter)) 


    for dragged_iter in dragged_iters: 
     if info == 0: 
      if dragged_iter and model.iter_is_valid(dragged_iter): 
       dragged_tid = model.get_value(dragged_iter, 0) 
       try: 
        row = [] 
        for i in range(model.get_n_columns()): 
         row.append(model.get_value(dragged_iter, i)) 
        #tree.move_node(dragged_tid, new_parent_id=destination_tid) 
        print "move_after(%s, %s) ~ (%s, %s)" % (dragged_iter, destination_iter, dragged_tid, destination_tid) 
        #model.move_after(dragged_iter, destination_iter) 
        model.insert(destination_iter, -1, row) 
        model.remove(dragged_iter) 
       except Exception, e: 
        print 'Problem with dragging: %s' % e 
     elif info in dnd_external_targets and destination_tid:  
      source = src_model.get_value(dragged_iter,0) 
      # Handle external Drag'n'Drop 
      f(source, destination_tid) 


dnd_internal_target = 'gtg/task-iter-str' 
__init_dnd() 
tv.connect('drag_data_get', on_drag_data_get) 
tv.connect('drag_data_received', on_drag_data_received) 
tv.connect('drag_failed', on_drag_fail) 

window.add(tv) 
window.show_all() 

tv.expand_all() 
gtk.main() 

# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 

私はこのスクリプトをPyGObject(GTK3)に移植しました。私のコード:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

from gi.repository import Gtk, Gdk 

window = Gtk.Window() 
window.set_size_request(300, 200) 
window.connect('delete_event', lambda w,e: Gtk.main_quit()) 

# Define Liblarch Tree 

store = Gtk.TreeStore(str, str) 
store.insert(None, -1, ["A", "Task A"]) 
store.insert(None, -1, ["B", "Task B"]) 
store.insert(None, -1, ["C", "Task C"]) 
d_parent = store.insert(None, -1, ["D", "Task D"]) 
store.insert(d_parent, -1, ["E", "Task E"]) 

# Define TreeView in similar way as it happens in GTG/Liblarch_gtk 
tv = Gtk.TreeView() 

col = Gtk.TreeViewColumn() 
col.set_title("Title") 
render_text = Gtk.CellRendererText() 
col.pack_start(render_text, expand=True) 
col.add_attribute(render_text, 'markup', 1) 
col.set_resizable(True) 
col.set_expand(True) 
col.set_sort_column_id(0) 
tv.append_column(col) 
tv.set_property("expander-column", col) 

treemodel = store 

def _sort_func(model, iter1, iter2): 
    """ Sort two iterators by function which gets node objects. 
    This is a simple wrapper which prepares node objects and then 
    call comparing function. In other case return default value -1 
    """ 
    node_a = model.get_value(iter1, 0) 
    node_b = model.get_value(iter2, 0) 
    if node_a and node_b: 
     sort = cmp(node_a, node_b) 
    else: 
     sort = -1 
    return sort 

treemodel.set_sort_func(1, _sort_func) 
tv.set_model(treemodel) 

def on_child_toggled(treemodel2, path, iter, param=None): 
    """ Expand row """ 
    if not tv.row_expanded(path): 
     tv.expand_row(path, True) 

treemodel.connect('row-has-child-toggled', on_child_toggled) 

tv.set_search_column(1) 
tv.set_property("enable-tree-lines", False) 
tv.set_rules_hint(False) 


#### Drag and drop stuff 

dnd_internal_target = '' 
dnd_external_targets = {} 

def on_drag_fail(widget, dc, result): 
    print "Failed dragging", widget, dc, result 

def __init_dnd(): 
    """ Initialize Drag'n'Drop support 

    Firstly build list of DND targets: 
     * name 
     * scope - just the same widget/same application 
     * id 

    Enable DND by calling enable_model_drag_dest(), 
    enable_model-drag_source() 

    It didnt use support from Gtk.Widget(drag_source_set(), 
    drag_dest_set()). To know difference, look in PyGTK FAQ: 
    http://faq.pygtk.org/index.py?file=faq13.033.htp&req=show 
    """ 
    #defer_select = False 

    if dnd_internal_target == '': 
     error = 'Cannot initialize DND without a valid name\n' 
     error += 'Use set_dnd_name() first' 
     raise Exception(error) 

    dnd_targets = [(dnd_internal_target, Gtk.TargetFlags.SAME_WIDGET, 0)] 
    for target in dnd_external_targets: 
     name = dnd_external_targets[target][0] 
     dnd_targets.append((name, Gtk.TARGET_SAME_APP, target)) 

    tv.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, 
     dnd_targets, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) 

    tv.enable_model_drag_dest(\ 
     dnd_targets, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) 


def on_drag_data_get(treeview, context, selection, info, timestamp): 
    """ Extract data from the source of the DnD operation. 

    Serialize iterators of selected tasks in format 
    <iter>,<iter>,...,<iter> and set it as parameter of DND """ 
    print "on_drag_data_get(", treeview, context, selection, info, timestamp 

    treeselection = treeview.get_selection() 
    model, paths = treeselection.get_selected_rows() 
    iters = [model.get_iter(path) for path in paths] 
    iter_str = ','.join([model.get_string_from_iter(iter) for iter in iters]) 
    selection.set(dnd_internal_target, 0, iter_str) 
    print "Sending", iter_str 

def on_drag_data_received(treeview, context, x, y, selection, info,\ 
          timestamp): 
    """ Handle a drop situation. 

    First of all, we need to get id of node which should accept 
    all draged nodes as their new children. If there is no node, 
    drop to root node. 

    Deserialize iterators of dragged nodes (see self.on_drag_data_get()) 
    Info parameter determines which target was used: 
     * info == 0 => internal DND within this TreeView 
     * info > 0 => external DND 

    In case of internal DND we just use Tree.move_node(). 
    In case of external DND we call function associated with that DND 
    set by self.set_dnd_external() 
    """ 
    print "on_drag_data_received", treeview, context, x, y, selection, info, timestamp 

    model = treeview.get_model() 
    destination_iter = None 
    destination_tid = None 
    drop_info = treeview.get_dest_row_at_pos(x, y) 
    if drop_info: 
     path, position = drop_info 
     destination_iter = model.get_iter(path) 
     if destination_iter: 
      destination_tid = model.get_value(destination_iter, 0) 

    # Get dragged iter as a TaskTreeModel iter 
    # If there is no selected task (empty selection.data), 
    # explictly skip handling it (set to empty list) 
    if selection.data == '': 
     iters = [] 
    else: 
     iters = selection.data.split(',') 

    dragged_iters = [] 
    for iter in iters: 
     print "Info", info 
     if info == 0: 
      try: 
       dragged_iters.append(model.get_iter_from_string(iter)) 
      except ValueError: 
       #I hate to silently fail but we have no choice. 
       #It means that the iter is not good. 
       #Thanks shitty Gtk API for not allowing us to test the string 
       print "Shitty iter", iter 
       dragged_iter = None 

     elif info in dnd_external_targets and destination_tid: 
      f = dnd_external_targets[info][1] 

      src_model = context.get_source_widget().get_model() 
      dragged_iters.append(src_model.get_iter_from_string(iter)) 


    for dragged_iter in dragged_iters: 
     if info == 0: 
      if dragged_iter and model.iter_is_valid(dragged_iter): 
       dragged_tid = model.get_value(dragged_iter, 0) 
       try: 
        row = [] 
        for i in range(model.get_n_columns()): 
         row.append(model.get_value(dragged_iter, i)) 
        #tree.move_node(dragged_tid, new_parent_id=destination_tid) 
        print "move_after(%s, %s) ~ (%s, %s)" % (dragged_iter, destination_iter, dragged_tid, destination_tid) 
        #model.move_after(dragged_iter, destination_iter) 
        model.insert(destination_iter, -1, row) 
        model.remove(dragged_iter) 
       except Exception, e: 
        print 'Problem with dragging: %s' % e 
     elif info in dnd_external_targets and destination_tid:  
      source = src_model.get_value(dragged_iter,0) 
      # Handle external Drag'n'Drop 
      f(source, destination_tid) 


dnd_internal_target = 'gtg/task-iter-str' 
__init_dnd() 
tv.connect('drag_data_get', on_drag_data_get) 
tv.connect('drag_data_received', on_drag_data_received) 
tv.connect('drag_failed', on_drag_fail) 

window.add(tv) 
window.show_all() 

tv.expand_all() 
Gtk.main() 

# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 

は、私はどちらかそれが誘発されていないか、データが受信されていないされている場合、正しくdnd_data_receive()を扱うことができないのです。

Failed dragging <TreeView object at 0xeb4370 (GtkTreeView at 0xf742a0)> <gtk.gdk.X11DragContext object at 0xf351e0 (GdkX11DragContext at 0xf96ca0)> <enum GTK_DRAG_RESULT_NO_TARGET of type GtkDragResult> 

私の質問:どのようPyGObject(GTK3)にポート最初のスクリプトをすることができGtkTreeViewをソートできるようにし、同時に行にドラッグ・アンド・それは、常に次のコールバック+そのパラメータで失敗します落ちた?ハンドリングドラッグアンドドロップコールバックを変更してドラッグアンドドロップを正しく処理するにはどうすればよいですか?

+0

liblarchへのGitHubリンクが壊れています。 – rvighne

答えて

5

まず、PyGObjectのバージョンに関連したエラーが表示されます。最新のUbuntu 13.04ベータ版でラップトップを再インストールする前に、同様のエラー情報を再現します。しかし、アップグレード後に、エラーコールバックの変更

on_drag_data_get(<TreeView object at 0x1765870 (GtkTreeView at 0x19120a0)> <gtk.gdk.X11DragContext object at 0x1765aa0 (GdkX11DragContext at 0x1988820)> <GtkSelectionData at 0x7fffb106b760> 0 21962912 
Traceback (most recent call last): 
    File "dnd_gtk3_org.py", line 116, in on_drag_data_get 
    selection.set(dnd_internal_target, 0, iter_str) 
    File "/usr/lib/python2.7/dist-packages/gi/types.py", line 113, in function 
    return info.invoke(*args, **kwargs) 
TypeError: argument type: Expected Gdk.Atom, but got str 
on_drag_data_received <TreeView object at 0x1765870 (GtkTreeView at 0x19120a0)> <gtk.gdk.X11DragContext object at 0x1765be0 (GdkX11DragContext at 0x1988940)> 45 77 <GtkSelectionData at 0x7fffb106b6e0> 0 21962912 
Traceback (most recent call last): 
    File "dnd_gtk3_org.py", line 151, in on_drag_data_received 
    if selection.data == '': 
AttributeError: 'SelectionData' object has no attribute 'data' 

のようなものを2つだけの小さな問題があります。

  • SelectionData.setの最初のパラメータは、()のみGtk.gdk.Atomすることができそうですpygtkのように指定する文字列ではありません。
  • SelectionDataには 'data'属性はありませんが、代わりにget_data()メソッドがあります。

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

from gi.repository import Gtk, Gdk 

window = Gtk.Window() 
window.set_size_request(300, 200) 
window.connect('delete_event', Gtk.main_quit) 

# Define Liblarch Tree 

store = Gtk.TreeStore(str, str) 
store.insert(None, -1, ["A", "Task A"]) 
store.insert(None, -1, ["B", "Task B"]) 
store.insert(None, -1, ["C", "Task C"]) 
d_parent = store.insert(None, -1, ["D", "Task D"]) 
store.insert(d_parent, -1, ["E", "Task E"]) 

# Define TreeView in similar way as it happens in GTG/Liblarch_gtk 
tv = Gtk.TreeView() 

col = Gtk.TreeViewColumn() 
col.set_title("Title") 
render_text = Gtk.CellRendererText() 
col.pack_start(render_text, expand=True) 
col.add_attribute(render_text, 'markup', 1) 
col.set_resizable(True) 
col.set_expand(True) 
col.set_sort_column_id(0) 
tv.append_column(col) 
tv.set_property("expander-column", col) 

treemodel = store 

def _sort_func(model, iter1, iter2): 
    """ Sort two iterators by function which gets node objects. 
    This is a simple wrapper which prepares node objects and then 
    call comparing function. In other case return default value -1 
    """ 
    node_a = model.get_value(iter1, 0) 
    node_b = model.get_value(iter2, 0) 
    if node_a and node_b: 
     sort = cmp(node_a, node_b) 
    else: 
     sort = -1 
    return sort 

treemodel.set_sort_func(1, _sort_func) 
tv.set_model(treemodel) 

def on_child_toggled(treemodel2, path, iter, param=None): 
    """ Expand row """ 
    if not tv.row_expanded(path): 
     tv.expand_row(path, True) 

treemodel.connect('row-has-child-toggled', on_child_toggled) 

tv.set_search_column(1) 
tv.set_property("enable-tree-lines", False) 
tv.set_rules_hint(False) 


#### Drag and drop stuff 

dnd_internal_target = '' 
dnd_external_targets = {} 

def on_drag_fail(widget, dc, result): 
    print "Failed dragging", widget, dc, result 

def __init_dnd(): 
    """ Initialize Drag'n'Drop support 

    Firstly build list of DND targets: 
     * name 
     * scope - just the same widget/same application 
     * id 

    Enable DND by calling enable_model_drag_dest(), 
    enable_model-drag_source() 

    It didnt use support from Gtk.Widget(drag_source_set(), 
    drag_dest_set()). To know difference, look in PyGTK FAQ: 
    http://faq.pygtk.org/index.py?file=faq13.033.htp&req=show 
    """ 
    #defer_select = False 

    if dnd_internal_target == '': 
     error = 'Cannot initialize DND without a valid name\n' 
     error += 'Use set_dnd_name() first' 
     raise Exception(error) 

    dnd_targets = [(dnd_internal_target, Gtk.TargetFlags.SAME_WIDGET, 0)] 
    for target in dnd_external_targets: 
     name = dnd_external_targets[target][0] 
     dnd_targets.append((name, Gtk.TARGET_SAME_APP, target)) 

    tv.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, 
     dnd_targets, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) 

    tv.enable_model_drag_dest(\ 
     dnd_targets, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) 


def on_drag_data_get(treeview, context, selection, info, timestamp): 
    """ Extract data from the source of the DnD operation. 

    Serialize iterators of selected tasks in format 
    <iter>,<iter>,...,<iter> and set it as parameter of DND """ 
    print "on_drag_data_get(", treeview, context, selection, info, timestamp 

    treeselection = treeview.get_selection() 
    model, paths = treeselection.get_selected_rows() 
    iters = [model.get_iter(path) for path in paths] 
    iter_str = ','.join([model.get_string_from_iter(iter) for iter in iters]) 
    selection.set(selection.get_target(), 0, iter_str) 
    print "Sending", iter_str 

def on_drag_data_received(treeview, context, x, y, selection, info,\ 
          timestamp): 
    """ Handle a drop situation. 

    First of all, we need to get id of node which should accept 
    all draged nodes as their new children. If there is no node, 
    drop to root node. 

    Deserialize iterators of dragged nodes (see self.on_drag_data_get()) 
    Info parameter determines which target was used: 
     * info == 0 => internal DND within this TreeView 
     * info > 0 => external DND 

    In case of internal DND we just use Tree.move_node(). 
    In case of external DND we call function associated with that DND 
    set by self.set_dnd_external() 
    """ 
    print "on_drag_data_received", treeview, context, x, y, selection, info, timestamp 

    model = treeview.get_model() 
    destination_iter = None 
    destination_tid = None 
    drop_info = treeview.get_dest_row_at_pos(x, y) 
    if drop_info: 
     path, position = drop_info 
     destination_iter = model.get_iter(path) 
     if destination_iter: 
      destination_tid = model.get_value(destination_iter, 0) 

    # Get dragged iter as a TaskTreeModel iter 
    # If there is no selected task (empty selection.data), 
    # explictly skip handling it (set to empty list) 
    data = selection.get_data() 
    if data == '': 
     iters = [] 
    else: 
     iters = data.split(',') 

    dragged_iters = [] 
    for iter in iters: 
     print "Info", info 
     if info == 0: 
      try: 
       dragged_iters.append(model.get_iter_from_string(iter)) 
      except ValueError: 
       #I hate to silently fail but we have no choice. 
       #It means that the iter is not good. 
       #Thanks shitty Gtk API for not allowing us to test the string 
       print "Shitty iter", iter 
       dragged_iter = None 

     elif info in dnd_external_targets and destination_tid: 
      f = dnd_external_targets[info][1] 

      src_model = context.get_source_widget().get_model() 
      dragged_iters.append(src_model.get_iter_from_string(iter)) 


    for dragged_iter in dragged_iters: 
     if info == 0: 
      if dragged_iter and model.iter_is_valid(dragged_iter): 
       dragged_tid = model.get_value(dragged_iter, 0) 
       try: 
        row = [] 
        for i in range(model.get_n_columns()): 
         row.append(model.get_value(dragged_iter, i)) 
        #tree.move_node(dragged_tid, new_parent_id=destination_tid) 
        print "move_after(%s, %s) ~ (%s, %s)" % (dragged_iter, destination_iter, dragged_tid, destination_tid) 
        #model.move_after(dragged_iter, destination_iter) 
        model.insert(destination_iter, -1, row) 
        model.remove(dragged_iter) 
       except Exception, e: 
        print 'Problem with dragging: %s' % e 
     elif info in dnd_external_targets and destination_tid:  
      source = src_model.get_value(dragged_iter,0) 
      # Handle external Drag'n'Drop 
      f(source, destination_tid) 


dnd_internal_target = 'gtg/task-iter-str' 
__init_dnd() 
tv.connect('drag_data_get', on_drag_data_get) 
tv.connect('drag_data_received', on_drag_data_received) 
tv.connect('drag_failed', on_drag_fail) 

window.add(tv) 
window.show_all() 

tv.expand_all() 
Gtk.main() 

# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 

質問内の1つを有する上記のスニペットとの間の差分の下にリストされた作業コードスニペットは

116c116 
<  selection.set(selection.get_target(), 0, iter_str) 
--- 
>  selection.set(dnd_internal_target, 0, iter_str) 
151,152c151 
<  data = selection.get_data() 
<  if data == '': 
--- 
>  if selection.data == '': 
155c154 
<   iters = data.split(',') 
--- 
>   iters = selection.data.split(',') 

また、GTK + 3バージョンの他の例が存在しています別のスレッドのTreeViewのドラッグアンドドロップ:unresponsive drag and drop in pygobject

1

GTGは素晴らしいソフトウェアです!しかし、少なくとも私のコンピュータでは、それは遅すぎる。だから私はGtk :: TreeViewを使って指示された非循環グラフを表示するC++ライブラリを書いており、LibLarchソースコードをたくさん見ました。

私が知る限り、GTKのPythonとC++のバインディングは同じ制限を共有しています(GTKのソースコードを参照して、そのように動作する理由を正確に見ています)。ドラッグアンドソートすると、ドラッグ&ドロップは機能しません。並べ替えを有効にした場合DND制限GTKへのパッチが、代わりに完全にそれを

  • を阻止するのことは自分でソートを実装してください

    1. :私はあなたがそれについて行うことができます3つのことを提供します。簡単に:ソートされたツリービューにデータをロードすることから始めます。今度は、ユーザーがドラッグアンドドロップするたびに、ソート機能を使用してドラッグした行を新しい位置に移動します。しかし、GTKソートをオフにしておきます。

    2. これは2に加えて、GUIデザインの問題です:GtkTreeViewでは、ソートされたツリーであまり意味がない兄弟アイテムの間にアイテムを挿入できます。 UIの面では、それらの間ではなくONの行だけをドロップする方が良いです。例:ノーチラスリストビューは、このように機能します。解決策は、TreeViewのdrag_data_received()デフォルトハンドラをオーバーライドするか、または保守性の面でそれよりも優れています。ドロップ位置がONかBEFOREかをモデルに伝えるビューからヒントをモデルに送信します。位置が前であれば、これあなたがきれいGUIを取得し、「あなたの木のdrop_possible()仮想オーバーライドがfalseを返すようにして、あなたは、ツリービューの「あなたがここにドロップすることができます」didplayは表示されません。

    2 3はC++で行いますが、Pythonで簡単に行うことができます:)

    また、オプション1に関する注意:GtktreeView(またはGtkTreeStoreは忘れていましたか?忘れていました)は、ソートが誰かがちょうどそれを修正した場合(あなた...または私...)、または少なくとも派生したビュークラスを作成すると、dndサポートのあるソート済みのツリーに対してデフォルトのクリーンGUIが用意されます。

  • 関連する問題