I have an embedded Linux C application that runs with a simple CLI. I am now tasked with creating a GUI that accomplishes the same functionality as the command line program. I am not an accomplished GUI designer and the majority if my experience is in deeply embedded C coding.
My initial thought is to use qtcreator to create the GUI, but there are several issues I’m ruminating over.
- Moving forward I want to maintain both the CL program and the GUI program, and preferably even have them be the exact same executable that can be launched in either mode. Unless this is a bad idea?
- My code is in C so far, and qt is natively c++
- I would like a direct correlation where button presses in the GUI call the same functions that I call from the CLI
- How do I best do this cleanly and efficiently? Is there some other thecnology or library that simplifies this? I don’t have to use qt if there is something better.
2
I could give you some rough guidelines as to how to create the equivalent GUI for a CLI app, design-wise. How you would actually make the calls is out of the scope of this answer.
- switches like -p -v etc are checkboxes
- mutually exclusive options are a group of radio buttons
- parameters that are a filename are a textbox with a “choose” button that shows a choose file dialog box when pressed
- string parameters in general are textboxes
- number parameters can be textboxes, combo-boxes, or spin boxes, depending on the values being known, being restricted in a range or free-form.
- totally divergent usages are separated into tab pages ( for example adding the meta-switch “commit” to git, changes the whole set of expected/allowed switches and parameters )
- Once the parameters are entered, a button executes the action
Note: input validation must be proactive, ie, you must prevent the user from executing the action when mandatory parameters have not been entered, by greying out the execute button and, generally, greying out or activating GUI elements in order to convey proper usage. In CLI apps, the user just runs the command and gets an error message, ie, validation is reactive.
1
Usually, this can be solved by writing a GUI front-end that builds a command line. At that point you simply call the old CLI “main()” function with the arguments in the appropriate order.
What you need to do then, depends on the output. You might do well by wrapping all printf()
‘s in a generic output variadic function, that in the CLI version will just pass control to printf
while in the GUI version sends output to a scrolldown log window or something like that.
This way, the CLI application is mostly unchanged and the GUI front-end, while losing in efficiency, remains loosely coupled and can be maintained independently (in some cases, a mockup – or even a real alternative to the GUI – might be an independent application that then spawns the CLI binary with the proper arguments; sort of what you can do with AutoIt on Windows, so to speak).
But this strongly depends on what the application actually does. This approach can still be pursued to a greater or lesser extent, but it might become awkward if, for example, you wanted to execute the CLI routine cyclically or something like that; or if the program expected to operate on an input from stdin
.
3
the first thing you want to do is make the back end (behind the current CLI) separated from the frontend (the CLI)
essentially separate the view/controller (CLI) from the model so all the functionality code can be separated out into it’s own stand-alone module (that you can compile into a static lib for example)
then you can use the public C interface of that module to code against in you QT GUI
for the correlation of the button presses there is a extensive signal-slot implementation in QT and QT creator will handle a lot of the binding for you (its as simple as right click-> go to slot…-> clicked() -> type foo()
)
If your current CLI application uses a reasonably structured input and output format (particularly the output. It should be structured enough to be parsed by a machine), then you can always create a separate GUI application that communicates with the CLI application through pipes and/or temporary files.
To integrate the GUI with the current application, you need to be able to completely separate the I/O handling from the rest of the application, so you can build the I/O-less part as a library and bolt a user interface (either GUI or CLI) on to that. If the original application was never designed for this, it might be a hard task, because it is so easy to scatter printf
calls all over the place.
The fact that Qt is C++ and your application is in C should not be a major stumbling block for an integrated application, as long as the interface to the back-end part is written in the common subset of C and C++. Then you just have the learning curve of C++ to overcome.