|
| 1 | +""" |
| 2 | +================ |
| 3 | +GTK4 Spreadsheet |
| 4 | +================ |
| 5 | +
|
| 6 | +Example of embedding Matplotlib in an application and interacting with a |
| 7 | +treeview to store data. Double click on an entry to update plot data. |
| 8 | +""" |
| 9 | + |
| 10 | +import gi |
| 11 | +gi.require_version('Gtk', '4.0') |
| 12 | +gi.require_version('Gdk', '4.0') |
| 13 | +from gi.repository import Gtk |
| 14 | + |
| 15 | +from matplotlib.backends.backend_gtk4agg import FigureCanvas # or gtk4cairo. |
| 16 | + |
| 17 | +from numpy.random import random |
| 18 | +from matplotlib.figure import Figure |
| 19 | + |
| 20 | + |
| 21 | +class DataManager(Gtk.ApplicationWindow): |
| 22 | + num_rows, num_cols = 20, 10 |
| 23 | + |
| 24 | + data = random((num_rows, num_cols)) |
| 25 | + |
| 26 | + def __init__(self, *args, **kwargs): |
| 27 | + super().__init__(*args, **kwargs) |
| 28 | + self.set_default_size(600, 600) |
| 29 | + |
| 30 | + self.set_title('GtkListStore demo') |
| 31 | + |
| 32 | + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, |
| 33 | + spacing=8) |
| 34 | + self.set_child(vbox) |
| 35 | + |
| 36 | + label = Gtk.Label(label='Double click a row to plot the data') |
| 37 | + vbox.append(label) |
| 38 | + |
| 39 | + sw = Gtk.ScrolledWindow() |
| 40 | + sw.set_has_frame(True) |
| 41 | + sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) |
| 42 | + sw.set_hexpand(True) |
| 43 | + sw.set_vexpand(True) |
| 44 | + vbox.append(sw) |
| 45 | + |
| 46 | + model = self.create_model() |
| 47 | + self.treeview = Gtk.TreeView(model=model) |
| 48 | + self.treeview.connect('row-activated', self.plot_row) |
| 49 | + sw.set_child(self.treeview) |
| 50 | + |
| 51 | + # Matplotlib stuff |
| 52 | + fig = Figure(figsize=(6, 4), constrained_layout=True) |
| 53 | + |
| 54 | + self.canvas = FigureCanvas(fig) # a Gtk.DrawingArea |
| 55 | + self.canvas.set_hexpand(True) |
| 56 | + self.canvas.set_vexpand(True) |
| 57 | + vbox.append(self.canvas) |
| 58 | + ax = fig.add_subplot() |
| 59 | + self.line, = ax.plot(self.data[0, :], 'go') # plot the first row |
| 60 | + |
| 61 | + self.add_columns() |
| 62 | + |
| 63 | + def plot_row(self, treeview, path, view_column): |
| 64 | + ind, = path # get the index into data |
| 65 | + points = self.data[ind, :] |
| 66 | + self.line.set_ydata(points) |
| 67 | + self.canvas.draw() |
| 68 | + |
| 69 | + def add_columns(self): |
| 70 | + for i in range(self.num_cols): |
| 71 | + column = Gtk.TreeViewColumn(str(i), Gtk.CellRendererText(), text=i) |
| 72 | + self.treeview.append_column(column) |
| 73 | + |
| 74 | + def create_model(self): |
| 75 | + types = [float] * self.num_cols |
| 76 | + store = Gtk.ListStore(*types) |
| 77 | + for row in self.data: |
| 78 | + # Gtk.ListStore.append is broken in PyGObject, so insert manually. |
| 79 | + it = store.insert(-1) |
| 80 | + store.set(it, {i: val for i, val in enumerate(row)}) |
| 81 | + return store |
| 82 | + |
| 83 | + |
| 84 | +def on_activate(app): |
| 85 | + manager = DataManager(application=app) |
| 86 | + manager.show() |
| 87 | + |
| 88 | + |
| 89 | +app = Gtk.Application(application_id='org.matplotlib.examples.GTK4Spreadsheet') |
| 90 | +app.connect('activate', on_activate) |
| 91 | +app.run() |
0 commit comments