Capturing modifier keys Qt - c++

I am trying to understand how to handle various events with Qt and have found an issue I cannot understand with key modifiers e.g. Ctrl Shift Alt etc. I have made a default Qt GUI Application in Qt Creator extending QMainWindow and have found that the following example does not produce understandable results.
void MainWindow::keyPressEvent(QKeyEvent *event)
{
qDebug() << "Modifier " << event->modifiers().testFlag(Qt::ControlModifier);
qDebug() << "Key " << event->key();
qDebug() << "Brute force " << (event->key() == Qt::Key_Control);
}
Using the modifiers() function on the event never is true while the brute force method returns the correct value.
What have I done wrong?

Try using this to check for shift:
if(event->modifiers() & Qt::ShiftModifier){...}
this to check for control:
if(event->modifiers() & Qt::ControlModifier){...}
and so on. That works well for me.
EDIT:
To get the modifiers of a wheel event, you need to check the QWheelEvent object passed to your wheelEvent() method:
void MainWindow::wheelEvent( QWheelEvent *wheelEvent )
{
if( wheelEvent->modifiers() & Qt::ShiftModifier )
{
// do something awesome
}
else if( wheelEvent->modifiers() & Qt::ControlModifier )
{
// do something even awesomer!
}
}

According to the documentation, QKeyEvent::modifiers cannot always be trusted. Try to use QApplication::keyboardModifiers() static function instead.
From Qt 5 Doc. – Qt::KeyboardModifiers QKeyEvent::modifiers() const:
Warning: This function cannot always be trusted. The user can confuse it by pressing both Shift keys simultaneously and releasing one of them, for example.

Related

How can I make Qt recognize a sequence of keys?

In my current application, I need to make QT close a window by pressing Shift + Eesc or by pressing Esc 3x.
First, I tried Shift + Esc, it went this way
if ((event->key() == Qt::Key_Escape) && (event->key() == Qt::Key_Shift))
{
cout << "test" << endl;
on_close_x_button_clicked();
}
But for some reason, it just doesn't work. I googled it and found something about a QKeySequence but I didn't find any example of how to do it properly. I tried some ways with no success like:
if ((event->key() == Qt::QKeySequence(Qt::Key_Escape + Qt::Key_Shift)))
{
cout << "teste" << endl;
on_close_x_button_clicked();
}
}
But again, no dice. Can someone point me how to proper implement this functionality?
I also could not find anything that allowed me to create an event based on pressing Escape key 3x. Can someone, please, also teach me how to do it?
I also tried using Shortcuts, and it went like this:
LinAdvancedTestWidget::LinAdvancedTestWidget(QWidget *parent,
QObject *event_filter,
SystemEvent *event, int dpi)
: AdvancedTestWidget(parent, event_filter, event) {
(void)dpi;
KeyShiftEsc = new QShortcut(this);
KeyShiftEsc->setKey(Qt::Key_Shift + Qt::Key_Escape);
connect(KeyShiftEsc, SIGNAL(activated()), this, SLOT(slotShortcutShiftEsc()));
}
void LinAdvancedTestWidget::slotShortcutShiftEsc()
{
cout << "Escape LinAdvancedTestWidget" << endl;
on_close_x_button_clicked();
}
But it again, also does not work :/
Shift is a modifier, not a key, as you seem to compare. You would need to write something like this:
if ((event->key() == Qt::Key_Escape) && (event->modifiers() & Qt::Key_Shift))
{
...
}
Also, it is better if you use the QWidget::addAction(...) method as:
QAction *action = new QAction("my action", "Shift+Esc");
myWidget->addAction(action);
You can also set multiple shortcuts on an action:
action->setShorcuts({"Shift+Esc", QKeySequence(Qt::Key_Esc, Qt::Key_Esc, Qt::Key_Esc)});

Issues trying to make a filter using Qt

I'm trying to make my software filter a list of elements.
I think I need to put my data in a TableWidget because I have to display other information.
I also put 3 Line Edit to search respectively in each category (called leName, leSource, leDestination)
so I tried to implement my filter for the name property, for now I have :
void MyClass::on_leName_textEdited(const QString &arg1)
{
for (int i=0;ui->tableWidget->rowCount()-1;i++)
{
qDebug()<<"before if";
if(ui->tableWidget->item(0,1)->text().contains(arg1) //tried with &arg1, I have the same issue, for now
{
qDebug()<<"If validated";
ui->tableWidget->showRow(i);
}else{
qDebug()<<"If not validated"
ui->tableWidget->hideRow(i)
}
}
}
When I hit a key, my soft crashes
I get "Before if", "If (not) validated", "Before if" from qDebug
I launched with debbugger and got Segmentation fault as error
not sure what I could add as detail about my error
Maybe I did nothing in the good way, I'm no expert in Qt nor c++
If you have any idea of what I should do to correct this, I would appreciate it =)
The fact that a cell exists does not imply that it has an associated QTableWidgetItem, so you must verify that it is not null.
QTableWidgetItem * item = ui->tableWidget->item(0, 1);
if(item && item->text().contains(arg1))
{
qDebug() << "If validated";
ui->tableWidget->showRow(i);
}else{
qDebug() << "If not validated"
ui->tableWidget->hideRow(i)
}

Get original key as though without shift modifier

I want to create keyboard bindings, which work at least similarly on different keyboard layouts. My problem is that the shift modifier converts keys into different keys, as detailed in the documentation: http://doc.qt.io/qt-5/qkeysequence.html#keyboard-layout-issues
Is there any way to find out the original key irrespective of the keyboard layout?
E.g. find out that . is pressed when shift+. is pressed.
See also this (currently unanswered) quesion: get shift+numerical keys in qt using qkeyevent
In Windows you can use MapVirtualKeyA and MAPVK_VK_TO_CHAR to get the unshifted key. MapVirtualKeyA needs the virtual key, which can be get using QKeyEvent::nativeVirtualKey.
Note: When pressing modifiers only QKeyEvent::key() may report a false character, the virtual key helps to distinguish these cases.
Example
void MainWindow::keyPressEvent(QKeyEvent* ke)
{
const auto vk = ke->nativeVirtualKey();
const auto unshifted_key = MapVirtualKeyA(vk, MAPVK_VK_TO_CHAR);
qDebug() << "Original key:" << (char)ke->key();
qDebug() << "Unshifted key:" << (char)unshifted_key;
if (unshifted_key > 0) {
// Printing the full key sequence just for comparison purposes
QString modifier;
if (ke->modifiers() & Qt::ShiftModifier) modifier += "Shift+";
if (ke->modifiers() & Qt::ControlModifier) modifier += "Ctrl+";
if (ke->modifiers() & Qt::AltModifier) modifier += "Alt+";
if (ke->modifiers() & Qt::MetaModifier) modifier += "Meta+";
const QKeySequence ks(modifier + QChar(ke->key()));
qDebug() << "Full key sequence:" << ks.toString();
}
}
The full source code for the example can be found in here.

How to disable next button in QWizard

What I'm trying to do
I am trying to create a subclass of QWizardPage that looks somewhat like this,but has a slight tweak. I want to disable the next button when a counter variable is more than 0. (It can't be 0 from the get-go due to some functionality that requires it to go x..x-1...0).
What I've tried
Reimplement isComplete() and emit completeChanged() in the constructor
bool DemoWizardPage::isComplete()
{
return ! (counter > 0); //Also tried just return false;
}
Reimplement initializePage and disable the next button from there
void DemoWizardPage::initializePage()
{
qDebug() << "QWizardPage:: initialize page";
if (!this->isComplete())
{
qDebug() << "try to turn off next button";
wizard()->button(QWizard::NextButton)->setDisabled(true);
qDebug() << "next button enabled? "
<< wizard()->button(QWizard::NextButton)->isEnabled();
}
}
Results so far
From stepping through the code I can see that the next button is disabled when the page loads. But then it is enabled again due to these 2 lines in QWizardPrivate (taken from qwizard.cpp)
bool complete = page && page->isComplete();
btn.next->setEnabled(canContinue && complete);
I am quite baffled as to why isComplete() is returning true here. I mean, I set my counter to be 2 at the beginning and I never decrease it. (And yes, I do emit a completeChanged() whenever I set the counter).
Any ideas?
QWizard automatically manages the state of Next button based on the QWizardPage::isComplete(), you should not implement that functionality yourself in initializePage(). The reason your isComplete() is not being called is that it doesn't actually overwrite QWizardPage::isComplete const from QWizardPage. Declare your function const and it will properly overwrite the original function.

Get target of cascades TouchEvent not working

I'm having problems trying to reach for the target of the Touch Event from BB10 cascades API. I have several containers, one below the other, and each one of them have the same Touch signal and slot assigned. Everything is being dynamically loaded from C++. So, in order to catch each touch event, I need to know which container triggered the event. I've read that I just need to use the TARGET property from the TouchEvent, but is not working and I dont know why. So I'm asking for help
Here's my code:
for (int i = 0; i < 10; i++) {
QmlDocument *qml = QmlDocument::create("asset:///customComponents/TableRow.qml").parent(this);
Container *passivesRow = qml->createRootObject<Container>();
passivesRow->setProperty("labelTextOne", "Hello_" + i);
bool res = QObject::connect(passivesRow,
SIGNAL(touch(bb::cascades::TouchEvent*)), this,
SLOT(handleAccountTouch(bb::cascades::TouchEvent*)));
Q_ASSERT(res);
Q_UNUSED(res);
myCurrentPageContainer->add(passivesScroll);
}
void PosicionConsolidada::handleAccountTouch(bb::cascades::TouchEvent* event) {
if (event->touchType() == TouchType::Up) {
qDebug() << "event catched";
VisualNode *p = event->target();
qDebug() << "object p: " << p->property("labelTextOne"); //Print nothing
}
}
Everything else is working just fine. My list of Containers is being created fine with their respective texts. When I click one of them, the event is being catched successfuly. I also tried to cast the VisualNode object to Container and it didn't work either. Please help!.
I would advice you an alternate approach which I used before. You can set objectName of control like this:
passiveRow->setObjectName("Hello_" + i");
QObject::connect(passiveRow, SIGNAL(touch(bb::cascades::TouchEvent*)), this,
SLOT(handleAccountTouch(bb::cascades::TouchEvent*)));
& in SLOT using it you can know which control emitted the signal:
if (event->touchType() == TouchType::Up) {
qDebug() << "object: " << QObject::sender()->objectName();
}
Here, sender() returns the control which emitted the signal.
In the API reference, there is no onTouch signal for the container.
On the contrary of other element like CustomControl
I do not know how your signal was successfully connected to your slot, but I guess that it was propagated from another component inside the container. So the target may be a Label or something else inside it.