I am trying to adapt this solution for Android tablet
The problem is QEvent::KeyPress is not fired on a tablet when using a virtual keyboard.
After some trial and error, I found what QEvent::InputMethod fired instead.
So, a simple modification make it working on tablet:
if ( event->type() == QEvent::KeyPress || event->type() == QEvent::InputMethod)
But this is complete nonsense because one line further it is converted to QKeyEvent:
QKeyEvent* pEvent = dynamic_cast<QKeyEvent*>( event );
I don't get why I don't have runtime exception, because InputMethod simply have no member key()
Even if it is working it is not safe.
How i should handle input in the correct way?
Related
My app uses Xamarin.Forms. Now I am trying to apply IceLink for implementing video calls. Is there a way to switch between front/rear/anyOther camera? I saw a sample where LocalMediaStream's UseNextVideoDevice() method is used, but now LocalMediaStream is obsolete, and I don't have it. But I do have IceLink.FM.LocalMedia object in my PageModel.
public void SwitchCamera()
{
if (_localMedia == null)
return;
// _localMedia.UseNextVideoDevice(); // obsolete
}
Is it possible to make that switch between cameras?
I want to intercept Tab key press in my main window to prevent Qt from switching focus. Here's what I've tried so far:
bool CMainWindow::event(QEvent * e)
{
if (e && e->type() == QEvent::KeyPress)
{
QKeyEvent * keyEvent = dynamic_cast<QKeyEvent*>(e);
if (keyEvent && keyEvent->key() == Qt::Key_Tab)
return true;
}
return QMainWindow::event(e);
}
This doesn't work, event isn't called when I press Tab. How to achieve what I want?
The most elegant way I found to avoid focus change is to reimplement in your class derived from QWidget the method bool focusNextPrevChild(bool next) and simply return FALSE. In case you want to allow it, return TRUE.
Like other keys you get now also the key Qt::Key_Tab in keyPressEvent(QKeyEvent* event)
Reimplementing virtual bool QApplication::notify(QObject * receiver, QEvent * e) and pasting the code from my question there works.
You can achieve by using setFocusPolicy( Qt::NoFocus) property of QWidget. You can set Focus policy on widget which doesn't require tab focus. I think the reason why event handler is not calling, because Tab is managed by Qt framework internally. Please see QWidget::setTabOrder API, which is static.
You'll need to install an event filter on your main window in order to receive the events. You can use installEventFilter method for this.
Another option is to override the keyPressEvent method to handle the key presses.
I took the example of the Poppler Library to render PDF on Qt platform. I am trying to write gesture handling for the example.
The example can be downloaded from "doc.qt.digia.com/qq/qq27-poppler.zip" URL.
In a nutshell, the example has a DocumentWidget.cpp which is Derived from "QLabel" which in turn derives from QFrame and QWidget.
Now since QLabel is inherited from QWidget I have started implementing for Gesture Handling.
in DocumentWidget.h i have added the below function
protected:
bool event( QEvent* e );
in DocumentWidget.cpp constructor
grabGesture( Qt::TapGesture )
bool DocumentWidget :: event( QEvent* e )
{
if( e->type() == ( Qt :: TapGesture )
gestureEvent();
}
In the above gestureEvent function I try to check if it is Tap and correspondingly planning to handle the tap event. However, In my example the event function is getting called but the tap gesture is being handled.
I have included all the necessary header files. I have forward declared the classes too.
Can you please tell me where am I going wrong. Can't we handle these gestures for QLabel.
Thank You in advance.
Chand.M
You are already checking for TagGesture in the event handler. So you need not check it once again in the gestureEvent() function. Moreover after consuming the event you have to return true; stating that the even has been consumed.
If the even is not a TapGesture then pass it to the QWidget itself like this.
if( e->type() == ( Qt :: TapGesture )
gestureEvent();
else
return QWidget::event(e);
You can find documentation on even handling here.
I have overridden the contentsMousePressEvent in my listview like this.
void AppListView::contentsMousePressEvent(QMouseEvent *e)
{
AppGenericListView::contentsMousePressEvent(e);
if (e->button() == Qt::RightButton)
emit rightClicked();
emit multiSelection();
}
Here is my keyPressEvent.
void AppListView::keyPressEvent(QKeyEvent * e)
{
AppGenericListView::keyPressEvent(e);
if ((e->key() == Qt::Key_Up) || (e->key() == Qt::Key_Down))
{
QListViewItem * item = currentItem();
if (item)
{
const QRect rect = itemRect(item);
QMouseEvent mEvt(QEvent::MouseButtonPress, rect.center(), Qt::LeftButton, Qt::LeftButton);
contentsMousePressEvent(&mEvt);
}
}
}
For now, this code working fine. Please note that i'm not creating a dynamic QMouseEvent object. What i want to know is will this cause a crash in future ? Does contentMousePressEvent need a dyanamic object ? Qt doc doesn't say much about it. Any ideas ....
It won't crash, because you are not using event loop. But i think you should, for two reasons:
You are simulating mouse press event but you are not serving it to the object as a such. For example, you don't serve your fake mouse event to mousePressEvent(). So for "natural" mouse press events and your simulated one, the application will behave differently. And you may forget why is that and you may get inexplicable crashes when your code evolves.
The original system keypress event handling will be blocked by handling a mouse press event. You can't know who (what thread) will connect() to your signals emitted from overriden mouse event handler. Don't be surprised if you get a deadlock.
Such a half baked shortcuts are good only as temporary solutions. In the long run, they will shoot at your back. If you really want a shortcut, stop pretending it's a mouse event and implement a special separate method which will be called also from the "real" mouse event. If you want a real mouse event, handled properly, create a dynamic QMouseEvent and enqueue it at the event loop.
QMouseEvent* evt = new QMouseEvent(QEvent::MouseButtonPress,
rect.center(),this->mapToGlobal(rect.center()),
Qt::LeftButton, Qt::LeftButton);
QCoreApplication::postEvent(this,evt);
The event handlers don't take ownership of the events they receive. So your current code is fine.
It would be deleted automatically (and cause a crash), if you were passing it to QCoreApplication::postEvent to be sent asynchronously.
When user types in a QWidget based window, I wanted a QLineEdit to process
all input keys,
so I tried the following two solution in keyPressEvent() of that QWidget:
A.
void Window::keyPressEvent (QKeyEvent *e)
{
switch (e->key())
{
// handle other short cuts
default:
QApplication::sendEvent (lineEdit , e);
break;
}
}
Well, this sometimes crashes the whole interface, especially when I resize window.
B.
void Window::keyPressEvent (QKeyEvent *e)
{
switch (e->key())
{
// handle other short cuts
default:
if ( ! lineEdit.hasFocus () )
{
lineEdit.setFocus ();
lineEdit.setText (e->key());
// i wanted to push the first key input to that QLineEdit , but how ?
// or i'll miss it
}
break;
}
}
Also I'm thinking about giving lineEdit focus all the time, but I can't do that as other events needed to be handled by the main UI.
Update
It won't crash when I filter key inputs, but why ?
default:
if ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ||
(e->key() >= Qt::Key_A && e->key() <= Qt::Key_Z )
)
QApplication::sendEvent(filter , e);
break;
}
I believe you are running into a crash because you are using sendEvent to send an event object that you don't have control over.
I don't think the Qt event system expects you to grab its events and throw them in other directions, and it's likely that the event object is getting destroyed before the line edit expects. In the case where you're filtering out input keys, it's probably not crashing because the line edit doesn't care about those kinds of key strokes and isn't using the event object as much as it would otherwise.
If you really want to use the sendEvent() functionality, then I would suggest you create your own QKeyEvent on the stack and pass it to the sendEvent() function (as demonstrated here), or you can just do something like this:
lineEdit.setText( lineEdit.text() + event->text() );
When a widget does not handle an event, it forwards it to its parent. So using sendEvent() to forward to a child is dangerous, as it can make a recursion.
The easiest way of doing it would be to use QKeyEvent::text instead of QKeyEvent::key and you should be OK. You might also try to create a copy of QKeyEvent and pass it to your QLineEdit. Thos are rather hacks than solutions though. If you need shortcuts in main window while QLineEdit has focus (assuming it is in this window) you can use QShortcut with Qt::WidgetWithChildrenShortcut context - this way you can keep your LineEdit active at all times.