Author Topic: How To Incorporate a GUI in C  (Read 9737 times)

0 Members and 1 Guest are viewing this topic.

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4039
  • Country: nz
Re: How To Incorporate a GUI in C
« Reply #25 on: March 08, 2024, 12:03:52 am »
For a more basic library, I'd suggest trying Dear Imgui : https://github.com/ocornut/imgui   wiki page here : https://github.com/ocornut/imgui/wiki

That does actually look quite useful, if you have OpenGL available.

Simple things look easy, and complex things are obviously possible, by the example screenshots.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6264
  • Country: fi
    • My home page and email address
Re: How To Incorporate a GUI in C
« Reply #26 on: March 08, 2024, 01:29:03 am »
Another cross-platform option in C is Simple DirectMedia Layer, aka SDL2, aka libsdl.  It is more commonly used with games rather than desktop applications, but if you want to do simple interactive stuff, it can be easier than the widget toolkits.  Plenty of guides and tutorials online, too.

I am aware of basically three widget toolkits you can use to create portable applications in C, without also depending on C++ or Tcl or some other programming language:
  • Gtk2 (old), Gtk3 (stable, old docs), and Gtk4 (new)
    Originating from GIMP, is the widget toolkit used in Gnome, Cinnamon, Mint, XFCE, and other desktop environments.  It uses its own look and feel in all operating systems, and is themeable.  There is an XML-based UI tool called Glade, and such UIs can be loaded and associated with functions dynamically at run time.  For Windows installation, see here.
     
  • Enlightenment (EFL; C API)
    Used by the Enlightenment desktop environment and some Samsung devices, including Tizen.
    I do not know if precompiled windows libraries and installers are easily available.
     
  • IUP
    Uses native Windows toolkit on Windows, and Gtk (or Motif/Lesstif) on Linux and macOS (not native on macOS).
I currently use Gtk3 in C, and Qt5 in Python.  Python 3 has Tcl/Tk support (tkinter and tkinter.ttk) as a standard module, "built-in", but I just like Qt better.  (My Python Qt programs can use either PySide2 or PyQt5 bindings, autodetected at runtime.)  However, I only use Linux, and do not have Windows licenses at all to even run in a virtual machine.
Gtk can be used from Python too, via gi, or gobject introspection, but I like Qt better.
IUP looks very interesting, if you want the native look and feel in Windows and Gtk-based desktops in Linux.  (It'll use the Gtk look and feel on macOS.)

Widget toolkits use an event-driven approach, in that you are not in full control of the program flow: you create structures (the UI or its basic framework) and pass the control to the library, which will then call your event handlers when it sees fit.
Object-oriented languages make these and extending the UI widgets easier, which is why there are so few widget toolkits written in C.

For heavy computation, I recommend using separate threads, and passing the tasks and the results between the worker threads and the UI thread via thread-safe first-in-first-out queues.  In C, this typically means pthreads aka POSIX threads.  They are surprisingly easy to use, and in e.g. Gtk, one can use the glib functions to insert events to the main event loop from other threads.  For example, if your worker thread sends one event when it starts processing, and another when it completes, you can use these messages to update the button state, instead of changing the button state only when clicked.  Essentially, you might have a pair of buttons forming a single element, where clicking on the "Do it! Do it!" button locks it down, with the "Cancel" button next to it popping up, and when the calculation completes, the "Do it! Do it!" button pops back up and the "Cancel" button gets grayed out, with the results displayed on-screen.  Each of these (button click, sending a message or triggering the work, work completion message) are all separate named events.

The same approach applies if you create simple static tool pages in HTML+JavaScript, to run in your browser, without requiring any kind of a server or a network connection, as the entire page and Javascript code is included in the HTML file (as source code).  There, you only need to use the window.setTimeout() method to start the "background work" as soon as possible, and not within the event handler, to have it be done in essentially a separate thread.  If you do it in the event handler, it will "freeze" the UI for the duration of your computation/work.   Browsers today have amazingly fast JavaScript interpreters/JIT compilers, so that is a very realistic way to do self-contained graphical tools.  The only limitation is that they cannot load or save files without a network server; you can only present it as text, and optionally copy the text to clipboard to be pasted into other programs.

In Linux, I use a simple Makefile for Gtk projects (that I only need to adjust slightly for each project).  Then, I can run make clean all && ./myprogram to clean the files generated by previous builds, rebuild the program, and run it, whenever I want.  Or, I could even run
    inotifywait -q -e close_write main-file.c -m | while read DUMMY ; do reset ; make || break ; done
to rebuild the code automagically whenever I save main-file.c, regardless of what editor I choose to use.

Adding anything Fourier or DCT-related, I do via the fftw3 library.  The trick with it is "wisdom", or previous knowledge on how a specific-size window is transformed most efficiently.  With pre-discovered wisdom, it is ridiculously efficient and fast even on large FFT window sizes.  It's what toolkits like numpy and scipy tend to use underneath, too.  (With Gtk, it is best to integrate the wisdom to the gtk application properties/settings.)

Integrated Development Environments or IDEs combine an editor, make-like project build management, and often a debugger interface and even a built-in git or other version management software client, in a single user interface.  It is not all a single program, just a single user interface.  Often, the main interface program calls external programs (like the compiler and the debugger) internally, receiving their output via a pipe, and optionally displays these in some window, or just on a status bar as a summary message (success/failure).  Because of the previous paragraph, I personally don't have any use for IDEs right now.

There is even a Gtk extension widget, GtkSourceView (provided as an add-on library to Gtk: 2.10, 3.24, 4.2, other versions, git), that provides a full syntax-highlighted text editor widget all-in-one, with most programming and scripting and mark-up languages' syntax supported out-of-the-box.
« Last Edit: March 08, 2024, 01:31:19 am by Nominal Animal »
 

Online bostonmanTopic starter

  • Super Contributor
  • ***
  • Posts: 1795
  • Country: us
Re: How To Incorporate a GUI in C
« Reply #27 on: March 08, 2024, 04:08:39 am »
Some substantial feedback has been provided and I'm only elaborating a bit on thoughts.

My problem is that I'm hardware far more than software. From experience, the best programmers I've come across are ones who have done programming for many decades so they have a good foundation. My background is C64 BASIC, some Pascal, a single course in C++ many years ago, and the rest is all seeing code from various languages. For example, I did some Assembly on these little boxes with seven-segment displays (if I remember correctly - but don't remember what they were or the model) way back when I also took Pascal and I've looked at HEX code many times on the C64 (keeping in mind I'm hardware and know binary, HEX, etc...).

So I can look at SOME codes and tell you which language it is. Just recently, long story short, I looked at Assembly Code someone created many years ago for a C64 game. I said to him, looking at the code, it looks like you're loading something into the accumulator, adding this, blah blah. He was impressed I could read the code, however, as I told him, I could only recognize a few lines and know very little.

Having said all this, I'm use to having the software "handed" to me meaning: I never had to incorporate tools or install modules to type/run a program. I'm used to BASIC just being there for me, or (I never did this) but loading a program where I just start typing BASIC lines without the need to install modules.

As I may have mentioned, the little C I've done hasn't provided anything "fun" to visualize. After getting past some of the first chapters in a C book, I found myself bored only getting results of "hello world" or performing some math calculations.

Attached is the type of GUI I think would be interesting to incorporate, but wonder what was used to create it since it runs on Windows. Without a GUI (as stated above) there isn't any visual feedback. The feedback is somewhat repetitive as in: I added two numbers in a C program, compiled, ran, got the answer, now I change the numbers, compile, run, etc...

Most likely things I'd like to create with a GUI are far more advanced such as reading data from a USB, sending data to a device (such as a circuit I built), or whatever, so maybe I'm dreaming a bit too big with the idea of GUIs. In general, I think spitting out the results of code looks far more better in a GUI than a black and white DOS screen. So I think "hello world" displayed in a GUI can open the doors to programming more elaborate programs than living in a DOS world.

 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 11653
  • Country: my
  • reassessing directives...
Re: How To Incorporate a GUI in C
« Reply #28 on: March 08, 2024, 05:13:12 pm »
C/C++ is only generic programming language, if you want GUI you need to embed OS's API into the programming, not an easy beginner level. i can only say about Win32 API because thats what i only learnt. if you want down to the metal programming in C/C++ for Windows i suggest old book https://www.amazon.com/Windows-Writing-Reusable-Schulman-Programming/dp/020160891X by Paul Dilascia and i've made a very basic Windows GUI "framework" (classes) with guidance from the book, so i can compile it from raw Ms VC++ 6 the old version. you can PM me if you interested in looking the framework just to see how the basic stuffs work. having doing the exercise i came to the conclusion the appreciation of already existing and most robust and complete framework such as Qt, Borland Windows C++ (now Embarcadero i think) or WxWidgets... i choosed Qt as my next IDE in C/C++ with Windows GUI if anything... but i dont have urgent need since i still can use my old VB6 to develop stuffs. fwiw.
Nature: Evolution and the Illusion of Randomness (Stephen L. Talbott): Its now indisputable that... organisms “expertise” contextualizes its genome, and its nonsense to say that these powers are under the control of the genome being contextualized - Barbara McClintock
 

Offline shapirus

  • Super Contributor
  • ***
  • Posts: 1369
  • Country: ua
Re: How To Incorporate a GUI in C
« Reply #29 on: March 08, 2024, 05:33:54 pm »
if you want GUI you need to embed OS's API into the programming
...and that's exactly where you lay the foundation of your program being impossible to port to other operating systems at a later time when you need it.

Portability is one of the goals of GUI toolkit libraries such as Qt, GTK and many more. With them you don't need to call OS API functions, you only use the interface of the library, which is (ideally) independent of the operating system.
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 11653
  • Country: my
  • reassessing directives...
Re: How To Incorporate a GUI in C
« Reply #30 on: March 08, 2024, 05:59:03 pm »
if you want GUI you need to embed OS's API into the programming
...and that's exactly where you lay the foundation of your program being impossible to port to other operating systems at a later time when you need it.

Portability is one of the goals of GUI toolkit libraries such as Qt, GTK and many more. With them you don't need to call OS API functions, you only use the interface of the library, which is (ideally) independent of the operating system.
i was talking down to the metal programming for exercise and experience feel... more robust cross platform such as Qt will have another classes/macros on top to check on which OS it is operating and divert class path and chain accordingly, underneath are few OSes classes/platform like the basic one i was exercising. the exercise was a good one to get a grasp of how complicated to develop a complete system such as Qt, not a one man job.
Nature: Evolution and the Illusion of Randomness (Stephen L. Talbott): Its now indisputable that... organisms “expertise” contextualizes its genome, and its nonsense to say that these powers are under the control of the genome being contextualized - Barbara McClintock
 

Offline shapirus

  • Super Contributor
  • ***
  • Posts: 1369
  • Country: ua
Re: How To Incorporate a GUI in C
« Reply #31 on: March 08, 2024, 07:24:42 pm »
i was talking down to the metal programming for exercise and experience feel...
Yeah that is definitely a useful practice, which some may find interesting enough to choose as their primary area. But as usual, it's important to choose the right tool for the job. For embedded systems, for developing cross-platform libraries -- yes, you quite rightfully need to interact with the target system on a low level. For developing a generic app which does not need to be closely coupled with a specific platform... then a cross-plaform toolkit is a better way to do it.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6264
  • Country: fi
    • My home page and email address
Re: How To Incorporate a GUI in C
« Reply #32 on: March 08, 2024, 09:38:55 pm »
After getting past some of the first chapters in a C book, I found myself bored only getting results of "hello world" or performing some math calculations.
This is an universal problem for anyone interested in using programming as a tool to achieve a purpose, instead of learning it for the fun of it.
Getting nice visual and sonic feedback from the code you write is an important way to keep your motivation high.  (With dopamine kicks!)

My recommended solution is not to try and incorporate everything into the C program, simply because I do not do that in the real life either.  Instead, use it for the interesting bits, and pipe the inputs from and outputs to useful sonification or visualization tools.

The main ones I recommend, are
  • Gnuplot.  Program output consists of points, which will be visualized into plots – curves or surfaces – by a simple gnuplot command.  Typically used with math stuff, like approximate functions, comparing your own fixed-point math implementation against the native floating-point implementation, and so on.
     
  • Graphviz.  Program output is DOT language text, describing graphs or directed graphs, including trees and forests.
    This is particularly useful for visualizing nested function exection, and many different types of data structures from heaps, trees, linked lists, to hash tables, disjoint-set data structures, and so on.
     
  • Netpbm tools.  Program output is an image in one of the very easy-to-use formats (PBM/P4 for bitmaps, PGM/P5 for grayscale images, and PPM/P6 for full-color images).  If directed to a file, the output can be opened in Photoshop, GIMP, and many other image editors.  Netpbm is a collection of utilities to convert the images to and from these formats.  For example, if your program modifies an image, you use netpbm tools to convert the input images, losslessly, to the corresponding PBM/PGM/PPM format, then does the pixel manipulation, and outputs the modified image as PBM/PGM/PPM format, which can then be converted to whatever format you like.  To load and save these images correctly, you only need a simple header file implementing a couple of functions; not even a library.  You can also write your own functions easily to do this with the tools you normally use, although they will typically be much less portable.
     
  • SVG 1.1.  This is the file format browsers support for describing vector graphics.  For example, the graphics on my home page is a simple SVG image embedded in the HTML file, all in plain text you can see if you view the page source.  If you save or redirect the output to a file, you can open the generated image in any browser.  I use this to generate vector graphics representations and diagrams, especially using 1:2 isometric perspective for 3D objects.  (The math for that is trivial, and you've seen similar in pixel art games already.)
     
  • aplay -f S32_LE -c1 -r48000 or paplay --format=s32le --channels=1 --rate=48000 to play mono sound at 48000 samples per second, each sample being a int32_t.  This is the easiest way to generate sounds.  If you intend to use low-quality audio reproduction on a microcontroller, you can use -f U8/--format=u8 instead, in which case each sample is an unsigned char, between 0 and 255, corresponding roughly to various PWM and PDM methods to generate an unipolar (0 to Vcc) audio signal.
For interactive stuff, I wholeheartedly recommend starting with Curses (especially ncursesw) for terminal stuff.  ncursesw supports Unicode glyphs, so that when you use a good-coverage font in your terminal, you have much more than the DOS cp437 old-style ANSI graphic characters.  You can also use the ANSI escape sequences to colorize your terminal output, although for unbuffered input you need to do more work.  Yes, this is the "DOS-like" stuff, but it is much simpler than other GUI approaches.

One of my favourite examples is to combine a maze generator and a singleplayer maze game in a Curses application, as a minimal start to old Rogue-like games.  (NetHack ring a bell?)

When using Curses "DOS-like", you still have the full control of the program flow.  When you move to Gtk or other GUI widget toolkits, you must relinguish the full control, and switch to event-driven model.  Essentially, the GUI toolkit will be given full reign of the control flow, and it will simply call some of your functions when necessary.  You cannot do "delay for 50 milliseconds" anymore, you instead must use an interface to say "after 50 milliseconds or more have passed, please call this function, toolkit".  While Gtk is pretty easy to use if you have experience in C, combining learning C and the event-driven model into a single learning step seems a bit risky/harsh/difficult to me.

Unfortunately, all of this is much easier in Linux than in Windows, because you basically have everything you need for these installed in Linux, or can get them installed in with just a few clicks (or a single command-line command starting with sudo apt install or sudo rpm install), as everything is provided in standard software repositories for all Linux distributions.  It helps that everything, even Curses documentation, is available as man pages, so a simple man function or man -k topic will usually provide you with details on what you seek.  I often also have a web browser open at Linux man pages project and whatever library pages or other documentation I use, since memorizing details is wasted effort (and only risks bugs when one remembers the details wrong).

I have not had an opportunity to work with anyone learning game programming via SDL2 (which is C and highly portable, used for the basis of many, many 2D games), but as I mentioned earlier, it is another possibility.  It is somewhat event-driven, too, but with focus on near-realtime and similar, as is needed by typical games.

I used to do some volunteer tutoring/bugfixing for STEM students having Linux laptops, and it was fun to see how fast they progressed from using the default tools to adjusting everything for maximum personal comfort/productivity, and concentrating on getting the task at hand done (learning programming, and using various computational tools from computer algebra to numeric calculation to running distributed simulations on the local HPC clusters).  Many of them were not interested in Linux at all, and only used it as a tool to get things done.  I think that is a very good, very useful attitude.  Linux has no value to me unless I can use it to achieve something interesting or useful to me.

So, my suggestion would be to install some Linux distribution, perhaps Linux Mint, in a virtual machine in your Windows, and do this stuff there.
Or, if you happen to have an old laptop not grunty enough to run Windows anymore, install Linux on that.  (I use a 6+ year old EliteBook 840 G4 with a Core i5 7200U, and it is plenty grunty enough.)

Otherwise, you'll need advice from others who used Windows to learn C programming.  My own experience with such persons is from a decade ago (I havent used Windows in anger for longer than that, even though I used to use and even administer a network of Windows machines over two decades ago), but it was consistently... not positive.  They hadn't learn C per se, they had learned the Microsoft way, and had big trouble learning portable stuff (especially anything POSIX.1, which is absolutely useful), basically because they needed to unlearn Microsoft-specific details and truths they had learned without noticing, having learned to assume them to be axiomatically true everywhere; and now, they had to replace that with new learning.  Unlearning is harder than learning, so it ended up being 2× or more difficult for them.
Those who had more than one OS available, and were used to the idea that a fact in one is not necessarily a fact in the other, even though they are very similar –– just have differences in approach and interface details –– had it much, much easier, because they didn't need to work on the "unlearning" part.
Old C64 and DOS plus Windows gives you already a much better starting point, although mixing in some macOS and perhaps Linux would not hurt.

For best advice, I recommend you listen to someone who uses Windows to write C code for both hosted (Windows or other OS) stuff, and for programming microcontrollers.  Like I said, my observations are dated and negatively colored; someone having done that successfully will be more use to you.

When you get the basics of C down, you'll find it rather straightforward to progress to Gtk+ (or the other widget toolkits, or to SDL) to do GUI stuff, if you want to.  The main step there is relinguishing control of the program flow to the toolkit/library, and the associated change in thinking/code-structuring/design approach.

I often don't go that way, because I prefer doing the user interface in Python –– requires no compilation, lets end users easily tweak UI details without knowing much about programming –– with any heavy computation or trickery or proprietary stuff implemented in a native library, C code compiled to a shared library, that is accessed via the Python ctypes module.  This is quite portable, too, as long as the shared library is compiled for the target architecture and OS.
That said, I have written Gtk+ GUI apps in C for specific useful cases.  There should be a skeletion of a VU meter here somewhere, for example.

For connecting to microcontrollers, I currently use USB Serial, and in Linux, macOS, BSDs the termios interface; not any library.  (I'm particularly unhappy with libserial, libusb, etc.; they seem to work for many, but having taken a careful look at their code, I don't trust them at all.)
This applies to both C code and Python GUI code.  Unfortunately, it is not portable to Windows.

I *often* play with USB HID devices, like keyboards, mice, joysticks, gamepads, etc.  The Linux interface is truly simple, a single one covers all, and if you want, you can easily synthesize one using a simple (privileged) application.  This is why I much prefer microcontroller development boards with native USB interfaces.  My preferred one is USB Serial + USB HID endpoints on the same device.  (There are several 8-bitters from CH552G to ATmega32U4 capable of this.  Teensy 4.x can provide data over USB Serial at 25+ mbytes/sec, or 200 Mbit/s, as it supports USB 2.0 High Speed (480 Mbit/s); most only support Full Speed (12 Mbit/s).)

For bulk and isochronous transfers, I like to use the Linux-specific "usbfs".  It is not a filesystem, just a device interface for the "raw USB device", without any kernel or userspace driver at all.  It is what libusb typically uses under the hood, but in a way I find much less than optimal.

The one key "trick" in Linux is to add an udev rule that permits your user account or group it belongs to, full access to the device.  That way there are no privilege issues.  It is common to forget to do this or skip this as "I'll do it later, as I just want to test this for now", and then complain about all the access- and insufficient privilege-related problems they encounter, and how difficult everything seems to be.
I even use my own wrapper around avrdude, so that when programming my ATmega32u4 (Pro Micro clones off eBay, using the Arduino Leonardo bootloader), the wrapper script resets the target microcontroller, and waits for it to appear, and reprograms the appearing one; regardless of what port/device was selected in the Arduino UI, because that way I avoid the occasional case when the OS changes the microcontroller "USB address" or device node, when the microcontroller is reset/rebooted.
Teensies have their own GUI-based utility which works solidly for me, but there is also a command-line one available at Paul Stoffregen's GitHub.

A few years ago, I mentioned in another thread here that I was thinking of creating a course on how to interface microcontrollers (via USB Serial and USB HID) to a GUI program written in Python for Linux, BSDs, and macOS, but it fell through.  I don't have anything written down, but as it is something I often do, I have lots of ideas on how to do this, starting from manipulating leds and relays on the microcontroller, to transferring intensive amounts of ADC'd data and processing them using FFT or similar (using e.g. fftw3).
« Last Edit: March 08, 2024, 09:44:41 pm by Nominal Animal »
 

Offline Zipdox

  • Regular Contributor
  • *
  • Posts: 170
  • Country: nl
Re: How To Incorporate a GUI in C
« Reply #33 on: March 09, 2024, 04:25:07 pm »
Making a one-off GUI in C is not that hard.
The hard bit is making a "reconfigurable" GUI. One that is flexible so you can easily add new menus and items and controls later with almost zero effort.
Let me introduce you to https://en.wikipedia.org/wiki/Glade_Interface_Designer
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14487
  • Country: fr
Re: How To Incorporate a GUI in C
« Reply #34 on: March 09, 2024, 09:32:17 pm »
After getting past some of the first chapters in a C book, I found myself bored only getting results of "hello world" or performing some math calculations.
This is an universal problem for anyone interested in using programming as a tool to achieve a purpose, instead of learning it for the fun of it.
Getting nice visual and sonic feedback from the code you write is an important way to keep your motivation high.  (With dopamine kicks!)

Yeah, the immediate reward problem I mentioned in another thread. This isn't doing us any good.
Sure some level of reward helps, but do not look for too much initial reward when learning something new, because it is a very sure way of getting bored very quickly.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6264
  • Country: fi
    • My home page and email address
Re: How To Incorporate a GUI in C
« Reply #35 on: March 09, 2024, 10:50:00 pm »
Sure some level of reward helps, but do not look for too much initial reward when learning something new, because it is a very sure way of getting bored very quickly.
True, too.  (The underlying issue is that when you already have a purpose in mind, and getting there takes several steps, you do need some feedback to keep your motivation up.  Otherwise the sucky part of the learning curve can suck more than one can handle.)

You could say my suggestion is more about lowering the amount of programming to get to that feedback in modest amounts, in a way that will be useful in the future too.  Even Curses interfaces are useful on headless appliances and SBCs, when you use a SSH connection to the device.

I at least do not incorporate plotting libraries and whatnot in my C code, because I do all that with less effort using existing effective external command-line tools, that support many use different cases, letting me achieve each task by combining different tools with less throwaway programming.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf