Welcome, guest | Sign In | My Account | Store | Cart

Using pygtk and glade you can easily write all you need to provide a log text buffer to output the data dropped.

Python, 93 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#-- dndtester.glade --

<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>

<widget class="GtkWindow" id="DNDTester">
  <property name="visible">True</property>
  <property name="title" translatable="yes">D'N'D Tester</property>
  <property name="type">GTK_WINDOW_TOPLEVEL</property>
  <property name="window_position">GTK_WIN_POS_NONE</property>
  <property name="modal">False</property>
  <property name="resizable">True</property>
  <property name="destroy_with_parent">False</property>
  <property name="decorated">True</property>
  <property name="skip_taskbar_hint">False</property>
  <property name="skip_pager_hint">False</property>
  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
  <signal name="destroy" handler="on_dndtester_destroy" />

  <child>
    <widget class="GtkScrolledWindow" id="scrolledwindow1">
      <property name="visible">True</property>
      <property name="can_focus">True</property>
      <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
      <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
      <property name="shadow_type">GTK_SHADOW_IN</property>
      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>

      <child>
	    <widget class="GtkTextView" id="log">
	      <property name="visible">True</property>
	      <property name="can_focus">True</property>
	      <property name="editable">True</property>
	      <property name="overwrite">False</property>
	      <property name="accepts_tab">True</property>
	      <property name="justification">GTK_JUSTIFY_LEFT</property>
	      <property name="wrap_mode">GTK_WRAP_NONE</property>
	      <property name="cursor_visible">True</property>
	      <property name="pixels_above_lines">0</property>
	      <property name="pixels_below_lines">0</property>
	      <property name="pixels_inside_wrap">0</property>
	      <property name="left_margin">0</property>
	      <property name="right_margin">0</property>
	      <property name="indent">0</property>
	      <property name="text" translatable="yes"></property>
	      <signal name="drag_data_received" handler="on_log_drag_data_received"/>
	    </widget>
      </child>
    </widget>
  </child>
</widget>
</glade-interface>

#-- / dndtester.glade --

# dndtester.py

import pygtk
pygtk.require("2.0")

import gtk
import gtk.glade

class DNDTester(object):
    def __init__(self):
        filename = 'dndtester.glade'
        windowname = 'DNDTester'
        self.wTree = gtk.glade.XML(filename, windowname)
        self.log_buffer = gtk.TextBuffer()
        self.setupWidgets()
        
    def setupWidgets(self):
        HANDLERS_AND_METHODS = {
            "on_dndtester_destroy": self.destroy,
            "on_drag_data_received": self.on_log_drag_data_received
            }

        log = self.wTree.get_widget("log")
        log.set_buffer(self.log_buffer)
        self.wTree.signal_autoconnect(HANDLERS_AND_METHODS)

    def on_log_drag_data_received(self, data):
        self.log_buffer.insert_at_cursor(data+'\n', len(data))

    def destroy(self, data):
        gtk.mainquit()

if __name__ == "__main__":
    app = DNDTester()
    gtk.mainloop()

Sometimes I need to debug the data that is dragged on my application windows to know how I should handle the dropped data. This short examples builds a GUI with pygtk and glade (an XML file that describes the GUI layout).

As you see the applications doesn't know anything about the GUI layout since everything is written and parsed by glade that will build the guy by itself. As you see the XML DTD is quite easy to read and understand, anyway GTK+ developers provided a GUI Designer, called glade too, that will help you in writing that XML file from your GUI skeleton.

This approach provides at least 2 advantages: * Python code only knows about data: GTK+ 2 is heavily built around the MVC design pattern which separates the model from the view using a controller for both. Basically we are writing a controller between our GUI and some models (self.log_buffer in this example). Then after we modify the buffer with on_log_drag_data_received, the view is automatically notified and updated by the toolkit.

  • We can reuse GUIs built for other languages. Since XML is language independent, we can grab the GUI from some C/C++ application that we like and recode it's body in python using its glade implementation.

As usual widgets events and our hand-coded class are bound using signals. Again the glade object we built with gtk.glade.XML() has a method that will register each key in a dictionary as an hook for the associated value. In this example we tell the the GUI that if it raises on_dndtester_destroy event, it should call self.destroy method in order to handle it.

Inside the glade file you can find this 2 particular tags:

Since GTK+ widgets share some of the signal names, we need to bind the signal with an handler inside the glade file. Pragmatically we are just providing a customized alias for the signal name, to help handling it from the application code.

To run this example you will need to copy the xml half in a file called dndtester.glade and put it in the same directory of the python source file. Then running it with the usual: python pysource_filename.py Will open a window containing only a TextView (TextArea in GTK+ conventions) that will accept drops and displays the drop content.

Created by Valentino Volonghi on Wed, 1 Dec 2004 (PSF)
Python recipes (4591)
Valentino Volonghi's recipes (6)

Required Modules

  • (none specified)

Other Information and Tasks