Asynchronous UI
It is possible to perform background computation without interfering with user interface responsiveness either using multithreading or using separate processes. Use of a separate process includes slightly more overhead but also ensures user interface responsiveness more robustly.
Here is an example using threads. Notice that this example will freeze the UI during computation unless Julia is run with two or more threads (julia -t2
on the command line).
using Gtk
btn = GtkButton("Start")
sp = GtkSpinner()
ent = GtkEntry()
grid = GtkGrid()
grid[1,1] = btn
grid[2,1] = sp
grid[1:2,2] = ent
signal_connect(btn, "clicked") do widget
start(sp)
Threads.@spawn begin
# Do work
stop_time = time() + 3
counter = 0
while time() < stop_time
counter += 1
end
# Interacting with GTK from a thread other than the main thread is
# generally not allowed, so we register an idle callback instead.
Gtk.GLib.g_idle_add(nothing) do user_data
stop(sp)
set_gtk_property!(ent, :text, "I counted to $counter in a thread!")
Cint(false)
end
end
end
win = GtkWindow(grid, "Threads", 200, 200)
showall(win)
Here is an example using a separate process to offload the work. This toy example is fairly straightforward, but things can get more complex if the offloaded task is more complex. See the manual for details.
using Gtk, Distributed
btn = GtkButton("Start")
sp = GtkSpinner()
ent = GtkEntry()
grid = GtkGrid()
grid[1,1] = btn
grid[2,1] = sp
grid[1:2,2] = ent
id = addprocs(1)[1]
signal_connect(btn, "clicked") do widget
start(sp)
@async begin
# Offload work to a separate process and block until it is done.
counter = @fetchfrom id begin
stop_time = time() + 3
counter = 0
while time() < stop_time
counter += 1
end
counter
end
# We are still in the main thread so it is okay to directly access widgets
stop(sp)
set_gtk_property!(ent, :text, "I counted to $counter in a separate process!")
end
end
win = GtkWindow(grid, "Distributed", 200, 200)
showall(win)