QML TextInput ignoring inputMethodHints - qt

I'm creating a custom text input in QML. One of its configuration is that it's a field that should only accept digits I did it like this:
import QtQuick 2.6
Item {
property string vmFont: "Mono"
property string vmPlaceHolder: "Some text ..."
property bool vmNumbersOnly: false
// Qt Quick approach to make internal variables.
Item {
id: own
property string enteredText: ""
}
Rectangle {
id: lineEditRect
anchors.fill: parent
color: "#e4f1fd"
radius: 2
}
TextInput {
id: lineEdit
text: vmPlaceHolder
color: "#5499d5"
font.family: vmFont
font.pixelSize: 13
anchors.bottom: parent.bottom
//inputMethodHints: vmNumbersOnly ? Qt.ImhDigitsOnly : Qt.ImhNone
inputMethodHints: Qt.ImhDigitsOnly
verticalAlignment: TextInput.AlignVCenter
leftPadding: 10
width: lineEditRect.width
height: lineEditRect.height
onActiveFocusChanged: {
if (activeFocus){
if (own.enteredText === ""){
// Removing the placeholder
lineEdit.text = "";
}
}
}
onEditingFinished: {
own.enteredText = lineEdit.text;
if (lineEdit.text === ""){
lineEdit.text = vmPlaceHolder
}
}
}
}
However, even though that the inputMethodHits is set to Qt.ImhDigitsOnly, the text input still accepts all kinds of keypresses. What am I doing wrong?

I think that inputMethodHints is for virtual keyboards (e.g. mobile phone software keyboards, Qt Virtual Keyboard, etc.). For restricting input when a physical keyboard is in use (though it can also be used when a virtual keyboard is in use), you can use inputMask and validator. For example, the following code would allow only four digits from 0 to 9 to be entered:
TextInput {
inputMask: "9999"
}
Think of inputMethodHints as affecting what the virtual keyboard displays and how it behaves, and these properties as affecting what the TextInput itself allows as input.

it worked for me in any device:
TextInput {
validator: RegExpValidator{regExp: /[0-9]+/}
}

Related

How to access subcomponentes in QML

I want to create my custom combo box. So I went and desinged a simple item that is a rectancle with a mouse area and a text. My idea is to draw multiple of these according to the values in an string array. Here is my code so far for the item:
Item {
signal itemSelected(int id);
property int vmItemIndex: 0;
property alias itemBody: ibody;
Rectangle{
id: ibody;
property alias itemMouseArea: imouseArea;
property alias itemText: itext;
Text{
id: itext
anchors.centerIn: parent
}
MouseArea {
id: imouseArea
anchors.fill: parent
onClicked: itemSelected(vmItemIndex);
}
}
}
the acutual combo box
Item {
property int vmWidth: 300;
property int vmHeight: 50;
property int vmCurrentIndex: 0;
property var vmItemTexts: ["Item 1", "Item 2", "Item 3"];
property string vmBackColor: "#ff0000";
VMComboBoxItem {
id: main;
itemBody.itemText.text: vmItemTexts[vmCurrentIndex];
itemBody.width: vmWidth
itemBody.height: vmHeight
itemBody.color: vmBackColor
}
}
Hoewever the engine load fails telling me it cannot access itemText. So what am I doing wrong?
I think the problem is that in your VMComboBoxItem component, you expose the inner Rectangle as a property. There's some hint about this in the Qt documentation.
What you can do instead is to expose selected properties directly in your "root" item in VMComboBoxItem:
import QtQuick 2.0
Item {
signal itemSelected(int id);
property int vmItemIndex: 0;
property alias itemBody: ibody;
// Expose the "text" property directly:
property alias text: itext.text
Rectangle{
id: ibody;
property alias itemMouseArea: imouseArea;
property alias itemText: itext;
Text{
id: itext
anchors.centerIn: parent
}
MouseArea {
id: imouseArea
anchors.fill: parent
onClicked: itemSelected(vmItemIndex);
}
}
}
And then set this property in QML code using your component:
import QtQuick 2.0
Item {
property int vmWidth: 300;
property int vmHeight: 50;
property int vmCurrentIndex: 0;
property var vmItemTexts: ["Item 1", "Item 2", "Item 3"];
property string vmBackColor: "#ff0000";
VMComboBoxItem {
id: main;
itemBody.width: vmWidth
itemBody.height: vmHeight
itemBody.color: vmBackColor
// Set Text property directly:
text: vmItemTexts[vmCurrentIndex];
}
}
It might generally be a good idea to expose only selected properties in your components, as this narrows the interface your component exposes (which in turn makes it much easier should you ever need to refactor your code).

read string from Qt application by reverse engineering

I want to programmatically read a string generated in runtime by a basic Qt GUI application.
The string appears on the screen but I don't have the source and I want to pass this string to another script.
Here's the relevant .qml file:
import QtQuick 1.0
Rectangle {
id: tagCloud
SystemPalette { id: palette } //we get the system default colors from this
//public API
property variant model
property color baseColor: palette.base
property color textColor: palette.text
property int textFontSize: 16
color: baseColor
Flow {
id: flow
width: parent.width
spacing: 15
anchors.margins: 4
anchors.verticalCenter: parent.verticalCenter
//property int maxHeight:0
Repeater {
id: repeater
model: tagCloud.model
Text {
id: textBlock
text: category
font.pointSize: tagCloud.textFontSize;
}
}
}
}
Is there an easy way to get the "category" string as it's being generated?
Edit: This is the link to the application,
http://cybertron.cg.tu-berlin.de/eitz/projects/classifysketch/sketchpad_win.zip

QML Access object property by property name string

I want to create a QML binding in a repeated component. I want to bind the value of one of the elements to a property from a known object. My problem is that the name of said property that I want to bind to will be provided as a string in the component. How can I resolve the property name to an actual property that can be used as the value in a binding?
PS. If possible I guess I could pass the property directly to the repeater but then I would like to be able to convert the property to a string because I need both and don't want to pass both.
EDIT:
Here's what I want:
ListModel {
id: settingsModel
ListElement { title: "Bed Width"; setting: "bedWidth"; }
ListElement { title: "Bed Length"; setting: "bedLength"; }
}
Component {
id: settingsDelegate
Item {
width: parent.width
height: childrenRect.height
Label {
id: setLabel
text: title + ":"
width: parent.width
}
TextBox {
id: setTBox
anchors.top: setLabel.bottom
anchors.topMargin: 5
width: parent.width
Binding on text {
when: !setTBox.isActive
value: settings.setting
}
Binding {
target: settings
property: setting
value: setTBox.text
}
}
}
}
Column {
id: settingsColumn
spacing: 10
anchors.left: parent.left
anchors.right: parent.right
anchors.top: txtSave.bottom
anchors.topMargin: 15
Repeater {
model: settingsModel
delegate: settingsDelegate
}
}
My problem is that the name of said property that I want to bind to
will be provided as a string in the component. How can I resolve the
property name to an actual property that can be used as the value in a
binding?
If you look at the documentation for Binding you will discover that the property property expects a string - property : string
So you don't have anything to resolve, that happens internally.
my problem is the "value: settings.setting" line
You could try something like settings[setting]

Unable to get highlighting working on TextEdit

TL;DR: TextEdit paints highlighted text only when I click on it. Nothing helps
I have a ListView with a QAbstractListModel model with string properties.
Those string properties are being spellchecked and QSyntaxHighlighter is used to show spell errors. I create QSyntaxHighlighter descendant in Component.onCompleted of TextEdit. I double-checked highlighting get's executed with correct spell errors and setFormat() of Highlighter is executed with correct positions. The problem is that it draws text in red (invalidates) only when I click on the TextEdit itself.
TextEdit lives in a Flickable (to track cursor) and Flickable lives in a Rectangle (to have nice background and border). Binding to some signals and calling update() of TextEdit does not help.
After spellcheck finishes, I emit rehighlight() signal of created SyntaxHighlighter.
Rectangle {
id: descriptionRect
height: 30
border.width: descriptionTextInput.activeFocus ? 1 : 0
clip: true
Flickable {
id: descriptionFlick
contentWidth: descriptionTextInput.paintedWidth
contentHeight: descriptionTextInput.paintedHeight
anchors.fill: parent
interactive: false
flickableDirection: Flickable.HorizontalFlick
height: 30
clip: true
focus: false
function ensureVisible(r) {
if (contentX >= r.x)
contentX = r.x;
else if (contentX+width <= r.x+r.width)
contentX = r.x+r.width-width;
}
TextEdit {
id: descriptionTextInput
width: descriptionFlick.width
height: descriptionFlick.height
text: description
onTextChanged: model.editdescription = text
Component.onCompleted: {
globalModel.initDescriptionHighlighting(index, descriptionTextInput.textDocument)
}
onCursorRectangleChanged: descriptionFlick.ensureVisible(cursorRectangle)
}
}
}
Here is a small sample of project with demonstration of how it does not work until you click on a text https://bitbucket.org/ribtoks/qt-highlighting-issue
Any ideas how I can solve this?
Just encountered this issue on 5.11.2 and found the following fix which allows updating of individual blocks without having to highlight/deselect the whole text area
rehighlightBlock(newBlock);
Q_EMIT document()->documentLayout()->updateBlock(newBlock);
The issue was probably caused by QTBUG-44765, fixed in Qt 5.5.
Given the low level of the bug, I don't think it is practically to work around it.
You can work around that by appending an empty string to the TextEdit when you're done with the syntax highlighting
TextEdit {
id: captionTextEdit
width: wrapperFlick.width
height: wrapperFlick.height
text: display
readOnly: true
Component.onCompleted: {
itemsModel.initHighlighter(index, captionTextEdit.textDocument)
}
Connections {
target: itemsModel
onUpdateTextEdit: {
console.log("Update element at index: " + indexToUpdate)
if (indexToUpdate == index)
{
console.log("Update me!")
captionTextEdit.append("")
}
}
}
onCursorRectangleChanged: wrapperFlick.ensureVisible(cursorRectangle)
}
where updateTextEdit(indexToUpdate) is a new signal your itemsModel has to emit.
itemsmodel.h
signals:
void updateTextEdit(int indexToUpdate);
itemsmodel.cpp
void ItemsModel::initHighlighter(int index, QQuickTextDocument *document) {
// Signal mapper could be avoided if lamda slot are available (Qt5 and C++11)
QSignalMapper* signalMapper = new QSignalMapper(this);
if (0 <= index && index < m_ItemsList.length()) {
SingleItem *item = m_ItemsList.at(index);
SpellCheckHighlighter *highlighter = new SpellCheckHighlighter(document->textDocument(), item);
QObject::connect(item, SIGNAL(spellCheckResultsReady()),
highlighter, SLOT(rehighlight()));
// TODO: Don't connect this slot for Qt 5.5+ to avoid performance overhead
QObject::connect(item, SIGNAL(spellCheckResultsReady()),
signalMapper, SLOT(map()));
signalMapper->setMapping(item, index);
}
connect(signalMapper, SIGNAL(mapped(int)),
this, SIGNAL(updateTextEdit(int)));
}
Full code is available here: https://bitbucket.org/swarta/rehighlighdemo/branch/workaround#diff

ListView in subwindow triggers immediate close, or whilst scrolling

I have rather strange scenario whereby if I launch a subwindow that contains a ListView with a moderately complex delegate and enough items to comfortably exceed the visible area, the entire subwindow will immediately close on launch.
Reducing the complexity of the delegate will allow the window to open, but then rapidly scrolling the ListView will forcibly close it.
This SSCCE triggers the effect on my laptop, but on a more powerful machine it may only do it whilst scrolling (or perhaps the delegate may need to be more complex):
import QtQuick 2.3
import QtQuick.Window 2.0
Window {
width: 300
height: 200
Component.onCompleted: {
win.createObject( null );
}
Component {
id: win
Window {
width: 600
height: 400
visible: true
ListView {
id: view
anchors.fill: parent
model: 100
boundsBehavior: Flickable.StopAtBounds
clip: true
delegate: Rectangle {
width: view.width
height: 24
property int debugLevel: index % 3
property int timestamp: index * 1000
property int message: index
color: "darkgray"
Row {
anchors.fill: parent
Repeater {
id: delegateRepeater
property list< QtObject > roleModel: [
QtObject {
property string label: timestamp
property int itemWidth: 100
},
QtObject {
property string label: debugLevel
property int itemWidth: 100
},
QtObject {
property string label: message
property int itemWidth: view.width - 100 - 100
}
]
model: roleModel
Item {
width: itemWidth
anchors {
top: parent.top
bottom: parent.bottom
}
Text {
anchors {
fill: parent
leftMargin: 4
}
verticalAlignment: Text.AlignVCenter
text: label
elide: Text.ElideRight
}
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
}
width: 1
visible: index != ( delegateRepeater.count - 1 )
color: "white";
}
}
}
}
}
}
}
}
}
There doesn't seem to be any particular part of the code that is causing the problem, removing any of the objects in the delegate reduces the probability of the subwindow closing.
I've added the debugging tag because my main problem is that this effect produces no debug output. If I add a breakpoint into the subwindow's destruction handler (Component.onDestruction) then there is a single stack entry pointing at the model: roleModel statement - but removing the entire Repeater and replacing with a copy-and-pasted equivalent yields the same results minus the stack entry.
So I would be grateful is anyone knows of a way of getting more information from this pure QML example.
As noted by #BaCaRoZzo the changing of behaviour by modifying the delegate code seems to be an unrelated side-issue.
The real cause is because it turns out you cannot create new root contexts (i.e. top-level windows) from QML. This was hinted at being resolved when Qt Quick Components were released, but the blog post boasting of Window doesn't explicitly state this. Creating a new Window and passing null for the parent technically works but the result seems to be very unstable.
Thankfully in my circumstance I'm creating a QML/C++ application so I've solved the issue by creating new root contexts from Q_INVOKABLE methods on the C++ side. But if you're developing a pure QML application, it seems that you are out of luck.

Resources