Unsolved Trying to fight my way out of mainwindow.cpp
-
Hi,
Quite a newbie question here.
So, I'm creating just a basic app that allows you to open a file and then copy the contents into a vector of a string.
The pushbuttons work within mainwndow.cpp, but trying to offload- Opening of file
- Reading the file contents
- Loading them into a vector
... into a side source file called simple.cpp (which has its accompanying simple.h)
The problem is, even though I've added:
#include "mainwindow.h"
#include "ui_mainwindow.h"into my simple.cpp (I've even included it in simple.h) it fails to recognise the ui-> before anything, claiming it to be undeclared.
Can anyone suggest what I might be doing wrong?
Thanks,
Uberlinc.
-
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
into my simple.cpp
Why should simple.cpp know anything about your UI? This is bad design! You especially should never ever try to access private members like ui from other classes!
It should be other way around: your main window includes simple.h header file and calls its functionality to get what ever it provides. -
Ah! I see - Ui::Mainwindow *ui is private!
So, should I include an accessor/mutator function to access this area of the program?
If not, then what would be the better design?
I am only learning here, but as everything is event-driven, and these events hang off Ui::Mainwindow, how to you relocated code to other files?
Surely you don't load up mainwindow.cpp with all your code?Can you please point me to a good example of a Widget application that then uses other source files (for reasons of modularity)?
Many thanks,
Uberlinc.
-
no. subclass the user interface and set the look/feel there, then attach its operation to the main window via signals/slots. Ui:: and ui_ implies that you are using qt designer. There are adequate examples online.
Long running operations like file loads should be done in separate threads, not directly in the UI code.
-
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
So, should I include an accessor/mutator function to access this area of the program?
NO
As I said: only mainwndow should access its UI!
Why should simple.cpp access any UI? What it should do is open file, read its content, load the file content into a vector and return this vector to whoever called it. Where do you see the need here to access any UI?#include "simple.h" void MainWindow::do_something() { Simple simple; QVector<QString> content = simple.getContent("path_to_file"); # Now you can add content to what ever UI you want without simple.cpp even knowing there is any UI... }
-
@Kent-Dorfman said in Trying to fight my way out of mainwindow.cpp:
Ui:: and ui_ implies that you are using qt designer. There are adequate examples online.
Yes, I'm using Qt Creator 4.15.0 based on Qt 5.15.2 running on Ubuntu 21.04.
Re: Online examples - I've looked around but it's like being a dog in a forest not knowing which tree to pee on!
I've been looking at Youtube examples and they all seem to be loaded up within mainwindow.cpp.Can you point me to a good resource that might have a good, simple program to start me off?
I'd like to get a picture in my head of how things should be structured so I can continue from there.
Any help is appreciated.
Thanks,
Uberlinc.
-
Qt lends itself to not follow the MVC model. What makes it easy to mix all this is that you can always query the current values from the view. Why should you store them again in a model?
I'll try to explain my understanding of MVC in the context of Qt. Obviously your
Ui::Mainwindow
is your view class. Naturally,MainWindow
will become the controller class. What you need in addition is a model class. The model class would store every state represented in the view in variables itself. When you create the UI you need to synchronize the model and the view (inside MainWindow). Then, you connect all signals of all the different controls of the UI/view with suitable slots in the model (which means your model class should inherit QObject). I am not entirely sure where the functionality should go in the MVC model, but I would personally put it into the model class. Basically, this would make yourSimple
class the model class in this scenario. So, instead of trying to get the state from the UI, have the state as member variables in Simple and use signal/slot connections (MainWindow connects signals and slots between the UI and Simple) to keep the view and the model in sync.That being said: I haven't succeded in getting every developer to create a separate model class. On a current project old code has just been changed to use Qt instead of the previouse framework and it hasn't been fully rewritten. So, in my code bases functionality is mostly handled by QWidgets (i.e. something derived from QMainWindow, QDialog, etc.) directly. Also, the code heavily accesses UI elements directly.
Usually, the view part is already separated into the ui-file; most controller stuff (mostly
connect
s) is only happening inside the constructor of QWidget-derived classes (e.g. the constructor of MainWindow); the remaining implementation of MainWindow is then mostly the model part. However, you can also have MainWindow just collect all information from the UI and then provide all necessary info as parameters to your processing class. Though the 3 steps you described would then be perfectly fit into a free-standing function (i.e. use procedural programming instead of OO). Let MainWindow get the filename from the UI and provide it to your processing function. And let your processing function return a vector. I don't see why this function should have access to the UI...Does someone have a better idea/description of how MVC should work in Qt? Or is MVC already outdated?
-
@jsulm said in Trying to fight my way out of mainwindow.cpp:
Why should simple.cpp access any UI? What it should do is open file, read its content, load the file content into a vector and return this vector to whoever called it. Where do you see the need here to access any UI?
Good question.
I tried passing the file name to simple.cpp that contained but when I did the test for a successful open, it contained a message box for the case of failure. This needed to reference ui.If I open the file within mainwindow.cpp to test, will I then have to pass that entire object into the constructor for simple?
My code also includes a lineEdit that displays the file name that is opened once it is successfully opened.
If I do all this from within the simple object, how do I pass this back to ui to send the name to the lineEdit object?
The only way I know of is an accessor function which I was told was I’ll-advised.I’m still struggling to picture the overall structure here.
All attempts to find an online example seem to lead to mainwindow.cpp-only applications.
I could really just do with one simple example that shows a mainwindow and non-mainwindow interaction so I can get a feel for it. I’m a visual person and work better seeing an example.
Anyone?
Please?
:) -
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
it contained a message box for the case of failure
Don't see the problem. Let getContent() return a bool to tell the caller whether it succeeded or not
Simple simple; QVector<QString> content; if (!simple.getContent("path_to_file", content)){ // Show error message here }
Think about QFile class for example: does it access any UI? Why should it?
-
Thanks for this.
I understand what you mean in this small example, but am struggling to put it into the big picture.And again, if anyone could point me to a really simple example to illustrate this sort of thing, I'd love to see it! :)
I'm still at a point in my coding where I am struggling to work with disconnected fragments of code.
Perhaps they will make more sense to me as my overall coding skills improve.Many thanks.
-
@SimonSchroeder said in Trying to fight my way out of mainwindow.cpp:
What you need in addition is a model class. The model class would store every state represented in the view in variables itself.
Can you point me to a code example that employs a model class?
Let MainWindow get the filename from the UI and provide it to your processing function.
See above. I tried this but ran into a snag when testing for viability of file.
And let your processing function return a vector. I don't see why this function should have access to the UI...
I considered this but I was worried about passing large chunks of data around between functions.
Does this cause any instabilities in memory, or do the use of pointers get around this?Many thanks.
Uberlinc.
-
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
Does this cause any instabilities in memory, or do the use of pointers get around this?
Vectors (in Qt) are shared, i.e. it doesn't matter how many times you pass them as parameters no actual copies of them or their data is made. (Qt also does other stuff like only making a copy when writing to many of its types.) But even if it were, say, a C/C++-type (pointer to) array it wouldn't get copied. You are passing around references to large areas of memory, but not copies of the data there.
Can you point me to a code example that employs a model class?
I'm not necessarily saying this one is great (haven't really looked at it), but what about starting from Item Views Examples? I picked the first one, Address Book Example, because I can see from https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/itemviews/addressbook?h=5.15 that it has several source files. I think you are asking about that specifically. It has a model class. There are a whole heap of examples starting from that first page involving models.
-
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
This looks like a good example!
I'll have a good look at this.
Many thanks, Jon! -
@Uberlinc said in Trying to fight my way out of mainwindow.cpp:
What you need in addition is a model class. The model class would store every state represented in the view in variables itself.
Can you point me to a code example that employs a model class?
Sorry, I don't have a quick example at hand. I'm glad that @JonB could provide you with an example that seems to work for you.
Let MainWindow get the filename from the UI and provide it to your processing function.
See above. I tried this but ran into a snag when testing for viability of file.
If you just want to display an error and return from the function reading from the file there are two possibilities. 1) Either MainWindow calls your function directly (not through a slot), so it can wait for a return code (you can use something like "expected" or Boost Outcome). In case your functions returns an error, MainWindow can display (trigger the display of) the error dialog. 2) If your function is a slot and might be/is called through a signal, you can yourself emit a signal that a MainWindow's slot is connected to. Provide the error message as parameter and then, again, MainWindow will handle showing the error dialog.
And let your processing function return a vector. I don't see why this function should have access to the UI...
I considered this but I was worried about passing large chunks of data around between functions.
Does this cause any instabilities in memory, or do the use of pointers get around this?As mentioned before QVector is implicitely shared and would not provide a problem at all. Furthermore, since C++11 we have move semantics and at least it is guaranteed that – if you were to use, e.g., a std::vector – the vector is moved. This is cheap. I believe Scott Meyers' Effective Modern C++ has an item on this. Unless you have proven otherwise (by benchmarking), since C++11 it is recommended that you even return containers by value.