I have a QT application that allows a user to define a list of models. Each model defined has a fairly complex widget class that is created. Currently this is all being done in the main (GUI) thread. The program works fine for normal use, but I tried to stress test it by creating 200 to 1000 models and the creation of the GUI took a VERY long time (20 seconds to many minutes).
I tried a couple attempts at threading out the work using QtConcurrent::run, but the program always complained because "Widgets must be created in the GUI thread."
I found this answer on SO: How do I create a Window in different QT threads?. But this doesn't seem to be doing much in the new thread except telling the main thread to create a new widget. This does not distribute the workload, as far as I can tell.
With all of that, I have a couple direct questions:
1) Is there a better design (faster performance) than looping through my list of models and serially creating each widget?
2) If this process is possible to be multithreaded, can someone point me in the direction of a simple example?
There really is no way to put widget stuff to other threads. OpenGL rendering or some data processing for a widget to show when ready, stuff like that can easily use other thread, but not the actual widgets.
Better design would be to create the widget when you need it. Or just have one widget and update the data it displays (unless widgets for different items are actually different).
If you are worried about performance when scrolling, then one solution to that is to switch widget only after current one has been visible for some minimum time (say, 500ms if user keeps scrolling, or 200ms after last scroll event, some logic like that) note that this is not delay for reacting to user selection, this is delay after selection and visible widget change, so if user just changes to next item, GUI is updated immediately. But in scrolling the widget is not updated for every item briefly selected, and things don't slow down. Use QTimer or two to send signal when widget should be updated.
Related
I am working on a packet sniffer with C++, using QT for the user interface.
I have two main threads: QT's main thread, and another thread that takes care of the packet capture and processing.
The capture thread captures and processes the packets -> it then sends the result to the GUI thread which displays it using the signals and slots mechanism.
I am using a QTableWidget to display the packets.
The problem is that when I have a massive flow of packets (When downloading something for example) the program starts to lag and the program starts to eat a lot of CPU (Up to 17% during a download or a video)
Is there a solution to optimize a QTableWidget and make my program more fluid?
My QTableWidget:
Your best bet is probably to stop using QTableWidget and use a QTableView instead. The difference between a QTableWidget and a QTableView is that a QTableWidget dynamically allocates a separate QTableWidgetItem object to hold the state of each cell; if you are creating and/or deleting a lot of cells in a short period of time (which it appears you are), the creation and/or deletion of all of these objects can be quite inefficient.
QTableView, on the other hand, doesn't require the creation of any per-cell QTableWidgetItem objects, which allows it to be more efficient when under heavy load. Instead a QTableView has to consult a model-object, and the model object tells the QTableView what data to display at any given moment. You'll need to create your own subclass of QAbstractTableModel for your QTableView to consult with, and call setModel() on your QTableView object with a pointer to your model-object.
It's all a bit involved, so you will want to read through Qt's documentation on the subject and look at their example-programs before trying to implement your own.
I've used this approach to implement e.g. a log-view which sometimes has dozens-to-hundreds of log messages generated per second, and it works well once you've set up the model correctly.
For test purposes I'd like to create and display a widget. For now I only need the widget to render correctly but in the future I may want to extend this so I simulate various events to see how the widget behaves.
From various sources it would appear that the following should work:
QApplication app;
QPushButton button("Hello");
button.show();
// Might also be necessary:
QApplication::processEvents();
But for me the widget does not render correctly. A window is created to display the widget, however it is entirely black.
I can get the widget to render correctly by adding the following lines:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();
With 10 milliseconds being about the smallest time necessary to get the widget to render correctly.
Does anyone know how to get this to work without the time delay, or know why the delay is necessary?
To test Qt GUI application you need at least QApplication instance and event loop being processed. The fastest way is just use QTEST_MAIN macro, this answer explains in a nice way what it does exactly. However, to have more flexibility (e.g. to use GTest, GMock) you can also simply create QAplication instance in your tests main (no need to call exec).
Then, to have the events processed, you should invoke QTest::qWait. This will process your events for the specified amount of time. It is a good practice to use qWaitFor which accepts a predicate - this way you avoid race conditions in your tests.
In the particular scenario, when you expect some signal to be emitted, you can also use similar functionality of QSignalSpy::wait.
Small example when we want to wait until some parameters are passed from one item to another:
QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings
Why don't you want to have the application run exec ? The process of displaying a widget is not "static". You don't "draw" the widget on the screen, but rather you have an application that listen for various events and receives draw events from the windowing manager. The application can only draw the widget when the windowing manager asks it to.
The reason your second code works is that you wait sufficiently long for the windowing manager to have sent the "draw" request in your conditions. This does not guarantee it will always work.
If you want to guarantee the display of the widget, you need to start a loop and wait until you have received at least one draw event, but even that isn't foolproof.
As expertly described by Vincent Fourmond, widgets are not a one-off deal. The GUI is non-blocking and for this, it needs to run in an event loop.
The exec() method starts this event loop which you mimicked by polling.
While it is possible to combine Qt's event loop with other event loops, I would recommend you a simpler solution:
Proceed your program within the event loop by calling a method when it starts. Find an excellent answer here on how to do this: https://stackoverflow.com/a/8877968/21974
As you mentioned unit testing, there is also a signal you can use for doing checks at the end of the lifecycle (before widgets are destroyed): QApplication::aboutToQuit. This will happen when the last window is closed (programmatically or by the user).
I'm working on a Qt app, and at some point I have a class (I name it here "engine") that is governing the program: it has a signal with a timeout which makes the class to draw, and evolve the app logic. Morevoer, it receives events that are caught from a QGraphicsScene.
Each engine "tick", the update() is called on the Scene, updating the drawing according to the app evolution.
Naturally, I want the drawing to be synchronized with the reactions of the events, otherwise, a drawing of some object could be made while the reaction of a event was destroying that same object, causing a SegFault.
I've tried using a queue on the engine such that I would only make the engine to react to those events on a specific place of a update, thus not interfering with the drawing part.
Two problems rised:
I cannot make a copy of a QGraphicsEvent. Apparently the copy operator is private (which I assume is for a good reason anyway).
When the class is processing the events, before the drawing, it can also happen that a new event appears, which can be "bad" because of non-synchronization of it
Taking into account this situation, is there any approach that can solve this situation? Is there any standard procedure in Qt for this? I mean, how do I ensure the drawing is not potentially desynchronized with the events' reactions of the application?
Let's imagine you have a fullscreen C++ desktop application that consists of several screens with each of them having a distinct function and a ViewController with appropriate models as well. For example a set of the following very simplified screens:
Quiz: The user is navigated through a set of multiple-choice questions.
Quiz Results with Statistics.
Information: The user is presented with information about a specific subject.
Menu (Quiz, Information, Exit)
Judging by the GRASP principle Information Expert, each ViewController will know best when it is finished and time to move to a new screen. Yet by the same principle, it is not the right place to decide what the next screen should actually be. In this rather simple example, one could argue it would be okay but in a more complex application, it will undoubtedly lead to duplicated code and logic as well as higher coupling and lower cohesion. There is also the problem that you would have to create the new widget and controller within the current screen's ViewController which brings all sorts of new problems and at least by the Creator principle, it is not the right choice. You would have to introduce a Factory to alleviate some of the problems, amongst other things.
So, the next logical step is to introduce an ApplicationController with the sole responsibility of managing Views and their controllers including the navigation flow from one view to the next.
This still leaves one problem wide open in my opinion: How to signal the ApplicationController that it is time to move to a different screen and hand over the control to that object properly?
One could use the Observer pattern, for example. Yet what if you have an expensive View active at the moment and want that one destroyed once the new screen is active? If the current ViewController signals the ApplicationController that the next screen should go up, it can manage everything up to the point where it would destroy the currently active screen which it cannot do because the current call comes from exactly that object. Apart from several other problems with that approach.
So my question is (and sorry for all the verbose introduction :P): How do you properly implement a navigation flow from one fullscreen widget to a different one with MVC which solves the above problems, splits the responsibility between the View- and ApplicationController and is nicely object oriented in terms of coupling and cohesion?
Sometimes you miss one detail in your thought process and you open up a whole can of problems without even realizing the mistake you made.
In this case the detail was that you can naturally post asynchronous as well as synchronous events. If you have to make sure that you are no longer in the context of the event posting method, post an asynchronous event. Once you receive that event in your handler, you can be sure that the context was left. And for example you can safely delete the object, if you so desire. Naturally the event handler should not be in the context of the same object that you are trying to delete.
For completeness: In Qt, you can specify for each signal/slot-connection you make with connect(), that it should be of type Qt::QueuedConnection. If you raise a signal, it won't be delivered until the control is back to the thread's event loop. Normally, Qt::AutoConnection is used which delivers a signal at the time it is raised (Qt::DirectConnection) if the receiver is in the same thread or falls back to queuing that signal (Qt::QueuedConnection) if the receiver is in a different thread.
In wxWidgets you can queue events with wxEvtHandler::QueueEvent(wxEvent* event) which is available through the Application singleton for example.
I am currently writing a wizard-style application using Qt4. I am not using the wizard class however, since going next/back does not make sense from every step in the process.
The user starts off at a "hub"-window with five buttons, each of which take him to another window at a different stage of the process. At the beginning all but the first button of the hub are disabled. After clearing each stage, the user will be directed back to the hub and one new button/stage will get enabled.
Since every stage has significantly differing objectives, I coded every single stage as a single QWidget that gets instantiated in the main() function. To switch between the widgets, I simply hide() the one I am leaving and show() the one I am going to.
However, this leads to problems if the user resized or moved one widget, since the next widget will always show up at its default position instead of the new one.
Is there a way to synchronize the widgets' sizes and positions?
Or, better yet, is there a more elegant way to deal with those different windows than switching between several hidden widgets?
Thank you in advance!
Create one top-level widget that holds the others.
I suggest that you either use QStackedWidget, or, if you want more control, create your own widget and use QStackedLayout directly.
Why not just have one main QWidget as a container for your pages? That way if the user moves the main QWidget and then goes to the next page, it will still open in the new position inside the main widget.
Generally, I've never had occasion to create multiple widgets inside my main method. Don't quite see the point.
I'm beginning on something similar - with different views (perspectives) for different tasks along the way. Using toolbar icons and file menu, not buttons, to move between views. Similar to how MS Outlook allows you to have the window display email, or a calendar, or contacts, etc.
My intent (haven't started yet) is to have one QMainWindow as the application window, containing my various QWidgets that offer the various views. Depending on what task the user is doing, one composite widget will be visible, and the others hidden.