Suppose I have class:
class Foo : public QObject{
Q_OBJECT
public:
...
private:
Bar* m_bar;
}
And for whatever reason, I'd like to replace m_bar with a pointer to an object of DerivedBar. The use case I most often find is when I want to replace it with an object of MockBar (using the google mock framework) for unit testing.
Now I know in most cases, I could just extend the constructor to be something like:
Foo(Bar* bar, QObject* parent)
and just set m_bar accordingly.
But the problem I have is when the classes are QWidgets and I'm assembling them via Qt Designer. Imagine Foo and Bar are widgets, and Bar is placed inside of Foo from designer; their connections are also set via designer (ie, stored in the qml file). I've tried something like:
Bar* bar = foo.findChild<Bar*>();
bar = new MockBar(&foo);
(neglecting any memory leaks here, just trying to get functionality) But when I go to set expectations, it does not seem to be connected like the existing one was. Slots aren't called in response to signals. I don't think this is entirely unexpected due to the way connections are made, but I'm wondering if there's a way to get the effect I'm looking for.
(nb: for now, using qt 4.8 and gcc 4.6, which does limit some options for c++
Here's a better answer I've found: The issue for me is ultimately to do with the QWidgets generated from ui files. But since the Ui::FooWidget class is functionally just a pimpl pattern, I can create a pointer to a local copy of one, and modify Foo's constructor to allow me to optionally inject the ui implementation. If Foo is making a direct function call to BarWidget, I can replace that ui's 'barWidget' object with my MockBarWidget, and set expectations and such and perform testing. The previous answer will still satisfy to some degree when the interaction between the two widgets is one of signal/slot connections.
Previous Answer:
Here's one answer I've found so far, but I don't much like it:
Bar* bar = foo.findChild<Bar*>();
bool connectTest = QObject::connect(&foo, SIGNAL(setValue(int)), bar, SLOT(setValue(int)), Qt::UniqueConnection);
ASSERT_FALSE(connectTest);
bar = new MockBar(&foo);
connectTest = QObject::connect(&foo, SIGNAL(setValue(int)), bar, SLOT(setValue(int)), Qt::UniqueConnection);
ASSERT_TRUE(connectTest);
//... rest of test
I could probably wrap the whole thing up in some kind of helper function, and that function may be better with c++11/Qt5 where signals and slots can be method pointers. But I wonder if I'm missing an easier way to do it.
Edit: It turns out this pattern was giving me a false positive, only the first 'connectTest' part of the test was giving a valid test of behaviour. This flaw is more obvious when Foo doesn't emit a signal to bar , but merely calls a method on bar. The mock is not injected through this pattern.
Related
I have some classes inherited from QGraphicsItem, I also have buttons in my interface. Right now, when I press a button, an item is created in the scene. I have such signal/slot system for all of my classes, so as a result I have a lot of slot functions that are very similar, and the only difference is in the type of objects they create. Is this a good programming practice or not, because it doesn't look like it. Is there a way to simplify this?
Armchair is a class inherited from QGraphicsItem
armchair is an object of this class
this is a code example of such slot function
void MainWindow::armchairButton_clicked()
{
scene_preview->clear();
armchair = new Armchair();
scene_preview->addItem(armchair);
}
There is no general fixed rule for this, just the DRY principle (Don't Repeat Yourself).
In general, every button has a distinct function, so there must be some code to distinguish those.
Depending on how much code is common and how much is individual, you need to find a good balance.
In your case, you seem to only have 1 thing to change (the object type to add) and some common code for cleaning. This could be separated, e.g.
void MainWindow::replaceSceneObject(QGraphicsItem *i)
{
scene_preview->clear();
scene_preview->addItem(i);
}
void MainWindow::armchairButton_clicked()
{
replaceSceneObject(new Armchair);
}
As you use manual connects, you actually don't need separate slots for this, but could use lambdas in the connect calls, e.g.:
connect(armchairButton, &QPushButton:clicked, [=]{ replaceSceneObject(new Armchair); });
Qt provides the QSpinBox, which is some far QObject derivative that provides a signal:
class QSpinBox:
public /* ... */ QObject {
signals:
void valueChanged(int i);
};
When deriving from this spin box, I might provide an override for this signal to emit some beautified version of the value:
class MySpinBox:
public QSpinBox {
private slots:
void originalValueChanged(int i) {
/* Beautify */
emit valueChanged( 42 * i );
}
signals:
void valueChanged(int myPersonalI);
};
This seems perfectly fine: The signal MySpinBox::valueChanged(int) hides the inherited signal. The only bit missing is to connect the inherited QSpinBox::valueChanged(int) to the private slot MySpinBox::originalValueChanged(int).
While this is possible using the new signals and slot syntax:
connect(
static_cast<QSpinBox *>(this), &QSpinBox::valueChanged,
this, &MySpinBox::originalValueChanged);
I am neither sure if this is allowed or sensible, nor how to connect the signal using the conventional string based signal/slot syntax. Using the latter, the slot is obviously connected to the MySpinBox::originalValueChanged(int) signal, which is clearly not intended.
Purpose
The above example is reduced to the problem I think I face. To understand why I ran into the problem and maybe to guide me out of this (pretended) broken design, think of a QDoubleSpinBox derivative to enter some physical quantitiy, e.g. speed. The user may want to enter this in some preferred unit, which may be km/h or mph. To get the unit conversion logic out of the application, I composed a new widget, derived from QWidget and containing only a QDoubleSpinBox. Then I implemented the usual spin box methods (setMinimum, setSingleStep etc.) that take the respective properties in SI dimension (i.e., m/s in this example), convert them to some chosen unit and then configure the inferior double spin box.
A setValue(double) converts its argument to the user's unit and passes it on to the inferior. In turn, there is a valueChanged(double) signal that is emitted whenever the inferior spin box emits valueChanged, but with the quantity converted back to the SI dimension.
So in the end I was tinkering about not composing a QWidget derivative with an inferior spin box but to derive from the QDoubleSpinBox and reimplement.
Pros and cons appear partly clear, including the issue explained by #Pavel Strakhov below already. Composing the widget in fact gets me rid of wrongly inherited methods being called (due to not being virtual), at the cost of a wrapping QWidget. So as an intermediate step, I'm tinkering of deriving private from QDoubleSpinBox. This is surely not a matter of resources in a GUI application, but to me it's also a matter of learning and tinkering.
Then I stumbled about the signal and wondered what Qt might think about it.
Note that QSpinBox::valueChanged is not virtual, meaning that if one have an instance of MySpinBox stored in QSpinBox* pointer and calls its valueChanged method, QSpinBox::valueChanged will be executed instead of MySpinBox::valueChanged. And Qt internal functions will definitely have QSpinBox* pointer to the instance. This inconsistency can be a source of errors. Non-virtual functions are not meant to be redefined in subclasses, and you should not do that. Neither of Qt built-in classes uses such redefinition. Subclasses usually add new signals leaving base class signals untouched.
Currently I'm aware of the following Dispatcher objects.
If you have a text view, you can use IWpfTextView.VisualElement.Dispatcher.
If your class is constructed by MEF (marked with [Export] and not directly constructed from your own code), then you can use the fact that the MEF part resolution algorithm and construction occurs on the UI thread, allowing the use of Dispatcher.CurrentDispatcher. For example:
[Export(typeof(ISomeInterface))]
public class MyClass : ISomeInterface {
private readonly Dispatcher _dispatcher;
public MyClass() {
_dispatcher = Dispatcher.CurrentDispatcher.
}
}
You can use Application.Current.Dispatcher from any code.
What, if any, is the recommended practice for obtaining a Dispatcher?
Do not take a dependency on MEF composing on UI thread. If it works for you right now, you're just getting lucky. Also MEF is delayed in nature and full of Lazy, so if you happen to realize it on a background thread, the entire subgraph will get realized on background.
I would use #1 or #3 (doesn't matter which, there is only one UI thread dispatcher, doesn't matter how you get to it).
Consider signal manager that receives the signal, checks for some conditions, and if they are met, transmits signal to slot, discarding signal otherwise:
signal(some args) ---> [manager] ---> slot(some args)
I can implement it for each given set of arguments using QMetaObject::invokeMethod, say for void signal(int) and void slot(int):
.h
class Manager: public QObject
{
Q_OBJECT
public:
Manager(QObject* sender,const char* signal, QObject* recv, const char* slot);
private:
bool isOkToSend();
QString slotInvokeSyntax;
QObject *recv;
private slots:
On_Signal(int);
}
.cpp
Manager::Manager(QObject* sender,const char* signal, QObject* recvIn, const char* slot)
: slotInvokeSyntax(slot)
, recv(recvIn)
{
connect(sender,signal,this,SLOT(On_Signal(int));
//retrieving method name only
slotInvokeSyntax.remove(0,1).remove(QRegExp("(*",Qt::CaseSensitive,QRegExp::Wildcard));
}
Manager::On_Signal(int val)
{
//invoking slot
if(isOkToSend())
QMetaObject::invokeMethod(recv,slotInvokeSyntax.toAscii().constData(),Q_ARG(int,val));
}
I would like to somehow generalize this for signals and slots with generic number/type of arguments - so that manager works on any pairs like signal(QString)-slot(QString), signal(int,int)-slot(int,int), ...
Is there any way to implement this functionality without adding slot for each of the argument types in Manager? In case my approach is in wrong in general, any suggestions on how to implement such manager are welcome!
EDIT
A bit of clarification on what am I trying to implement - I have large system with several possible states consisting of many smaller widgets (or sub-systems) (some sub-systems can also act both as stand-alone applications or as a part of the larger system). I'm trying to implement global observer that intercepts certain ui events (such as buttons clicks, edits in QLineEdit, QDropbox changes, etc.), and either let corresponding slot of the widget to be called, or discards it if desired action interferes with the global state of the system. I would like to do it through intercepting signal since it allows to avoid dependencies between system components and compiling each subsystem as stand-alone library (with observer not being dependent on any other part of the system and thus being put in core library), but I'm open to any other alternatives that will allow me to achieve that!
FYI, whenever you use something like this:
QString foo;
something(foo.toAscii().constData());
...you are accessing already freed memory because the data pointed to by the QByteArray::constData are valid only until the QByteArray instance lives and is not modified. In your case, the QByteArray is a temporary created by calling foo.toAscii() and is destroyed before the something is called. So this will crash at some point. edit: this does not apply to function calls, see the comments.
To your question -- it would be interesting to know what you're trying to achieve here. The Qt's metatype and metaobject system is indeed a rich one, but abusing it too much might not be the most ellegant way of solving your problem. That said, it's probably fine to use it in this "creative" way with mocked objects, in unit tests etc.
I haven't done this myself and I am not sure whether it's doable without having to touch the q_static_metacall, but it looks like QObject generic signal handler contains an answer to your question.
After Edit:
You said you're looking for a something like a common event bus; the alleged reason is to avoid excess rebuilds when the individual components change. I would not introduce a central interceptor to this architecture. If the toal amount of states is reasonably small, why don't you just let something emit signals upon entering a particular state and have all of your components react to that by enabling/disabling the individual QActions?
I am writing an application of middle size. I will have many gui components and many classes. However, it is difficult for me to organize the code, to separate the logic, ... For example, let say that I press one button that creates an object of a class and perform a computation on that object. After exiting the slot function of the button, this local object is destroyed. What if I need it in another function later? Defining everything as a global variable in the header file is not a good thing for me. So I was thinking of a static class that contains somehow pointers to all the objects I will need later. Does anybody has a better idea?
How to manage objects inside an application is always a tricky
question. Qt goes down a very object-oriented route and uses reference
semantics implemented through pointer for nearly everything. To
prevent tedious manual memory management Qt organizes everything into
Object Trees. This
is augmented by Qt own
object model that adds
some dynamic capabilities.
If you want to go down that route, stick to everything Qt provides. It
is much more similar to Java than the usual C++ approach and might be
more comforting for beginners and maybe suits your application
domain. It tightly ties your code to Qt and will make it hard to
separate from it.
One other approach means to simply forgo all Qt stuff and work out the
core logic of your application. Develop it in pure C++ and than have a
thin layer that ties this logic into your Qt application through
signals and slots. In such an approach you would opt to use more
value-semantics.
For your concrete example of creating an algorithm and keeping it
around. The Qt approach:
class MyAlgo : public QObject {
Q_OBJECT
public:
MyAlgo(QObject* o) : QObject(o) { }
virtual compute();
};
// use it in a mainwindow slot
void MainWindow::executeAlgorithm(const QString& name) {
MyAlgo* algo = this->findChild<MyAlgo*>(name);
if(!algo) {
// not found, create
algo = new MyAlgo(this); // make mainwindow the parent of this algo
algo->setName(name); // QObject name property
}
algo->compute();
}