1

Here's a minimal example to illustrate the problem. When the button is clicked, 500 TextView objects should get added, each containing some text. What actually happens is that there is a short delay, 500 empty TextViews get added, there is a much longer delay and then they all get populated with text at once and the layout sizes itself properly. Code below:

import gtk.Button;
import gtk.Main;
import gtk.MainWindow;
import gtk.Notebook;
import gtk.ScrolledWindow;
import gtk.Statusbar;
import gtk.TextView;
import gtk.TextBuffer;
import gtk.UIManager;
import gtk.VBox;
import gtk.Window;

import std.stdio;

class UI : MainWindow
{
  Notebook notebook;

  this() {
    super("Test");
    setDefaultSize(200, 100);
    VBox box = new VBox(false, 2);
    notebook = new Notebook();
    Button button = new Button("add lines");
    button.addOnClicked(&addLines);
    box.packStart(notebook, true, true, 0);
    box.packStart(button, false, false, 2);
    add(box);
    showAll();
  }

  void addLines(Button b) {
    VBox box = new VBox(false, 2);
    for (int i = 0; i < 500; i++) {
      auto tv = new TextView();
      tv.getBuffer().setText("line");
      box.packStart(tv, false, false, 1);
    }
    ScrolledWindow swin = new ScrolledWindow(box);
    notebook.add(swin);
    showAll();
  }
}

void main(string[] args)
{
  Main.init(args);
  auto ui = new UI();
  Main.run();
}

Edit: this thread suggests that creating a bunch of text views is intrinsically expensive, and that I should be rewriting using a treeview.

Martin DeMello
  • 11,876
  • 7
  • 49
  • 64

2 Answers2

2

GTK is event-driven, and uses a message pump. If in a callback you do a lengthy operation, you never give a chance to the message pump to process the pending messages. You could replace the code in your callback by a sleep of 2 seconds, the effect would be the same: the UI would be frozen during that time slice.

If you can't split up your actions, use the d equivalent of what is described in gtk_events_pending documentation:

/* computation going on */
...
  while (gtk_events_pending ())
      gtk_main_iteration ();
...
/* computation continued */

Called between each of your loop iterations, it will give some time to GTK to process the events you generated by adding your widgets.

liberforce
  • 11,189
  • 37
  • 48
  • why are empty textviews ever displayed, though? the textview.getbuffer.settext() calls come before the vbox.packstart(textview), so even if there was a delay in adding the textviews i'd expect them to appear fully populated. also why is adding 500 textviews so slow? it doesn't seem like an overly large number, and i don't remember having the same issue in gtk2/haskell. – Martin DeMello Apr 25 '12 at 20:46
  • i tried using gtk_events_pending, and it does keep the ui responsive, but slows loading down even more. – Martin DeMello Apr 26 '12 at 06:10
  • doh - i just realised my old haskell code where i was doing something similar was using GtkEntry rather than GtkTextView. so it looks like 500 textviews *is* excessive. – Martin DeMello Apr 26 '12 at 07:22
1

After some more googling and experimenting, it turns out that GtkTextViews are intrinsically expensive to instantiate, and I should not have been trying to create so many of them. As per the advice in this thread I will be reworking my code to use a GtkTreeView instead.

Martin DeMello
  • 11,876
  • 7
  • 49
  • 64