How to ignore key press events that don't output characters - qt

I'm developing a virtual musical keyboard that allows you to press keys on your keyboard and have it play notes. So in my MainWindow class I have reimplemented keyPressEvent. I would like to ignore events generated by modifiers (Control, Alt, Shift, etc.), as well as events generated by other non-character keys such as Tab, Backspace, and Enter. Something like this would be ideal:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if (!event->key().isCharacter()))
{
event->ignore();
return;
}
// handle the event
}
Is there a way to do something like that (short of testing every possible non-character key individually)? If not, is there at least a way to easily ignore the event if it is a modifier?

Looks like you want QKeyEvent::text().

The accepted answer is unfortunately incomplete. If you press Ctrl+C, then QKeyEvent::text() will return "\x03" (^C "End of Text").
That is not an empty string.
I decided to look inside the Qt source code, since they need to handle this problem for QLineEdit as well:
In QLineEdit::keyPressEvent:
d->control->processKeyEvent(event);
src/widgets/widgets/qlineedit.cpp:1742
In QWidgetLineControl::processKeyEvent:
if (unknown
&& !isReadOnly()
&& isAcceptableInput(event)) {
insert(event->text());
src/widgets/widgets/qwidgetlinecontrol.cpp:1912
In QInputControl::isAcceptableInput:
bool QInputControl::isAcceptableInput(const QKeyEvent *event) const
{
const QString text = event->text();
if (text.isEmpty())
return false;
const QChar c = text.at(0);
// Formatting characters such as ZWNJ, ZWJ, RLM, etc. This needs to go before the
// next test, since CTRL+SHIFT is sometimes used to input it on Windows.
if (c.category() == QChar::Other_Format)
return true;
// QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards
if (event->modifiers() == Qt::ControlModifier
|| event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
return false;
}
if (c.isPrint())
return true;
if (c.category() == QChar::Other_PrivateUse)
return true;
if (c.isHighSurrogate() && text.size() > 1 && text.at(1).isLowSurrogate())
return true;
if (m_type == TextEdit && c == u'\t')
return true;
return false;
}
src/gui/text/qinputcontrol.cpp:21
This is exactly what you need but you may want to change the check for \t and ignore that as well.

Related

How to store button value by pushing only once

I am trying to make a program that stores my button digital input so that I don't have to keep holding the button for it to work.
The algorithm I am trying to develop is when the button is pressed, it it executes the servoMomvement() function then increments count by one. If count is even then program runs, but then if the button is pressed again it will not be even and would stop working.
void loop() {
while(true){
int count = 0;
bool isEven = count%2;
bool condition = digitalRead(4);
if(condition == true && isEven == false){
servoMovement();
count++;
}
}
}
It is not working as intended. I still have to hold to push button for it to not stop executing.
You can use timer to incremenet count by one.This timer function check periodically button. And when you press it will work as you want. But first of all you have to know timers ability and capacity.
The problem is that the loop method is executed in a loop (like one could guess by the name of the method...) and therefore it's checked in every loop whether the button is pressed.
Because in your if statement it says condition == true && ... this will only be true if the condition is true (the button is pressed).
If I understood your question correctly you want to have some kind of start-/stop-button. If so you could try like this:
//global variable run
bool run;
void setup() {
run = false;
}
void loop() {
while(true){
bool condition = digitalRead(4);
if (condition) {
run = !run;//switch the state of the run variable
delay(50);//some delay to debounce the button; see https://www.brainy-bits.com/arduino-switch-debounce/ for more information
}
if(run){
servoMovement();
}
}
}
I have a quite simple solution for that.
You can compare the actual buttonstate with the buttonstate the "round" before.
bool Button = false;
bool ButtonBefore = false;
bool help = false;
void loop()
{
Button = digitalRead(ButtonPin);
if(Button > ButtonBefore) help = !help;
if(help) { do stuff; }
ButtonBefore = Button;
}
When you press the button, "Button" becomes true while "ButtonBefore" is still false. So "Button" is bigger than "ButtonBefore" so "help" changes to true. In the next cycle "ButtonBefore" is even to "Button" so "help" won't change its state. When the button is released, "ButtonBefore" is bigger than "Button" so it "help" won't change too. So the state from "help" is changed when the button is pressed.
I hope I could help you with this.

Qt text editor project: auto-indenting when Enter is pressed after an opening curly brace

I'm working on a text editor project in Qt, and I've added the following method override to a class that's of type QPlainTextEdit:
/* Custom handler for events. Used to handle the case of Enter being pressed after an opening brace.
*/
bool Editor::eventFilter(QObject* obj, QEvent* event)
{
bool isKeyPress = event->type() == QEvent::KeyPress;
if(isKeyPress)
{
QKeyEvent *key = static_cast<QKeyEvent*>(event);
if(key->key() == Qt::Key_Enter || key->key() == Qt::Key_Return)
{
QString documentContents = document()->toPlainText();
if(documentContents.length() >= 1)
{
int indexToLeftOfCursor = textCursor().position() - 1;
if(indexToLeftOfCursor >= 0 && indexToLeftOfCursor < documentContents.length())
{
bool hitEnterAfterOpeningBrace = documentContents.at(indexToLeftOfCursor) == '{';
if(hitEnterAfterOpeningBrace)
{
// TODO determine indentation level of the opening brace
insertPlainText("\n\t\n}");
QTextCursor cursor = textCursor();
cursor.setPosition(cursor.position() - 3);
setTextCursor(cursor);
}
}
}
}
else
{
return QObject::eventFilter(obj, event);
}
}
else
{
return QObject::eventFilter(obj, event);
}
return false;
}
Without the code for setting the text cursor's position, the result looks like this:
The cursor ends up on line 4, and there's a tab on line 2. My intent is to move the cursor so it sits to the right of the tab, so I tried to do that with the code I've written. But that gives me this:
Here, the indent is still on line 2, but now there's an extra line between the tab and the closing brace, which is a little odd.
Even more strange is that this happens regardless of what new position I enter. I tried doing cursor.position() - 2 and cursor.position() - 1 out of curiosity, for example, but I still got the same result.
What am I misunderstanding here about inserting the text and moving the cursor?

Xamarin.Forms UI Test - Tap Button multiple (5) times

I'm working on writing an UI-Test for my Xamarin.Forms Application.
Therefore I need to tap a button 5-times. This invokes a dialog and I need the result of the user's input to this dialog.In code I realised this by implementing an GestureRecognizer:
private bool HandleMultipleTouch()
{
if (iLastTap == null || (DateTime.Now - iLastTap.Value).Milliseconds < iToleranceInMs)
{
if (NumberOfTaps == 4)
{
NumberOfTaps = 0;
iLastTap = null;
return true;
}
else
{
NumberOfTaps++;
iLastTap = DateTime.Now;
return false;
}
}
else
{
NumberOfTaps = 0;
iLastTap = null;
return false;
}
}
Do you know any method how to use Xamarin.UITest to get the button taped 5 times in a short time?
I tried used double tap twice and one single tap, but this is not working because of the time needed to execute the taps.
I had a similar issue, where I had to tap a morse code using Xamarin.UITest and concluded that it's impossible to ensure consistent timing between taps. My solution was therefore to abandon the morse code and only check in the app whether the button was hit 5 times.

Delete JavaFX table row with delete key

Is there a way to delete selected table row using keyboard delete key?
Is there any example with this implementation?
Sure you can. You only have to register an EventHandler and listen to the specific KeyCode. Following example is for TreeTableView but should be applyable for all TableViews.
treeTableView.setOnKeyPressed( new EventHandler<KeyEvent>()
{
#Override
public void handle( final KeyEvent keyEvent )
{
final TreeItem<YourObject> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
if ( selectedItem != null )
{
if ( keyEvent.getCode().equals( KeyCode.DELETE ) )
{
//Delete or whatever you like:
presenter.onEntityDeleteAction( selectedItem );
}
//... other keyevents
}
}
} );
After trying a lot I managed to intercept and handle (with my application logic) the Delete key (Del or Canc, as you prefer to call it).
Thanks to some debugging I understand that the Delete key is identified with the Unicode code: \u007F.
So, the moment I type the key, I read the character and compare it with this code.
Here is a piece of my code that has nothing to do with table views but I used it for a TextField.
The important thing is the reasoning.
#FXML
public void myKeyListener(KeyEvent keyEvent) {
//Matches and manage TAB, Enter and Delete buttons
if ((keyEvent.getCharacter().equals("\t") ||
keyEvent.getCharacter().equals("\r") ||
keyEvent.getCharacter().equals("\u007F") //<-- **THIS** is the important one! *****
)) {
//My / your application logic
keyEvent.consume(); //The documentation says: "Marks this Event as consumed. This stops its further propagation."
return;
}
//Other logic...
//Entered only to have test outputs
System.out.println("getCode: " + keyEvent.getCode());
System.out.println("getCharacter: " + keyEvent.getCharacter());
System.out.println("getText: " + keyEvent.getText());
System.out.println("isMetaDown: " + keyEvent.isMetaDown());
}
Outputs:
getCode: UNDEFINED
getCharacter: ⍰
getText:
isMetaDown: false
I hope it can be useful to someone else. 🤞
P.S. I'm using Windows 10 with italian keyboard layout. In case it's relevant.

QlineEdit with some default text for which cursor should not be moved?

In QT, a created lineEdit shows a text using the setText() method.
But the cursor is movable for the default text. I want the cursor should not be movable for the default text.
My lineEdit type has been set as password. Hence the default text('Password') is also displayed as '********'. Whenever user types the type has to be changed as password and when there is no text or until the user have not typed any text, the lineEdit should display the plain text 'password'
Any idea to fix the above two issues?
In the constructor put
ui->lineEdit->setPlaceholderText("password");
ui->lineEdit->setReadOnly(1);
And in on_lineEdit_selectionChanged() SLOT, put
ui->lineEdit->setText("");
ui->lineEdit->setEchoMode(QLineEdit::Password);
ui->lineEdit->setReadOnly(0);
I noticed this question has tag pyqt so I'll put an actual answer related to that tag for those actually looking for a python way instead of c++.
self.searchEditText = QtGui.QLineEdit()
self.searchEditText.setPlaceholderText("Search for word")
I managed to do what you want by deriving a class from QLineEdit as per following..
Constructor..
QCustomLineEdit::QCustomLineEdit(QWidget *parent) :
QLineEdit(parent)
{
connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int)));
setEchoMode(QLineEdit::Password); // Echo mode in your case..
m_echoMode = echoMode(); // Member variable to store original echo mode..
m_placeHolderText = "Password"; // Member variable..
m_isPlaceHolderActive = true; // Member varible..
// Default case..
setPlaceholderText("");
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(__placeHolderText);
}
Override keyPressEvent..
void QCustomLineEdit::keyPressEvent(QKeyEvent *e)
{
if(m_isPlaceHolderActive)
{
if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
e->accept();
else
QLineEdit::keyPressEvent(e);
return;
}
QLineEdit::keyPressEvent(e);
}
Cursor position change event..
void QCustomLineEdit::onCursorPositionChanged(int /*oldPos*/, int newPos)
{
if(m_isPlaceHolderActive)
{
if(newPos != 0)
setCursorPosition(0);
}
}
Text change event..
void QCustomLineEdit::onTextChanged(const QString &text)
{
if(m_isPlaceHolderActive)
{
if(text.compare(m_placeHolderText) != 0)
{
m_isPlaceHolderActive = false;
// Remove the 'placeHolderText' from 'text' itself..
QString temp = text;
temp = temp.mid(0, text.lastIndexOf(m_placeHolderText));
setStyleSheet("QCustomLineEdit{color: black;}");
setEchoMode(m_echoMode);
setText(temp);
}
else
{
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
setStyleSheet("QCustomLineEdit{color: gray;}");
setCursorPosition(0);
}
}
else
{
if(text.isEmpty())
{
m_isPlaceHolderActive = true;
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
}
}
}
I have written it very hastily to just show you. Test it yourself and feel free to point any mistake(s) or optimization(s). Hope this helps.
For question 1, in Qt 5.0 and higher, setPlaceholderText does what you want. https://codereview.qt-project.org/#change,45326

Resources