15

I finished a project in C++. It is a console application, created with CodeBlocks. Although I consider it not so important in the scope of this question: The application manages data about bills and customers of a small company. The program is complete and could be very easily expanded by a console user interface (right now, I run it as a programmer).

Now I decided to learn GUI programming using Qt and the QtCreator with its QtDesigner!

Not only because it is common practice to separate logic from GUI when creating a GUI application, I want to put my project into practice in two big parts, namely, of course, logic and GUI. You already know that the logic part is complete; what I have is a project folder called project containing another folder (CodeBlocks project) project_logic which again contains several classes, thus header files and implementation files (and a main, which will of course be obsolete, eventually). It also contains files from/into which the program reads/writes. It is written in "pure" C++ and uses none of the means provided by Qt and it is important to me that it stays that way!

Now I added a Qt project project_gui into the project-folder and started to create the GUI, implementing only the most basic functionality, like changing between dialogues, closing the application, etc. So far it knows nothing about its future back-end (project_logic).

As a third component I need some kind of controlling which links the application's logic with its GUI. Here comes my conceptual question: What is the best way to put them together in one application?

Suggestions

  1. Since project_logic could work alone as a console application, it already provides the most essential controlling components and functions. This will stay this way, because I want to keep its standalone functionality. Even more so because I am totally new to GUI programming and/or in two weeks I could happen to create another GUI for the same logic. The result would be that the classes of the logic part are included in the GUI source like any other header and used to create a program with full functionality. Validating user input would rest on the GUI part. The program's logic would in any case remain updatable.

  2. To make the GUI as reusable as possible; should I implement a third component à la project_controlling that provides interaction between GUI and logic (user input validation done by controlling) in that each of the two remain as independent as possible? GUI not including headers of logic, so to say, but including controlling headers?


The second point may sound a little bit weird, I admit; to put it short, my aims are:

  • Keeping the project_logic standard C++ and independent (in terms of patching, adding functionality, etc...) and
  • using Qt for GUI at maximum (at the same time reasonable) separation of GUI and logic.

Trains of thoughts

  1. Should I include the project_logic headers via #include "../project_logic/header1.h" etc? (There may be a problem with using the classes, which I will post in a separate question.)

  2. Should I include them as a subproject?

  3. How would I connect the parts "in code"?

  4. Do the logic functions still find the files I mentioned earlier (read/write)?


Please keep the following in mind: I'm new to GUI programming! And I gave my best to explain my thoughts/problems... However, I know C and C++ and write console applications which I use for e.g. simulations at university and can handle the standard stuff quite well, I reckon. Even if the potential answerer feels like suggesting a very different approach, I would appreciate a "solution" for the concept I proposed. The reason for that I explained in the introduction. Unnecessary to mention though that I am of course interested in hearing different suggestions.

I decided to post the question after I did some research and tried my best in "trial & error" fashion before. There is a lot of information about this topic out there on StackOverflow and other boards, so I wanted to present my idea and collect criticism and inputs, rather than adding another "how to?" to the hodgepodge of questions.

Since this question is about the general approach, I will maybe (quite sure... :-P ) ask more technical questions later, which I would like to edit into this question (hyperlinks) as soon as they arise. However, basic recipes in this matter, if available, are welcomed, of course.


After some comments and answers I feel like posting a little EDIT just to make things clear:

Current status of logic

  • project_logic is more or less finished and coded in CodeBlocks as a CodeBlocks project.
  • It could work as a console application with "console user interface". (It has a main.cpp which is now only used for debugging.)
  • Its components are divided in classes (headers and cpp implementation files) as much as possible.

Current status of GUI

  • project_gui is being set up as a Qt-Widget-Application project (using QtCreator/Designer).
  • So far it is only GUI an nothing more (no connection to project_logic in any way).

Aims and ...

... the workflow, I want to follow, since this is my first big project:

  • project_logic and project_gui won't leave their respective directories; they both are in a directory called project. (Exception: Logic will be exported as a dll (or something similar) if necessary, which is then provided to the GUI.)
  • If there were things to be changed in the project_logic I want to do so in CodeBlocks (and repeat a possible export as described above).
  • project_logic (or any third layer like for instance project_controlling) have to be made disposable for project_gui in the most easiest fashion imaginable... (see Trains of thoughts number 1) :-P
LCsa
  • 607
  • 9
  • 30
  • 1
    And "Hello, StackOverflow!" :-) – LCsa Aug 02 '14 at 21:49
  • I'd like to [link to another question](http://stackoverflow.com/questions/25630829/the-role-of-the-main-cpp-in-a-qt-project) of mine, which also deals with the setup and structure of a project (this project, actually). It could be useful for users asking themselves the same questions in the course of setting up their first Qt project. – LCsa Sep 02 '14 at 20:37

2 Answers2

3

Welcome to SO.

You have really bundled two or three question together here, but lets have a go at it:

As a third component I need some kind of controlling which links the application's logic with its GUI.

Since you are using Qt, you have a built in answer to this question:

Qt Project-Model/View Programming. To get you started:

The model/view architecture

Model-View-Controller (MVC) is a design pattern originating from Smalltalk that is often used when building user interfaces. In Design Patterns, Gamma et al. write:

MVC consists of three kinds of objects. The Model is the application object, the View is its screen presentation, and the Controller defines the way the user interface reacts to user input. Before MVC, user interface designs tended to lump these objects together. MVC decouples them to increase flexibility and reuse.

If the view and the controller objects are combined, the result is the model/view architecture. This still separates the way that data is stored from the way that it is presented to the user, but provides a simpler framework based on the same principles. This separation makes it possible to display the same data in several different views, and to implement new types of views, without changing the underlying data structures. To allow flexible handling of user input, we introduce the concept of the delegate. The advantage of having a delegate in this framework is that it allows the way items of data are rendered and edited to be customized.

The MVC model, explicitly supported by the QT framework (and possible to implement with other GUI frameworks as well, albeit with more work), is widely accepted as a robust, flexible group of design patterns that affords management and separation of the various application layers, in the manner you are thinking about - so you are on the right track.

The second point may sound a little bit weird, I admit; to put it short, my aims are...

The question of how to set up your source code projects really has nothing to do with your application architecture per se, although these areas generally do intersect such that good project organization facilitates easier implementation of your architecture, and vice- versa. How you organize your project and its various libraries and classes may depend not only the project you're working on now, but on plans for future projects. For example, as you mentioned, you may want to design certain GUI components that you can use for several different applications. If so, you may want to put your GUI modules into a separate reusable generic library that can be used by many applications.

Certain rules, however are applicable across the board and are followed by most experienced developers - here are a few big ones, there are many more:

  • One major class and its friend classes per unit (hpp/cpp file).

  • Be very careful about what you include in header files and what you leave to your CPP files. You will find guidelines here on SO and in any good C++ book on this subject, which is quite important, particularly in complex projects. (From the sound of it - for example your questions about how to use #include and "connect the parts "in code - you need to get a better grasp of the some the fundamentals of C++ programming. Some excellent books are out there - you can find lists on here. C++ Primer (5th Edition) is one of the best places to start.)

  • Break down your classes and libraries in terms of their functionality. Most IDES support virtual sub-folders in your project (not sure about Code::Blocks) to help keep things organized in such manner. This actually gets into fundamental design questions, not merely how to lay out the code in your project.

  • Avoid tight coupling!

    In software engineering, coupling or dependency is the degree to which each program module relies on each one of the other modules.

    Coupling is usually contrasted with cohesion. Low coupling often correlates with high cohesion, and vice versa. Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability.

  • Make good use of namespaces, another great language feature that helps keep things modularized and organized.

In your case it seems that you might want to to do is package your "application logic" into one library, your generic GUI modules into a second, and then a third, thin executable -perhaps simply containing main() and a few lines to kick things off and shut them down when done - that launches the Qt application and intializes the classes in your libraries, which interact using the the MVC model and do the actual work of the application. Three separate modules is not necessary, although it will be more "generic" and reusable" and easier to keep organized that way.

You really have touched on a wide variety of subjects with this question, and again, some of them are related to C++ programming fundamentals, not simply "separating application logic from GUI". Hopefully this answer will help get you moving in the right direction.

An important note: GUI programming is a complete and not particularly easy branch of programming. There are GUI specialists and there are programmers who work with GUI only minimally. (I'm one of the latter group). There is an SE site called User Experience which, although it doesn't deal with GUI programming per se, deals with how users interact with systems, which is directly related to GUI programming techniques. So, when you say "Now I decided to learn GUI programming", know that you are taking on a big job. If you're not really interested in making GUI programming your speciality, you might want to consider using Wizards and pre-fabricated GUI solutions instead of doing it all by hand. QtCreator does provide some such support, as does Code::Blocks. If you intend on making this serious business, there are commercial frameworks available as well. Unless you're doing it simply for the sake of learning, re-inventing the wheel is not recommended for serious commercial programming work.

Community
  • 1
  • 1
Vector
  • 10,879
  • 12
  • 61
  • 101
  • I started to read this Model/View article before posting the question, actually. Although it is surely a very powerful mechanism, I would like to stick to more basic means for this first project. I want to include the `project_logic` sources in the "easiest" fashion, because I can handle standard `C++` (and the scope of the project doesn't require any fancier stuff). Even if that approach might not be super duper neat; because the next new thing I want to be handling the GUI using the QtDesigner (which I didn't mention in my post; GUI programming as such is another business, I know that. ;-) ) – LCsa Aug 03 '14 at 06:49
  • Two new concepts at once are too much to even get an idea of either of them. – LCsa Aug 03 '14 at 06:53
  • @LCsa: Most important concept IMO is loose coupling, which is applicable to all programming-if you studiously focus on decoupling your functions and modules, things often naturally fall into place - the natural borderlines become prominent. Also, I personally have a rule (not **ironclad**) that if I'm heading towards more than 3 parameters or 10 lines in a function, I'm probably coupling and bundling things and it's time to rethink the approach. In C++, setting up your headers, source files and namespaces correctly goes a long way towards achieving all types of modularization and separation. – Vector Aug 03 '14 at 07:01
  • As for the second part of your answer: All modules are perfectly separated from each other already. There is a customer class, an item class, a bill class (which has customers and items as members) and there was forged a control class which takes on communication and controlling. All of which are in separate units and independent (as much as possible, see bill class); creating a new control class could use the other classes in a different manner. This state of my project I tried to emphasize in the introduction. The header question aimed at learning if there was anything more to do than... – LCsa Aug 03 '14 at 07:03
  • ...just including my modules in the GUI code to make their functionality fully disposable. If that just works fine (maybe the second answer here leads down that alley...) I could as well include the thin controlling layer into the GUI (in the same way I would include the logic) and let that take on the part of controlling/communication. This would, I guess, make the GUI more reusable because no "logic stuff is hard-coded inside the GUI", if you know what I wanna say. – LCsa Aug 03 '14 at 07:12
  • @LCsa: Main point of MVC and such approaches is _no logic stuff hard-coded inside the GUI_, really an extension of loose coupling. GUI modules just handle GUI stuff. "Business logic" modules call into the GUI modules depending on their needs. Write a plotting module that draws a graph with X/Y coordinates. X/Y could represent sin(x), or the price of homes over a year's time- graph doesn't care about that. Your real estate app sends price/time values to set the X/Y in the graph, your math module sends sin(x) values to set the X/Y in the graph. The graph is _dumb_. **Dumb is Smart.** – Vector Aug 03 '14 at 07:26
  • Yep, sure, sorry, what I meant with "hard-coded" was "calling functions/constructors/etc. of my logic directly"... In your description right now business logic calls GUI... In my case it is the other way around, isn't it? GUI (or the interposed controlling layer) calls logic. – LCsa Aug 03 '14 at 07:53
  • @LCsa - not sure what your case is, but _GUI calls logic_ : Obviously it works both ways. Your GUI provides controls that you use to call into your business modules. They do their computations and return results. Those results are sent back to the GUI. The key is the intermediate layer - the _Model_ in MVC, which stands between the two - 'a layer of indirection' - so that your GUI and your business modules can both remain dumb and therefore flexible and robust. – Vector Aug 03 '14 at 08:01
  • Okay, this was my notion when asking and the "general concept" I proposed, actually. So, you'd suggest to introduce that third layer of controlling which calls the methods of the logic classes and returns their results to the GUI. The controlling methods are called by the GUI. – LCsa Aug 03 '14 at 10:30
  • @LCsa _So, you'd suggest..._ - I myself am not really suggesting anything. I'm just explaining that is the generally accepted way for a well designed application to handle things. It all goes back to loose coupling really. Your "business logic" is decoupled from your GUI via an intervening interface layer. The "logic module" can plug into that interface, or a console interface or a web page interface; the GUI can show math functions, or home prices or baseball stats - you simply swap out your thin intermediate layer and plug your pieces into a different one. **Think Lego** :) – Vector Aug 03 '14 at 11:48
  • Okay, however the general way you present corresponds to my suggestions and planned approach, which I presented in the introduction. It's good to see my intuitive concept confirmed. Now the questions in the course of my "trains of thoughts" remain to be solved. Namely, how to include the logic components. The other answer may cover this, if not, I will post a separate question. Thank you. – LCsa Aug 03 '14 at 13:30
3
  • If you have separate projects :

when you have developed different parts of your application in different projects, the easiest way is to just link your main project with the libraries and use them. So in your case you should provide the dll for the project logic which is developed and compiled in CodeBlocks to your Qt project, link to it and use the classes.

For example you can put the header files of your library in a folder named Logic and the debug and release versions of the .lib files in relevant folders and link your application :

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/Logic/release/ -lLogic
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/Logic/debug/ -lLogic

INCLUDEPATH += $$PWD/Logic
DEPENDPATH += $$PWD/Logic
  • In case you have everything in one Qt project:

In this case using Subdirs is a good idea to separate code modules from each other. This way you can have independent software modules which are reusable and able to be changed easily. It also makes the project much cleaner and easier to read.

In this approach the modules can interact with each other through signals and slots which makes different components completely independent and changing one module does not require changing other parts.

Qt Creator provides good automation in liking the parts to each other. You can make a Subdirs project and add your subprojects to its .pro file :

TEMPLATE = subdirs

CONFIG += ordered

SUBDIRS += \
    Component1 \
    Component2 \
    Component3 \
    MainApp \

You should bring the subprojects that others depend on, first in the list. Also notice that the name of the .pro file of the subproject should be the same as it's folder name. This way the subprojects are detected and listed in the Projects pane.

The subprojects Component1, Component2 and Component3 could be libraries. Part of .pro file for Component1:

TARGET = Component1
TEMPLATE = lib

DEFINES += COMPONENT1_LIBRARY

SOURCES += ...
HEADERS += ...

The subproject MainApp can be app. Part of .pro file for MainApp :

TARGET = MainApp
TEMPLATE = app

You can use the libraries in each subproject by linking it to the subproject. This can be done by right clicking on the subproject and choosing "Add Library" and then "Internal Library". When you select one library from the list of subprojects, the linking configurations are added to the .pro automatically. It will be like :

win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Component1/release/ -lComponent1
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Component1/debug/ -lComponent1
else:unix: LIBS += -L$$OUT_PWD/../Component1/ -lComponent1

INCLUDEPATH += $$PWD/../Component1
DEPENDPATH += $$PWD/../Component1
Nejat
  • 31,784
  • 12
  • 106
  • 138
  • The main application (GUI?) is also only a subproject? Couldn't I just put the project logic into a dll and then include it into my already existing GUI-Qt-project? Why detouring via subprojects? --- Is there no plain simple way to tell my program "In this specific folder you can find a .h and a .cpp file, use it!" without making those files part of the GUI project itself? Be it a dll, dependencies, whatever... ^^ Or is that what you just described, sorry... xD – LCsa Aug 03 '14 at 14:55
  • Both, logic and GUI exist, in my perfect world I just tell the Qt-GUI-project that there exist headers and cpp files of the logic class which it should use. – LCsa Aug 03 '14 at 14:57
  • @LCsa `MainApp` is also a subproject which could have GUI (For example MainWindow and other dialogs). This way all of the subprojects of type `lib` become dlls in Windows. This way helps you to break your project in to some small and reusable parts. Of course you can also avoid this logic and have different components in different classes in folders. But using subprojects makes your project clean and neat. Also you can benefit from the automations that QtCreator provides you for subdirs. After all this approach is to have libraries (e.g dlls) in different folders in a well defined manner. – Nejat Aug 03 '14 at 16:04
  • May I ask: If I have a dll of all the classes of my program's logic, wouldn't it be the easiest way to include this dll to the GUI part (Qt project)? For now I'd like to develop the logic in CodeBlocks (to update it) and only provide it to the GUI (which is created using Qt). – LCsa Aug 04 '14 at 13:18
  • I attached an edit section to my question, summing everything up as neat as possible. I'm sorry if the question gets confusing or "too big", however I tried my best to provide all information needed and make it interesting for other people as well (as it is held quite general). Your post was helpful, but I'd love to work according to what I edited in my original post (and I hoped it'd come across right at the start). And your approach doesn't feel like the "simplest" -- correct me, if I'm wrong. In my question I aimed to show my workflow, gather criticism for future projects and help to go on. – LCsa Aug 04 '14 at 13:54
  • @LCsa If you have developed the project logic in another project then you are right. It's easier to just link with the dll. The approach in the answer is good if you want to have everything in Qt and in a project solution. That way the modules can interact with each other through signals and slots which makes different components completely independent and changing one module does not require changing other parts. – Nejat Aug 04 '14 at 14:52
  • Okay! Would you be so nice and add that dll info to your answer, dividing it in a "in one project" and "two separate projects" part? It would be great if you'd give a brief example (like you did already for "in one project") for the dll implementation also, because then we could consider the question answered and accepted. The general approach got confirmed and you delivered ways to combine logic and GUI. :-) – LCsa Aug 04 '14 at 15:11
  • Thank you, accepted! Just out of interest: Would it theoretically be possible to directly use the headers and cpp files in the `project_logic` project without creating a library? I guess no, because the creation of the modules and linking wouldn't be done by the `project_gui` since they're not part of the GUI project... And, is it possible to use the `$$PWD` together with a command like `../`? – LCsa Aug 04 '14 at 18:33
  • @LCsa Using directly the header and source files of the `project_logic` in the `project_gui` makes it like the second approach. If the logic source is able to be compile in Qt Creator then yes it is possible. `$$PWD/../` means one level upper than the project working directory. – Nejat Aug 05 '14 at 02:58