Ask HN: Where are the GUI libraries that aren't bloated?

56 points by ErotemeObelus ↗ HN
It takes fifty lines to create a dialogue with a button.

Why?

Is there some kind of theorem in computational complexity that this is a strict lower bound?

52 comments

[ 2.7 ms ] story [ 102 ms ] thread
tcl/tk was the X Windows answer to visual basic.

Simple dialogs are very simple with tcl/tk. No matter what you do, however, it is going to look awful and people will give you grief about it. Dealing with window resizing, scrollbars, and the like may also make you cry.

i've used themed tk (ttk) via python's tkinter.

It looks almost nice, and generally nice enough that people didn't realize immediately it was tk (that says a lot, considering how ugly tk is).

Take a look at REBOL. This one-liner opens a window with a form that accepts an email address and url, downloads the web page contents and emails it to said address.

  view layout [u: field "user@rebol.com" h: field "http://" btn "Send" [send to-email u/text read to-url h/text alert "Sent"]]
They don't exist. I've seen good things relating to this Red language, but have fun learning a new language when you really just want to make a program you've already written graphical.

Try learning the unreasonable class hierarchies of Gnome or Qt, if you want to write a graphical application in most languages; there are several tomes covering X11 and Motif and, if you bother to learn those now, just remember that Wayland's been right around the corner for over a decade now.

Every other option is either unsuitable, unmaintained, or something else. The terminal is also poorly used in UNIX: you can't get key modifiers for everything, since it's all sent as plain characters; there are several competing conventions for reporting mouse codes, all broken in different ways; instead of using the FUNCTION KEY control sequence, which scales to however many you need, Xterm and cohort send baroque sequences with no pattern, instead; and, lastly, extended color codes are broken, because Xterm implemented its own standard before someone read the real one and then it implemented the real standard incorrectly, with the other terminals following its lead as if lemmings, because they probably never saw the standard at all, and now it's too ingrained to implement properly, so just send the wrong codes, right?

It's all utterly broken and it's disgusting. I want you to take notice of how much visual garbage is in Unicode. Now, part of that is to encompass other character sets, but consider that, since the GUI and everything else is so utterly broken, why not make the character set the GUI toolkit? That seems to be what's been done, and who needs a real GUI system when you can send cute Unicode glyphs back and forth?

Big problem with OOP: "let's create a new type!"

Functional programming is extremely unnatural. I am using "unnatural" in the same sense of how the Bible considers sodomy to be an extremely unnatural sex act. Yes, functional programming is the sodomy of programming. No state? Except for inherently-declarative paradigms like databases or spreadsheets, this is 100% inappropriate for any programming.

But yet there is a reason why so many intelligent people like functional languages like ML, F# or the theorem-prover Haskell. They have expressive type systems that don't degenerate into a big ball of mud, because they're based on the lambda cube. If someone took javascript and added product types, sum types, dependent types, polymorphic types... they would drop OOP.

Just go the electron route and find a way to make it snappy in-spite of electron (ala vs code)
I'd love to know how Microsoft gets Electron as performant as they do.
> Just go the electron route and find a way to make it snappy in-spite of electron (ala vs code)

This in reply to the question: Where are the GUI libraries that aren't bloated?

I'm gasping for breath.

I get your point, but the question seems to be about code bloat, not RAM.
Tkinter for python seems pretty concise. I'm not an expert with it. Looks prettier than I remember tcl/tk to be.
Tkinter is Tcl/Tk, nothing more or less.
> It takes fifty lines to create a dialogue with a button.

In Tk/Tcl it takes one line if you want a simple dialog with a button:

      tk_dialog .d1 "Dialog Title" "Dialog Text" "" "" "Button Text"
Creating your own custom dialog takes a few more lines (obviously), but nothing close to fifty lines for just some text and a single button.
FLTK is the classic lightweight toolkit. Their "Hello world" example from the documentation is 15 lines[1]. Possibly more importantly it is also very lightweight in terms of memory footprint, the docs advertise[2]:

> * The "core" (the "hello" program compiled & linked with a static FLTK library using gcc on a 486 and then stripped) is 114K.

> * The FLUID program (which includes every widget) is 538k.

While that is pretty neat, I do feel like there would be place for the true graphical equivalent of ncurses; something both equally fast/lightweight, and as simple to code.

[1] https://www.fltk.org/doc-1.3/basics.html#basics_writing

[2] https://www.fltk.org/doc-1.3/intro.html#intro_features

I think I discovered the problem with GUI libraries. They mix configuration with component logic.
Can you elaborate?
You have to specify a bunch of information regarding the width, height, color, positioning in the call of the function. There isn't anything analogous to css in programming languages so you're left with a big ball of mud.

HTML+css is the easiest GUI toolkit to learn to date. It's so easy that young children in middle school are taught it in their web elective classes. And one reason it is so easy is because there is something like css.

I used this for a small project where I needed a quick GUI interface and it was great to use. I just made the GUI using FLUID and linked the buttons to my code. And I was able to compile it statically to all 3 OSes without too much trouble. Plus it's fast.
If you’re on a Mac, AppleScript is pretty short.
What platform? In iOS, you can make a button in a few lines. There is more code to add it to the View Controller.
Yeah, I understand the pains of implementing native GUIs, but one of the niceties that they provide is that you can implement simple - moderately complex GUIs in fewer lines and cleaner APIs than what the cross-platform libraries provide.
> It takes fifty lines to create a dialogue with a button.

It's not true for both Qt and GTK+.

I've used Qt and wxWidgets[1], and found them both great.

They both also have bindings for many languages, and it certainly doesn't take fifty lines to create a dialog with a button using any of them.

[0]: https://www.qt.io

[1]: https://www.wxwidgets.org

Delphi might be one of the rare exceptions.
Or lazarus, if you don't mind a slightly less-polished experience
Try an immediate mode GUI. e.g. Dear Imgui[0].

[0] https://github.com/ocornut/imgui

Here's the code to draw a slider whose value is stored in a float:

    float f = 0.5f;  
    ImGui::SliderFloat("my float", &f, 0.0f, 1.0f);
edit: A lot of the problem with GUIs taking so much code is that they duplicate the application's state, requiring a large amount of effort to keep that state synced with their internal state. By instead binding directly against the user's state you can avoid much of the overhead.
I looked at Imgui before for a project, but decided not to go with it since the examples are all over a hundred lines long, for example:

https://github.com/ocornut/imgui/blob/master/examples/exampl...

It seems like there is a lot of setup / configuration code necessary to wire up Imgui with the graphics rendering back-end.

Note that I haven't used Imgui in a real-world project yet. Does anyone know of a better way to set-up Imgui that does't need all this configuration code?

Most of that code is incompressible to make a portable OpenGL app in C++, not really Dear ImGui's fault.

There's literally about ~10 lines of specific imgui code in there other than the 35 lines of example code in the middle of the main function.

Your problem is perhaps that you don't want to engage in actually reading that code.

I just built a couple things in Go using the Go bindings for Nuklear[0] - most of my GUI work so far has been with wxWidgets in C++/Python and I was very pleasantly surprised at how straightforward building the GUI was.

[0] https://github.com/golang-ui/nuklear

I think the question of "Why does it takes fifty lines to create a dialogue with a button" is very programming-language dependent:

If you're working with a higher-level programming language, you can make cross-platform GUIs very easily (see tkinter + python as others have recommended) without having to write 50 LOC.

If you're working with C / C++ specifically, then your bottleneck really is figuring out how to build and link with your cross platform library across all platforms. In my experience that has been much more painful than the lines of code required to set up a GUI in C++.

Once you've got the build/deployment system working in C++, most GUI libraries don't need as much as 50 lines of code. For example, even with Qt this is the code to get a dialogue with a button:

    #include <QApplication>
    #include <QPushButton>

    int main(int argc, char **argv)
    {
     QApplication app (argc, argv);

     QPushButton button ("Hello world !");
     button.show();

     return app.exec();
    }
In newer low-level languages with sane standardized package managers, like Rust, things should be much better, but I'm finding any good examples right now
Especially, it takes one line in almost all toolkits to create Standard dialogs such as

   window.alert("Hello world");
You can show such windows even from the terminal in Powershell, Linux, OS X. With one line of code.

It's not everything so broken...

A message box is not the same as a dialog with user controls.
All major toolkits have confirmation modal windows, input modal windows, etc as single line "calls". Of course it's not a "custom window" but it is one.
Consider looking at the Inferno operating system / virtual machine: you can use Tk from the command line. If you like Google Go or Plan 9 you will love Inferno.

http://inferno-os.org/inferno/papers/sh.html

See how simple it is to draw a button:

load tk wid := ${tk window 'My window'}

fn x { args := $* or {tk $wid $args} { echo error on tk cmd $"args':' $status } }

x button .b -text {A button} x pack .b -side top x update

There's IUP for light stuff. Lua-related, but eminently usable via c api.

http://webserver2.tecgraf.puc-rio.br/iup/

Of course there always was and ever will be the incomparable Tk from before the world went bonkers. Some commenters here seem stuck with the idea that Tk is 'ugly'. And true, it used to be. Sometime last century.

That the phone platforms chose to break entirely with all established practice from the desktop world, that is a tragedy still fully blown with us.

(comment deleted)
Having experimented down the rabbit hole of GUIs, it is essentially a flexibility trade-off. If you want something to look and feel just right way for the user (ie. not programmer) to easily interact with, it turns out to require endless customisability. The GUI framework to accommodate customisability requires a fair amount of boilerplate and some more to accommodate different platform semantics.

I basically ended up concluding that any time I need a GUI on desktop, I'll just use browser/electron + React/Material Design which is pretty much the ultimate in customisability. I found this not only simplified my life as a programmer, it also resulted in more intuitive to use and better looking programs. There are very few use cases where sticking with traditional Desktop visual semantics and maintaining a uniform look with system apps is actually a usability advantage.

> It takes fifty lines to create a dialogue with a button. Why?

Because it isn't just a dialog with a button. You need to specify the element positions, resize behaviours, tool tips, separators, element selection, animations etc. The deeper you dig into UI design the more you see the "bloat" being justified.

I've seen an interesting demo a few weeks ago for calling GTK directly from CL without binding/libraries:

    (load "./demostuff")
     
    (defun gtkapp ()
      (sb-int:set-floating-point-modes :traps '(:overflow :invalid))
      (gapp testgtk
        (window win testgtk "Test" 400 200)
     
        (box v outerbox1 win)
        (box v mainbox1 outerbox1)
        (box h buttons1 mainbox1)
        (box h numbox1 mainbox1)
        (box h leftbuttons1 buttons1)
        (text num1 "Press the OK button." numbox1)
        (button b1nw "OK" leftbuttons1 (xtext num1 "Button pressed."))
     
        (gtk_widget_show_all win))
      (g_application_run testgtk 0 nil)
      (g_object_unref testgtk))
This is enough to create a window with a button and a text object, in less than 20 lines.

The "demostuff" part contains a few function and macros that are used in the author's demo. The zip archive distributed in his GitHub page[0] also contains a dumped SBCL image at around 40 MB and a script to build it for people who want to try it without installing SBCL. Not small in absolute terms but, even without function tree-shaking, its size can be reduced with core compression to a little more than 10 MB (12MB on my Debian installation, your SBCL needs to be built with "--with-sb-core-compression"), anyway still an order of magnitude smaller than Electron... ^__^;

[0] https://github.com/mifpasoti/Gtk-Demos

I think Racket has a pretty sensible GUI kit. A little Hello-World dialogue box looks like this:

    #lang racket/gui
    (require racket/gui/base)

    (let* ((frame (new frame% (label "Hello, world!")))
           (msg (new message% (parent frame)
                     (label "Hello, world!")))
           (btn (new button% (parent frame)
                     (label "Exit")
                     (callback (lambda (b evt)
                                 (exit))))))
      (send frame show #t))
The first two lines just tell Racket what language you're using, and conjure up the GUI library. Then, each definition of the let statement is a control you need, supplying its properties; the body of the let statement shows the window frame. I find it simple and obvious, but I've only been able to use it in anger a couple times.