Qt::QUndoCommand problem and possible solutions.
We are developing an application of 3D editing in Qt.
We need to implement a "stack of operations" which allow the user to call undo-redo on his operations.
We are using QUndoStack with QUndoCommand Qt classes.
The application is based on the MVC pattern so the View (QGLWidget) knows how to draw the scene structure.
We have sliders (QSlider) to translate/rotate/scale the 3D objects (Meshes), and we need to show the effect of the transformations in real-time.
For example if I have selected an object and I'm moving the "X Translation Slider" I want to see the object moving along the X axis while I'm dragging the slider.
The problem is to get the real-time editing working with the stack of operations. In fact the "undoable" operation who should be pushed on the stack is the total slider movement (from the pression to the release of the slider).
We find out 2 ways of doing this:
While I'm dragging the slider (at every valueChanged signal) the
transformations are applied to the model and the QGLWidget updates
straight after every slider tick. At the release of the slider the
command must be pushed in the stack. QUndoStack automatically calls
the QUndoCommand::redo() action when a command is pushed. To prevent
the operation to be executed twice (the first time to grant the
real-time effect, the second at the QUndoStack::push() call), before
the call of QUndoStack::push() The inverse transformation is applied
to the object (obtained from the total slider movement) and then I
push the command to the stack.
QUndoStack tryes to merge command when they have the same result
from a call to QUndoCommand::Id(). While I'm dragging the slider (at
every valueChanged signal) a QUndoCommand is generated and
immediately pushed on the stack, the stack merges it with the
command at the top if they have the same Id(), then the stack calls
the redo() for the command who is being inserted, then the QGLWidget
updates and the real-time effect is obtained.
With the second one an instance of the "Command" class is generated every slider tick, while with the first one the real-time operation get's reverted just to push a command and to stay in a consistent state.
What solution is better in terms of "good programming"?What is better in terms of performance?
I think you're looking for QUndoStack::beginMacro() and QUndoStack::endMacro()
Which can be used to merge a series of commands in the undo stack so that they're done/undone as an atomic operation.
Chris is correct, you could use macros as well as your proposed solutions. But I don't think his criticism of 'overly complicated' is fair: the Qt mergeWith AND macro mechanisms are intended for your purpose.
I would not worry about the performance of any of the solutions, until you find that the performance is a problem. Get it working, then test for performance, and then fix any performance issue. You can't know until you try it whether the generation of excessive commands(that are then merged) or your inverse transformation is a performance problem.
Another solution: on the first tick, push a command and keep a reference to it. On subsequent ticks, update the command and perform an increment of transformation?
(There is a related problem where a command is pushed but a user cancels the operation. For example, what if the user drags the slider, but releases the mouse outside the slider? Is the slide canceled? Search for "transactional undo command". It reimplements redo so that it does nothing the first time it is called as the command is stacked, and has a commit() or rollback() method that is called later.)
(I learned something from your post: when self.mergeWith(other) is called, Qt calls the redo method of other. That's not clear from the documentation.)
Related
I have been writing some GUI test frameworks that can record and replay some GUI user scenario by recording mouse and keyboard events and replaying them.
The mouse events are currently recorded as (press or release, (x, y)). However, this is very fragile because if only the destination widget moves by a few pixels, but the structure and everything else stays the same, the testcase ceases to work.
What is a better approach to do this? Some things that I can think about
Record the "tree path" of the destination widget in the tree of widgets and their parent widgets. I.e. (press or release, (top level, first child, second child, destination)), where the "child list" is what is returned by Qt's QObject child list. I think this has the drawback that the test now is dependent on the internal code structure.
Give every testable widget a unique name and when replaying search the widget with that name. This seems to be a non-negletible overhead.
Any other ideas, and what is the commonly accepted "best" approach to this?
The Specifications
The decision is yours to what extent are the test cases bound to the particular setup of a test, and to changes in code. It's essentially a question of how tight are your specifications.
On one hand, there are "mechanical", or "dumb" tests. It may be that you're testing with tightly controlled initial conditions: the same settings for initial window positions are pre-set before the test, the same platform style is enforced, the same fonts are available, etc. It is then a reasonable expectation that if you switch two buttons around in a widget, or change the initial window/dialog size, the tests are supposed to fail.
On the other hand, there are "human" tests. You may wish for the tests to succeed if a human reading a script from paper would succeed at the test. In such case, the minor changes such as fonts, location of visual elements, etc., are not important: human testers readily adapt to such changes.
Those two extremes may even apply all at once, but to different parts of the application, or to different stages of the product lifecycle.
If you're designing a UI for an aerospace flight management system, there are aspects that may require a fully "mechanical", non-adaptable tests, since any changes to the UI that are not covered by specification changes would be in fact a bug.
If you're designing a consumer application, you may wish to keep the specification tight across bug fix or minor releases, but could relax this for major releases, for example.
Cooperation from the Test Cases and Tested Code
In implementing more flexible, more human-like tests, one needs some cooperation from either the tested code, or test case generation process, or both.
The test case generation process (a test script, a human, etc.) has important knowledge about the meaning of a particular event. For example, a click on a generic button is really destined for the middle of the button - then it doesn't matter if the button's active area has rounded corners that don't react to clicks. A click may also be destined to a button labeled "OK", no matter if that button is on the right or left edge of a button bar on a particular platform.
The tested code also has important knowledge about classification of a particular event. For example, a click's coordinates may be important by themselves if it's a click on the canvas of a painting program. Otherwise, it may be a particular visual element within a widget that is important, not its exact coordinates. In this latter case, changes to the appearance of the widget due to platform styling or code updates may make the relative coordinates obsolete.
I’m using Qt 4.8.
I have a big QGraphicsScene to update (it takes 3 secs to append the new QGraphicsObjects).
I would like to show the user that the update is in progress.
In particular I thought about showing a loading wheel on screen and than remove it when the update ends.
The problem here is that I should make the wheel visible and then not visible in the
same thread of the scene update. This because:
It is not allowed to edit graphic properties outside the gui thread.
I cannot move the computation in a “worker thread” since it involves graphics.
This results in the wheel not showing at all, since when the view is updated the wheel
has been already set visible and then not visible again:
showWheel();
/*... big computation involving graphics ...*/
hideWheel();
/*... here GUI is updated, thus the wheel doesn't show up...*/
Is there anything I can do?
Thanks
Presumably you have some event triggering the computation. Instead of using it to trigger the computation, use it to trigger a scheduleComputation()slot. The scheduleComputation slot can call showWheel() and then schedule the doComputation() slot for the end of the next event queue, after which it will return. This will allow the event loop to run and show your wheel, then perform computation. When computation is over, you can call hideWheel() and return to the event loop.
Something like this:
void scheduleComputation()
{
computeScheduler = new QTimer(this);
computeScheduler->setInterval(0);
connect(computeScheduler,SIGNAL(timeout()),this,SLOT(doComputation()));
showWheel();
}
void doComputation()
{
//...Computation Here...
hideWheel();
}
It is also a good idea to keep from blocking the UI thread for long periods of time. This can be done by splitting your long running code into smaller pieces that can be triggered by a timer.
At regular intervals in the "big computation" you can let the event handler run for a little while.
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 have a rather large application I'm trying to make in Visual-C++, and I am now trying to add undo/redo functionality.
Having a rather large amount of events (button clicks, label text changed, etc.), I would like to find a way to undo/redo without adding code to every function.
For Instance, I would like a class that can read every event done and store it automatically. Then in my undo/redo events, I can just get the latest action stored.
If that is not possible, I would not mind some other way.
Any help?
Declare a class that represent two operations - undo and redo.
Also create two vectors of that class.
For each operation you want to apply undo/redo, push an instance of that class into the undo vector. There should be as many derived classes as there are opreations you want to undo.
For example, if a button click paints the background to green, you create a class instance whose undo metdho paints the background to the previous color, and its redo method paints the background to green, and stuff it into the undo vector.
When you undo - you pop the last class instance and call its undo method, which will paint the background to the previous color. Then you push it to the redo vector.
When you redo, you pop the redo vector for the class instance at the top and invoke its redo method, them stuff it back to the undo vector.
There are some corner cases (boundaries), you'll tackle them when encountered.. :-)
Do all of your events pass through a queue of some kind? by default in c++ there is no queue like this (there is a windows os level event queue, but that is likely managed already and unusable in c++-cli and you did not indicate if this closely mapped onto your problem), there may be some other construct I am unaware of.
If you have some central queue, then it is just a matter of capturing events as they pass through and knowing how to undo each action. If no central queue is present then I see no other way easier than changing each undo-able function to create an undo object of some kind and storing it in and undo queue of some kind.
In a pure .net or a C++ environment without a large central work queue I would make a class that is and undo entry, that implements a method/member function to undo and another to redo/do the work. But for just undo functionality, this could be just a .net delegate or a c style function pointer, and a list of arguments. If you make an action undo/redo class it could be a template or generic that stores pointers/delegates to the the do and undo functions, and a list of arguments from when it was originally called.
These can be run to undo the actions that have been done. They will be inserted into a queue container of some kind, the kind of container doesn't seem to matter as longer as it preserves order, your should pick the best std, .net or other container for your application. You can discard older ones when you no longer need them. When executed the entry last inserted into the queue must be removed to preserve consistency.
If you also need redo functionality, then your queue of actions done must be iterable, and it would be easiest to use the class that was and action had a method/member function that could undo/redo the desired actions. You would have and iterator, pointer, index or marker of some kind indicating how far back you have undone. Every time an undo is requested you must move the marker backward (earlier chronologically) and execute the undo command at that point in the queue. If a redo is requested then the current item indicated executes its redo instruction and then the iterator is advanced forward (chronologically) through the queue, or ignored (I presume) if you are at the forward-most item in the queue.
If you wanted to go off the deep end, which you have no way indicated you want to, you could center you app around the action queue. You might not need to change you functions implementing this approach. Your user interface (I assumed, could just as easily be your API) functions, insert actions (which support doing and undoing) into a queue, and then command the queue to do. You would not have to change your existing functions if their side effects are known and reversible. However, you would need to change all the callers to make actions instead of directly calling, and you would need to write counterparts that do the undoing.
I've tried to achieve something like that in a small experimental library: https://github.com/d-led/undoredo-cpp. It contains an implementation of a TransactionStore similar to what CodeChords man suggested. You might need to really add functionality to each of your undoable objects, and also take care of object lifetimes, in case your actions involve object construction or destruction