Can't capture QkeyEvent in QopenGLWidget - c++

I have a problem about capturing QKeyEvent in a QOpenGLWidget when I use it as a... widget. It works perfectly well if I use my QOpenGLWidget as a main window but not if the widget is the child of another mainWindow... (Nothing happen)
Maybe I messed up something about how Qt widgets works but I can't figure it out.
Thank you

Try calling yourGLWidget->setFocusPolicy (Qt::StrongFocus);
From http://doc.qt.io/qt-5/qwidget.html#focusPolicy-prop: "You must enable keyboard focus for a widget if it processes keyboard events. This is normally done from the widget's constructor."

I guess either your mainWindow treat the QKeyEvent (maybe it's an already mapped key combination) or prevents the forwarding to your custom widget component. Either when used as "QWidget", special rules are applied and you need to override some others handlers to make your handler able to take place.

Related

Changing the behavior of a widget type in another class

I have a MainWindow class in Qt, in which several checkable QGroupBox widgets are placed.
What I want to do is, to trigger a general onClick(bool checked) slot whenever one (any) of the QGroupBox objects are clicked, identify the sender and trigger some code.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
This is the signal I'm trying to handle:
class Q_WIDGETS_EXPORT QGroupBox : public QWidget
{
...
Q_SIGNALS:
void clicked(bool checked = false);
...
};
I tried adding a custom slot like this and tried connecting it with the signal above but since QGroupBox at its own is not an object or pointer, the operation fails.
void MainWindow::onClick(bool clicked)
{
qDebug()<<"Custom slot triggered";
}
Long story short, I need to handle a control type's default behavior within my MainWindow class.
Thanks for any ideas in advance.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
Perhaps, but I'm smelling an XY Problem here. You can certainly prevent emission of signals by invoking blockSignals() on the widget. But that's a hack - it will also prevent Qt's internals from acting on the object's destroyed() signal, and you might subtly break other users of the object's signals.
Instead, one could make the UI stateful and have the controller implement the stateful aspect of the button's interaction with the rest of the application. Currently, the button's clicked() signal is connected directly to other users. Instead, connect the button to the controller, and have the controller disable the children only when it's appropriate to do so. One could use the QStateMachine to make this stateful behavior explicit in terms of states.
#Kuba Ober, maybe you're right, I could not state my problem and the facts around it seperately and clearly. Thank you for pointing that out.
After checking out the QGroupBox class' source, I discovered that a "toggle" signal is emitted after every other operation in a "clicked" event.
http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qgroupbox.cpp
void QGroupBox::setChecked(bool b)
{
Q_D(QGroupBox);
if (d->checkable && b != d->checked) {
update();
d->checked = b;
d->_q_setChildrenEnabled(b);
#ifndef QT_NO_ACCESSIBILITY
QAccessible::State st;
st.checked = true;
QAccessibleStateChangeEvent e(this, st);
QAccessible::updateAccessibility(&e);
#endif
emit toggled(b);
}
}
By combining this information with that of #rbaleksandar 's suggestion, I managed to obtain a solution.
I iterated through the controls of my MainWindow class and connected every QGroupBox's "toggle" signal with a common "MainWindow::onToggle" slot in which I could handle the post-event operations I desire.
As for my previous approach, I could've created a class which inherits QGroupBox and override any methods I wish to. But that would be overkill compared to my current solution. The fix I've came up with did the trick perfectly.
Thanks everyone for their insight and help.

GTKmm Why the signal_hide() signal doesn't emit correctly?

I've got a Gtk::Box container (maincontroller) and inside of it, there is a Gtk::Grid (mainmenu). I've added a signal in the maincontroller.cpp like this:
mainmenu->signal_hide().connect(
sigc::mem_fun(this, &MainController::Elmozdulas)
);
When i press a button in the mainmenu, i call the hide() function, what works correctly, i don't see anything after that, but it doesn't emit the signal, only if i close the window. Why is that and how could i fix it?
Thanks for your answers in advance!
You might consider binding to signal_unmap instead. I think signal_hide only gets called if the widget is hidden, not if one of its parents are. Neither of these would be triggered if hide is actually called on a child of mainmenu rather than mainmenu itself. In that case it would appear like mainmenu had been hidden, but would in fact still be visible (and mapped, and realized).

QMainWindow no longer active window

I'm making a simple game with Qt and I'd like to pause the game when the user switches to a different window (this could be by minimizing it or by accidentally clicking on a window beside it, etc). My game is wrapped in a QMainWindow, so I'd like to be able to detect when that loses focus.
I've tried a few different methods for this, but I haven't been successful. I first tried overloading QMainWindow's focusOutEvent, but this method was only called when I first gave the window focus with setFocus. I also tried to overload the window's event(QEvent *) method to check for QEvent::ApplicationActive and QEvent::ApplicationDeactivate.
I would post the code for my QMainWindow but there isn't much to show, I literally just tried to implement those two methods but neither were called. I did nothing else to set up those methods (maybe I'm missing a step?).
Does anyone know a good way to determine if your QMainWindow has "lost focus"?
I had a similar need once, and resolved it by overloading event(QEvent*) method of my QMainWindow :
bool MyMainWindow::event(QEvent * e)
{
switch(e->type())
{
// ...
case QEvent::WindowActivate :
// gained focus
break ;
case QEvent::WindowDeactivate :
// lost focus
break ;
// ...
} ;
return QMainWindow::event(e) ;
}
From the documentation -
A widget normally must setFocusPolicy() to something other than
Qt::NoFocus in order to receive focus events. (Note that the
application programmer can call setFocus() on any widget, even those
that do not normally accept focus.)
From this part of the documentation, about focusPolicy-
This property holds the way the widget accepts keyboard focus.
The policy is Qt::TabFocus if the widget accepts keyboard focus by
tabbing, Qt::ClickFocus if the widget accepts focus by clicking,
Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if
it does not accept focus at all.
You must enable keyboard focus for a widget if it processes keyboard
events. This is normally done from the widget's constructor. For
instance, the QLineEdit constructor calls
setFocusPolicy(Qt::StrongFocus).
So set your focus policies accordingly, I guess then you will receive appropriate focus events.
Try QWidget::isActiveWindow() .

Forcing QDialog to stay open

How should I best go about forcing a QDialog to stay open when the dialog's accept() slot is called? I was thinking of reimplementing that function to get the dialog's exec to return without hiding the dialog, but was wondering if there were any better ways to accomplish this.
Rather than use a QDialog, I would accomplish the effect with a QDockWidget.
Remove the feature that allows the dock to be moved (QDockWidget::DockWidgetMovable)
Set the dock widget to floating (setFloating(true))
Connect items on the dock widget to the appropriate signals and slots on the main window
References
Dock Widgets Example
QDockWidget Documentation
You need to make your QDialog modeless, by calling show instead of exec, and using a custom signal instead of accept, because accept closes the window. And you connect that signal to a slot in the main window with the code you had after the exec call.
And in case that wasn't already the case, you should keep a reference/pointer to your QDialog somewhere (as a member in your main window class, or a static variable within the function that opens it) to be able to avoid creating multiple instances of the dialog, and you need to make sure you only connect the signals/slots once.

Is there a way to determine if a top level Qt window has been moved?

I am trying to determine when the main window of my application has been moved. The main window is a standard QMainWindow and we've installed an eventFilter on the QApplication to look for moveEvents for the QMainWindow, but none are being triggered. For a variety of reasons, subclassing the QMainWindow isn't really an option.
Any thoughts on this, aside from starting a QTimer tto constantly check the position, would greatly be appreciated.
I guess it's better to install the event filter at the top-level window, instead of the application. However, if you still do not get QMoveEvents and you're working on Windows, you probably can override winEventFilter() and wait for WM_MOVE. Similar functionality might be available for Linux and Mac.
I usually do not recommend to break the platform-independence, but sometimes it might make sense.
Subclassing is really the best solution :-/
In the class that implements your top level windows you just overload this function:
virtual void moveEvent ( QMoveEvent * event )
From the documentation:
This event handler can be
reimplemented in a subclass to receive
widget move events which are passed in
the event parameter. When the widget
receives this event, it is already at
the new position.
The old position is accessible through
QMoveEvent::oldPos().
This should allow you to detect if your main window has moved. Why can't you subclass? Are you using an instance of QMainWindow directly? The usual use case is to subclass it anyway.