[ANN] CImGui.jl - A Wrapper for Bloat-free Immediate Mode Graphical User interface(Dear ImGui)

Had seen references to it but didn’t realize the effects of that continuous recreation were so drastic.

Just gave this a try combined with ImPlot.jl and I’m really impressed with how responsive it is. Also, it seems I can run the loop on a background thread. I wrapped the examples in https://github.com/wsphillips/ImPlot.jl/blob/master/demo/example_plots.jl in a function and called it with Threads.@spawn and it all worked like magic. This seems like a real advantage over other plotting / UI libraries for Julia.


Could you share the example code? I got a crash on my machine. I guess I just did something wrong when using Threads.@spawn.

 2020-08-30 10:40:44.470 julia[42621:627679] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1677.104/Foundation/Misc.subproj/NSUndoManager.m:363
2020-08-30 10:40:44.471 julia[42621:627679] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.'
*** First throw call stack:
libc++abi.dylib: terminating with uncaught exception of type NSException

signal (6): Abort trap: 6
in expression starting at none:0
__pthread_kill at /usr/lib/system/libsystem_kernel.dylib (unknown line)
Allocations: 7965270 (Pool: 7963320; Big: 1950); GC: 7
[1]    42621 abort      julia

Sure. It might be platform dependent.

You can see what I tried in this gist which I adapted from the ImPlot.jl example.

I tested on Julia 1.5.0 on Windows 10 (20H2).

If that doesn’t work for you, you could use @async instead and put yeild() at the end of the event loop. Not multi-threading, but at least it runs in the background.

Looks like this doesn’t work on macOS. Maybe this is due to CImGui.jl isn’t thread-safe, will try to fix it later.

update: it turns out to be a GLFW limitation: https://discourse.glfw.org/t/which-thread-for-handling-opengls-window/871/2

1 Like

Works fine in Julia 1.5.0 on Ubuntu. Very impressive!

1 Like

Here’s how my oscilloscope GUI works so far. I’m very happy with CImGui and ImPlot!


Wow, I have been thinking of trying this for a long time! Is this via serial or GPIB?

You can find the code here. The gui is somehow separate from the instrument driver, I still have to tidy things up.
The gif above is the gui actually connected to a Lecroy HDO6054 via USB( not the TDS2002 in the repo).
The Lecroy setup has decent refresh rate, depending on the size of the waveform( this one was tested with only 5k samples).
I’m struggling however with the TDS2002(also USB), which has 100ms delay for every command I send. Fetching a waveform (2500 pts) for one channel takes 1 second and it’s driving me crazy. I don’t know if it’s the scope that is slow or if I have a problem with the computer( it’s a different computer than the Lecroy setup, some old core duo laptop), but other instruments exhibit this behavior as well…

Many thanks! I misread the oscilloscope type and thought it’s older series, of course USB nowadays.

This is because on macOS the GUI must run on the application main thread, I hit the same problem in QML.jl, and presumably Gtk.jl would be similarly affected. Maybe we should figure out a way to keep the main thread free for this kind of application?

I guess at least we should notify those Mac users to always run GUI code on the main thread. Is it feasible to define a function that will throw the warning when called with Threads.@spawn?

How are you talking via USB using Julia ?

I have this VISA wrapper: https://github.com/iuliancioarca/GenericInstruments.jl


That makes sense. Interesting that some platforms don’t have that same restriction.

For keeping the main thread free ThreadPools.jl works very well. I normally use either @bthreads macro or bmap. The one thing missing is something like @bspawn to launch a single task on a background thread, but @tspawnat 2 works well enough.


So I just asked a question on your package’s GitHub discussions after seeing your post there @Gnimuc. A suggestion - if that’s where you’d prefer Q&A etc to go then maybe mention this in the README in order to direct people there?

CImGui looks really awesome, BTW. I’m especially excited that it seems that it may be possible to integrate Makie.

1 Like

Github discussions and Julia discourse are both fine to me, when asking general questions about CImGui on discourse, feel free to ping me if I missed that post.

SteffenPL has an example in thie post:

Hey @Gnimuc, first off, thanks again for this package.

Quick question. You provide a Renderer.jl

For myself, when I’m using coroutines or threads in Julia I control the exit by having the corouting or thread running on while run_flag[] where run_flag is a Threads.Atomic{Bool}.

From your Renderer.jl, I see that you do something that feels similar, but I don’t really understand it. This line:

How can I set GLFW.WindowShouldClose(window) to true, so that the renderloop exits?

Thank you.

EDIT: I just checked, and I can use my solution alongside yours by replace your while with while run_flag[] && !GLFW.WindowShouldClose(window). However, this solution A) makes me feel like I’m missing something, and B) it skips the finally, so maybe it’s not cleaning up properly…?

GLFW should responsible for returning that value when users close the GLFW window(IIRC, either by clicking the [x] button or pressing Esc?).

Ahhhhh I understand. That doesn’t work for me, but maybe that’s because I’m using i3wm, which is a bit unusual in that respect.

Thank you!

EDIT: fot future reference, it DOES work with i3wm, you just have to use the keyboard instead of the mouse: Pressing ALT+SHIFT+Q will correctly trigger WindowShouldClose(window).

1 Like