Reputation: 667
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?
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.
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:
project_logic
standard C++
and independent (in terms of patching, adding functionality, etc...) andQt
for GUI at maximum (at the same time reasonable) separation of GUI and logic.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.)
Should I include them as a subproject?
How would I connect the parts "in code"?
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:
project_logic
is more or less finished and coded in CodeBlocks as a CodeBlocks project.main.cpp
which is now only used for debugging.)project_gui
is being set up as a Qt-Widget-Application project (using QtCreator/Designer).project_logic
in any way).... 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.)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) :-PUpvotes: 15
Views: 4800
Reputation: 32665
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 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
Upvotes: 3
Reputation: 11753
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.
Upvotes: 3