I am kinda sick of making subclasses for each minor modification I need to make in QWhateverView behaviour so I got an idea:
What if I make a ProxyView for most commonly overriden functions that will essentially do stuff like:
//(mousePress used as an example)
void ProxyView::mousePressEvent ( QMouseEvent * event )
{
if(mousePressFunctionHandler != nullptr)
functionHandler(this, event);
else
QTreeView::mousePressEvent(event);
}
While it's true that I won't have access to view's internals this way, I often don't need it anyway... The only thing stopping me so far is that I am not sure if this idea is sane or not... :)
Or is there better way?
It seems you need to use event filters.
Related
In my Qt (6.3.1) application, for a model I developed, I noticed the submit() method being called all the time.
After some debugging, I noticed, in void QTableView::setSelectionModel/QTreeView::setSelectionModel, this:
if (d->selectionModel) {
// support row editing
connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
d->model, SLOT(submit()));
}
The documentation for QAbstractItemModel::submit() mentions "this function is typically used for row editing", which means this is done on purpose.
I have got more than 1 problem with this way of doing things, compared to the alternative of letting/requiring application developers to create the connection themselves:
Views do not seem to have a property to stop this connection from being created, hence the behavior is more than just a default, it is mandatory.
I do not see any way to know what to do except looking through Qt's source code. I had rather have to create the connection myself if I want it.
Only QSqlTableModel seems to have a mechanism to handle this (editStrategy()) but I could find nothing in neither QAbstractItemModel nor QAbstractTableModel.
-> what would be a good reason to want this connection above to be always created? Or am I perhaps wrong thinking this design is a bad one?
Answering my own question after 4 weeks without another answer nor any comment.
Despite having found a solution that seems to work in every case (see below), I still think this very design choice made by Qt as well as other special case they implemented are bad choices, would be interested to read other opinions in the comments.
Better than disconnecting signals, the solution I ended up implementing was to subclass QIdentityProxyModel and create an attribute to block the calls to submit (+ optionally revert).
void MyModel::revert() {
if (forwardRevertCalls)
QIdentityProxyModel::revert();
}
bool MyModel::submit() {
if (forwardSubmitCalls)
return QIdentityProxyModel::submit();
else
return false;
}
The reason for this choice is because of another special case in QStyledItemDelegate::eventFilter. Found in the documentation:
If the editor's type is QTextEdit or QPlainTextEdit then Enter and Return keys are not handled.
And I suppose things like QSpinBox do not behave this way.
This was causing submit to be called whenever I pressed Enter to validate an input in my model and change the selected row in 1 input; more precisely, it would execute case QAbstractItemDelegate::SubmitModelCache in QAbstractItemView::closeEditor.
I'm trying to develop a game controller for an android app in qt and am having some issues. The controller works perfectly fine when I just use QMouseEvents instead of QTouchEvents, but the problem is that it doesn't support multiple points of contact. There doesn't seem to be an equivalent for QWidget::mousePressEvent for touch events. I was told to use QWidget::event instead as such.
bool GameController::event(QEvent* event)
{
switch(event->type())
{
case QEvent::TouchBegin:
//Do something...
break;
case QEvent::TouchEnd:
//Do something else...
break;
case QEvent::TouchUpdate:
//Do something else...
break;
}
return QWidget::event(event);
}
The problem with this is that I'm unable to use event->touchPoints() to get the position of the touches because it doesn't know that its a touch event. How can I properly read touch events?
The compiler may not know it's a touch event, but as long as you know it, you can downcast:
case QEvent::TouchBegin:
{
QTouchEvent * te = static_cast<QTouchEvent *>(event);
// now you can call te->touchPoints(), etc here
}
Note that the above code will invoke undefined behavior if event isn't actually pointing to a QTouchEvent (or a subclass thereof), so only use static_cast when you can 100% guarantee that event is actually a QTouchEvent (which AFAIK you can in this scenario).
For cases where you can't guarantee the downcast will be valid, you can use dynamic_cast instead, which is smart enough to check the pointed-to-object and return NULL if it isn't actually valid to downcast to that type:
case QEvent::TouchBegin:
{
QTouchEvent * te = dynamic_cast<QTouchEvent *>(event);
if (te)
{
// now you can call te->touchPoints(), etc here
}
}
Of course that runtime check costs a few CPU cycles, so don't use dynamic_cast unless you need to.
All of the protected functions/event handlers for various types of events for QWidget (e.g. QWidget::showEvent(QShowEvent*), QWidget::hideEvent(QHideEvent*)) are specializations of the general QWidget::event() method for your convenience.
And QWidget::event() itself is implemented through the QObject::eventFilter() virtual method. You can read more about it here - https://doc.qt.io/qt-5/qobject.html#eventFilter. Through the help of bool eventFilter(QObject *obj, QEvent *ev) override, you can get notified about all QEvents that are sent to your QObect as well as to other objects through the use of QObject::installEventFilter().
In the body of your implementation of QObject::eventFilter() you check the type of the event as well as its receiver and then after that do either static_cast or dynamic_cast as described by #Jeremy Friesner to access the methods specific to that event. Using this powerful mechanism you can implement your own specialized event functions, as well as custom signals, if you want your sub-classed QObject to emit a signal in case of an event.
Excuse me for cross-posting on Software Engineering, didn't know that it was frowned upon.
The answer I was got there was exactly what I was looking for, for those curious: https://softwareengineering.stackexchange.com/a/347143/269571
Original question
I'm reading the book "Agile Software Development, Principles, Patterns, and Practices" by Robert C. Martin.
When he talks about the Dependency Inversion Principle he gives the following example of a DIP violation:
This seems very clear to me, as the higher-level object Button is depending on a lower-level object Lamp.
The solution he comes with is:
He creates an interface so that way Button is no longer depending on the object Lamp.
The theory seems really clear to me, however I can't wrap my head around using the principle in real-life projects.
Who is going to determine what classes (that implement SwitchableDevice) need to be called?
Who tells Button what devices he need to turn on/off?
How do you tell an object that uses something abstract which concrete things it needs to use? (Please correct me if this question is completely wrong)
If anything is unclear about my question, please let me know, I'll be glad to clarify things for you.
The whole point of dependency injection (at least as I understood it) is that the Button does not need to know what concrete SwitchableDevice it is switching.
The abstract interface could look like this:
struct SwitchableDevice {
virtual void switchOn() = 0;
virtual void switchOff() = 0;
};
And the button could be implemented like this:
struct Button {
SwitchableDevice& dev;
bool state = false;
Button(SwitchableDevice& d) : dev(d) {}
void buttonPress(){
if (state) { dev.switchOff(); }
else { dev.switchOn(); }
state = !state;
}
};
For the button, thats it! Noone needs to tell the button what is the concrete implementation of the SwitchableDevice, in other words: The implementation of the Button and the SwitchableDevice are decoupled.
A possible implementation of a Lamp could look like this:
struct Lamp : SwitchableDevice {
void switchOn(){std::cout << "shine bright" << std::endl;}
void switchOff(){std::cout << "i am not afraid of the dark" << std::endl;}
};
And that could be used like this:
int main(){
Lamp lamp;
Button button(lamp);
button.buttonPress();
button.buttonPress();
}
Hope that helps...
The benifit is that now we can change the implementation of the Button and the Lamp individually, without having to change anything on the other part. For example a ButtonForManyDevices could look like this:
struct ButtonForManyDevices {
std::vector<SwitchableDevice*> devs;
bool state = false;
Button(std::vector<SwitchableDevice*> d) : devs(d) {}
void buttonPress(){
if (state) for (auto d: devs) { d.switchOff(); }
else for (auto d: devs) { d.switchOn(); }
state = !state;
}
};
And similarly you could change the behaviour of the Lamp completely (of course within the limits of SwitchableDevice without having to change anything on the button. The same ButtonForManyDevices could even be used to switch a Lamp, a VaccumCleaner and a MicroWaveOven.
He's saying that what a button controls should be more generalized than just a lamp. If you have button classes for each type of thing that a button can control, then you could wind up with a lot of button classes.
In the first example, one is describing a button on a lamp. It essentially is taking the lamp as the starting point and dividing it into components.
In the second example, he is dividing the parts and looking at a button more generally.
Who is going to determine what classes (that implement SwitchableDevice) need to be called?
There is going to have to be a link between the button and the interface.
Who tells Button what devices he need to turn on/off?
The Button class would need to implement a mechanism to tell what device it is connected to.
How do you tell an object that uses something abstract which concrete things it needs to use? (Please correct me if this question is completely wrong).
Because an object that derives from an abstract interface must fully implement the interface. A Lamp object must define a TurnOn and TurnOff method somewhere..
In my application, I have my re-implemented QGraphicsView checking for a mouseReleaseEvent(), and then telling the item at the position the mouse is at to handle the event.
The QGraphicsItem for my view is made up of two other QGraphicsItems, and I check which one of the two is being clicked on (or rather having the button released on), and handle the respective events.
In my Widget's constructor, I set one of the items as selected by default, using the same methods I used when the items detect a release.
When I debugged, I found that for the LabelItem, select is called without a problem from the constructor (and the result is clear when I first start the application). But, when I click on the items, the application terminates. I saw that I was getting into the select function, but not leaving it. So the problem is here.
Which is very weird, because the select function is just a single line setter.
void LabelItem::select()
{
selected = true;
}
This is the mouseReleaseEvent;
void LayerView::mouseReleaseEvent(QMouseEvent *event)
{
LayerItem *l;
if(event->button() == Qt::LeftButton)
{
l = (LayerItem *) itemAt(event->pos());
if(l->inLabel(event->pos()))
{ //No problem upto this point, if label is clicked on
l->setSelection(true); //in setSelection, I call select() or unselect() of LabelItem,
//which is a child of LayerItem, and the problem is there.
//In the constructor for my main widget, I use setSelection
//for the bottom most LayerItem, and have no issues.
emit selected(l->getId());
}
else if(l->inCheckBox(event->pos()))
{
bool t = l->toggleCheckState();
emit toggled(l->getId(), t);
}
}
}
When I commented the line out in the function, I had no errors. I have not debugged for the other QGraphicsItem, CheckBoxItem, but the application terminates for its events as well. I think the problem might be related, so I'm concentrating on select, for now.
I have absolutely no clue as to what could have caused this and why this is happening. From my past experience, I'm pretty sure it's something simple which I'm stupidly not thinking of, but I can't figure out what.
Help would really be appreciated.
If the LabelItem is on top of the LayerItem, itemAt will most likely return the LabelItem because it is the topmost item under the mouse. Unless the LabelItem is set to not accept any mouse button with l->setAcceptedMouseButtons(0).
Try to use qgraphicsitem_cast to test the type of the item. Each derived class must redefine QGraphicsItem::type() to return a distinct value for the cast function to be able to identify the type.
You also could handle the clicks in the items themselves by redefining their QGraphicsItem::mouseReleaseEvent() method, it would remove the need for the evil cast, but you have to remove the function LayerView::mouseReleaseEvent() or at least recall the base class implementation, QGraphicsView::mouseReleaseEvent(), to allow the item(s) to receive the event.
I have seen these odd behaviours: It was mostly binary incompatibility - the c++ side looks correct, and the crash just does not make sense. As you stated: In your code the "selected" variable cannot be the cause. Do you might have changed the declaration and forgot the recompile all linked objects. Just clean and recompile all object files. Worked for me in 99% of the cases.
Right now, I'm making a Gui Library for games. The Widgets have several callbacks / listeners for various events.
The thing about it is a listener can consume an event.
The issue comes here. The base class is called with event info. It calls the callbacks for the listeners. Any of them can handle the event.
This means it is up to the user to check if the event has been handled or not.
Ex:
void TextBox::MouseClick(MouseEvent &event)
{
Widget::MouseClick(event);
if(!event.isHandled())
{
//do stuff
}
}
The alternative would be to hide this and have onMouseClick(...) which is the virtual one and not called unless the condition is met. I found this to be rather messy though, and annoying for those who make more events.
Is this a good design? If not what might be better to accommodate this?
Thanks
If you want to this for many events, I'd rather go the onMouseClick way (IIUC):
void TextBox::onMouseClick(MouseEvent &event)
{
//do stuff or empty of not needed
}
in class Widget:
void Widget::MouseClick(MouseEvent &event) // nonvirtual
{
// do the listeners' stuff
if(event.isHandled()) onMouseClick(event);
}