Secure text entry for TextFiled - qt

I am using textfiled for password entry with echomode password. but i want it should display characters while entering and after some time(one sec) or entering next char it should goto asterisks.
code:
TextField {
id: inputtext
height: parent.height
width:parent.width
font.family: "Helvetica"
horizontalAlignment: TextInput.Center
font.pointSize: Math.round(28 * (main.height/1080))
placeholderText:"Password"
echoMode:TextInput.Password
}
I tried it using text item which displays current enter key after some time i will make it invisible and moving text item based on cursor position.
code:
TextField {
id: inputtext
anchors.centerIn: parent
width: 200
height: 20
echoMode:TextInput.Password
Text{
id: showpwd
text: "h"
font.pointSize: 10
verticalAlignment: Text.AlignVCenter
}
onTextChanged: {
showpwd.x = cursorPosition*7
showpwd.text = text.charAt(cursorPosition-1);
}
}
issue: still i can view asterisk behind the text item. could some one help me out of this.

I think you should use TextInput instead of TextField because it's a basic element in qml. Let's take the following example for password entry, I'm using passwordMaskDelay property of TextInput which was introduced in Qt 5.4.
Rectangle {
id: container
width: 200
height: 200
color: "yellow"
TextInput {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
id: text2
echoMode: TextInput.Normal
font.pixelSize: 20; font.bold: true
text: "Enter text here..."
width: container.width - 40 ;
focus: true
passwordMaskDelay: 1000
}
MouseArea {
anchors.fill: parent
onClicked: {
text2.text = "";
text2.echoMode = TextInput.Password;
}
}
}
I think you wanted a transparent background, I've kept that in mind. You can experiment with it.

Very interesting question. But I think it's impossible to override visible text of TextField in this way. As for solution I can offer only this lame workaround:
TextField {
id: inputtext
anchors.centerIn: parent
echoMode:TextInput.Password
horizontalAlignment: TextInput.Center
onEditingFinished: mask.visible = false
Rectangle {
id: mask
anchors.fill: parent
color: "white"
border.width: 1
border.color: "#999"
Text {
anchors.centerIn: parent
font: inputtext.font
text: new Array(inputtext.text.length).join( "*" ) + inputtext.text.charAt(inputtext.text.length - 1)
}
}
}

I just have done very little testing. But, it should give you the idea.
TextField {
id: pwdField
property string password: ""
// could be ugly solution, but does the job
property string replaceString: "*******************************************************************"
property bool ignoreNext: false
placeholderText: "some text"
onTextChanged: {
if (ignoreNext) return;
var txtLength = text.length;
if (txtLength === 0) {
password = text;
updateTimer.stop();
} else {
if (txtLength < password.length) {
password = password.substring(0, txtLength);
console.log(text, "pwd: ", password)
return;
} else if (txtLength > password.length) {
password += text.charAt(txtLength - 1)
}
if (updateTimer.running) {
obscureText();
ignoreNext = true
text = text.substring(0, txtLength - 1) + password.charAt(password.length - 1);
ignoreNext = false
}
updateTimer.restart();
}
console.log(text, "pwd: ", password)
}
onEditingFinished: {
updateTimer.stop();
obscureText();
}
function obscureText() {
ignoreNext = true;
text = replaceString.substring(0, text.length);
ignoreNext = false;
}
Timer {
id: updateTimer
running: false
repeat: false
interval: 1000
onTriggered: pwdField.obscureText();
}
}
issues you have to workaround:
you can't really use text property anymore as it will give you all *****, use password and onPasswordChanged signal
this solution won't work if user moves the cursor around using navigation keys

Related

Qt 5.11.3 - QML - treeView - resize row height depending of itemDelegate property

I'm trying to adapt the row height of a TreeView to automatically fit the content in its itemDelegate, but I have no clue how to do so.
So far, I tried to create a property "lines" in my itemDelegate object, but everytime I try to access it QML says my treeDeleg item is undefined.
Is there a way to get the result I want ?
EDIT : following what JarMan said, it's not possible to reference a delegateComponent by ID. So instead, is there's a way to automatically adapt the row height to its content ? Something along the lines of "height: auto" in CSS. This is really important because long values make my interface hard to read.
If all else fails, would there be a better component to create a tree styled view able to contain long, editable values ?
main.qml :
TreeView
{
id:treeView
anchors.top: rowInfo.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
itemDelegate: TreeDelegate
{
id: treeDeleg
}
style: TreeViewStyle
{
id: styleTree
rowDelegate:Rectangle
{
id : rowDeleg
height: styleData.selected ? 75 : 25 * treeDeleg.lines
color:
{
var baseColor = styleData.alternate ? "white" : "#d9edf7"
return styleData.selected ? "yellow" : baseColor
}
}
}
Component.onCompleted:
{
treeView.model = Qt.binding(function()
{
if (typeof theModel !== "undefined")
{
return theModel;
}
else
{
return null;
}
});
}
TableViewColumn
{
id:column1
role: "Name"
title: "Name"
width: 450
}
TableViewColumn
{
id:column3
role: "Value"
title: "Value"
width: 400
}
TableViewColumn
{
id:column4
role: "Desc"
title: "Description"
width: 750
}
}
TreeDelegate.qml
Item
{
id: item
width : parent.width
height : 25
property var lines: null
TextEdit
{
id: text1
font.pixelSize: 14
readOnly: true
focus: false
width : parent.width
height: 25 * lineCount
anchors.left: parent.left
wrapMode: TextEdit.Wrap
text: (styleData.value !== null) ? (styleData.value.text + styleData.value.id) : "";
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
Component.onCompleted:
{
lines = text1.lineCount == 0 ? 1 : text1.lineCount;
console.log("Lines : " + lines);
}
}
}
```

Qt5/QML - Pagination in Text/TextArea

Let's say I have a QML Text or TextArea that contains a very long HTML page. I want to make it easier to read by splitting it into pages.
More specifically, every time I press the down key, I want it to scroll down until none of the current text on the screen is still there.
I already know how to make the entire TextArea scrollable; that's not what I'm looking for. What I'm looking for is more like the kind of behavior you'd expect in an ebook reader.
Is there any way to do something like that, preferably in pure QML (though C++ is also fine).
You can measure the TextArea height after loading, divide it to the container height and so get the count of pages. Then you just move the TextArea relative to its container according to the current page.
The simple illustration of my idea:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
id: main
visible: true
width: 640
height: 800
property int currentPage: 1
property int pageCount: 1
ColumnLayout
{
anchors.fill: parent
anchors.margins: 5
RowLayout {
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignHCenter
Button {
text: "<"
onClicked: {
if(main.currentPage > 1)
main.currentPage --;
}
}
Text {
text: main.currentPage + " / " + main.pageCount
}
Button {
text: ">"
onClicked: {
if(main.currentPage < main.pageCount)
main.currentPage ++;
}
}
}
Rectangle {
id: container
clip: true
Layout.fillHeight: true
Layout.fillWidth: true
TextArea {
id: msg
text: "Loading ..."
width: container.width
height: container.height
y: -(main.currentPage - 1) * container.height
textFormat: TextEdit.RichText
wrapMode: TextEdit.Wrap
Component.onCompleted: {
msg.makeRequest();
}
onContentHeightChanged: {
msg.height = msg.contentHeight;
if(msg.contentHeight >= container.height && container.height > 0)
{
main.pageCount = msg.contentHeight / container.height;
loader.running = false;
}
}
function makeRequest()
{
var doc = new XMLHttpRequest();
msg.text = "";
doc.onreadystatechange = function() {
if (doc.readyState === XMLHttpRequest.DONE) {
msg.text = doc.responseText;
}
}
doc.open("GET", "http://www.gutenberg.org/files/730/730-h/730-h.htm");
doc.send();
}
}
}
}
BusyIndicator {
id: loader
running: true
anchors.centerIn: parent
}
}
Of course you have to process margins, the last line on a page, recalculate the values on resizing etc.

Make QT/QML TextArea scroll to bottom

I'm having this hard time with QT/QML 5.11 over such a simple thing I almost think there's a bug in the library at this point.
I have the following code:
Flickable {
id: txflick
anchors.top: title_label.bottom
anchors.bottom: crect.bottom
anchors.right: crect.right
anchors.left: busy_ind.right
flickableDirection: Flickable.VerticalFlick
onContentYChanged: console.log("contentY_changed", this.contentY)
//contentY: txarea.contentHeight - txarea.height
interactive: false // Has no effect, contentY keeps changing to zero
TextArea.flickable: TextArea {
id: txarea
topPadding: 8
bottomPadding: 10
leftPadding: 10
rightPadding: 10
readOnly: true
text: menu_view.pwrcon.text
onTextChanged: {
console.log("text changed")
txflick.contentY = txarea.contentHeight - txflick.height
console.log("chg", txarea.contentHeight - txflick.height)
console.log(text)
}
onContentHeightChanged: {
console.log("ctheight = ___", contentHeight, height, txflick.height, txflick.contentHeight)
}
font.family: "DejaVu Sans Mono,Ubuntu Sans Mono,Noto Sans Mono"
font.bold: false
font.pixelSize:12
color: "black"
//verticalAlignment: TextInput.AlignTop
background: Rectangle { color: "lightgrey"; radius: 2;
border.width: 1; border.color: "darkgrey" }
}
}
Basically the TextArea's text is linked to "menu_view.pwrcon.text", which is changed in the Python code (it's a property). When the text changes, I want it to set the flickable to the bottom of the text, so that we see the most recently added lines.
So I do
txflick.contentY = txarea.contentHeight - txflick.height
When the onTextChanged() event is fired. No issues there, I checked the numbers and it's fine (scrolling manually to the number shown with console.log() shows the contentY calculation is correct).
But it seems the component (the flickable), just after I change contentY, changes it alone back to 0 (this behavior happens only after the text height becomes bigger than the fixed height of the flickable). It's so genuinely idiotic I question whether it's a bug or intended.
In other words, right after my calculation, contentY goes back magically to zero without my intervention, which of course breaks the whole thing.
Is there anything to fix this issue?
You can achieve it with Flickable or ScrollView.
changing cursor position to in TextArea will focus on that line automatically.
create a function in the text area and change focus each time text changes. You have to call it manually
cursorPosition = length-1
or
you can directly set property
cursorPosition : length-1
in TextArea block on each text update.
ScrollView {
id: scrollView
height: parent.height
width: parent.width
clip: true
anchors.fill: parent
TextArea {
id: statusTextArea
Layout.preferredWidth:parent.width
Layout.fillHeight: true
readOnly: true
textFormat: TextEdit.RichText
text: "Long Text \n"
width: parent.width
height: parent.height
anchors.fill: parent
function append(strAdd)
{
statusTextArea.text = statusTextArea.text + strAdd
statusTextArea.cursorPosition = statusTextArea.length-1
}
}
}
Timer {
running: true
interval: 1000
repeat: true
property int iteration: 0
onTriggered:{
statusTextArea.append("Line %1\n".arg(iteration++))
statusTextArea.append("Line %1\n".arg(iteration++))
}
}
This is my codes, it work pretty well for me.
TextArea {
id: textArea
width: parent.width
height: parent.height
readOnly: true
selectByMouse: true
wrapMode: Text.WordWrap
function append(newText) {
if (textArea.flickableItem.contentHeight - textArea.height <= 0) {
textArea.text = textArea.text + newText
} else {
if (textArea.flickableItem.contentY >= textArea.flickableItem.contentHeight - textArea.height) {
textArea.text = textArea.text + newText
textArea.flickableItem.contentY = textArea.flickableItem.contentHeight - textArea.height
} else {
textArea.text = textArea.text + newText
}
}
}
}
Timer {
running: true
interval: 1000
repeat: true
property int iteration: 0
onTriggered:{
textArea.append("Line %1\n".arg(iteration++))
textArea.append("Line %1\n".arg(iteration++))
}
}

Dynamic validator for TextField / Change validator at runtime

I have small problem/requirement about validators, which i'm currently not able to implement.
I have a simple TextField (QtQuick.Control 2) which is decorated with different colors depending on a state. It should also use a different RegExpValidator (with another regular expression) depending on the current state.
Does anyone have an idea how i can switch/change/modify a RegExpValidator at runtime? (e.g. when a PushButton is pressed or onEditingFinished-Event is triggered)
My current qml code is:
import QtQuick 2.3
import QtQuick.Controls 2.2 as Quick
import QtQuick.Layouts 1.3
RowLayout {
id: layout
property color modeColor: "whitesmoke"
property color modeTextColor: "gray"
spacing: 0
Rectangle {
id: rect
Layout.fillWidth: true
Layout.minimumWidth: 100
Layout.preferredWidth: 100
Layout.maximumWidth: 100
Layout.preferredHeight: layout.implicitHeight
color: modeColor
border.width: 1
border.color: modeColor
Text {
id: recttext
anchors.centerIn: parent
text: "Enter key"
color: modeTextColor
}
}
Quick.TextField {
id: input
Layout.fillWidth: true
placeholderText: "Text"
background: Rectangle {
color: "whitesmoke"
border.width: 1
border.color: modeColor
}
validator: RegExpValidator { regExp: /.*:$/ }
onEditingFinished: {
recttext.text = input.text
if (layout.state == "keyinput") {
layout.state = "valinput"
// should change to another regExp validator
} else {
layout.state = "keyinput"
// should change to another regExp validator
}
input.clear()
}
Keys.onPressed: {
if (event.key == Qt.Key_Escape) {
layout.state = "keyinput"
recttext.text = "Enter key"
input.clear()
}
}
}
states: [
State {
name: "keyinput"
PropertyChanges { target: layout; modeColor: "whitesmoke"; modeTextColor: "gray" }
},
State {
name: "valinput"
PropertyChanges { target: layout; modeColor: "red"; modeTextColor: "white" }
}
]
state: "keyinput"
}
Best Regards, Chris
edit:
The endgoal is an inputline for entering key-value pairs (where i could use a specific RegExpValidator for a specific key.)
Here it should use RegExpValidator for entering a key e.g. "author:" + Pressing Enter (keyinput-mode)
#
After switching into the valueinput-mode, it should use another RegExpValidator:
btw. It's a desktop application :)
I hope this can help you!
property var valid1 : IntValidator { bottom:0; top: 2000}
property var valid2 : IntValidator { bottom:2000; top: 4000}
...
validator: if(condition) { valid1 }
else { valid2 }

QML: TableView dynamic change row height

I have a table of 4 columns, in one of which is text. When you change the width of the column, the width of the internal text also changes. In some cases, the width of the text becomes rather small and the text begins to increase its height (text wrap). How can I increase the height of the row in which this text is located?
This is a column with text
TableViewColumn {
id: fullNameColumn
property int minColWidth: 175
property int maxColWidth: 500
role: "fullName"
title: "ФИО"
width: 360
property string imageSource : ""
onWidthChanged: {
if (width < minColWidth)
width = minColWidth
}
delegate: Rectangle{
id: rowCellContentFullName
color: "transparent"
Text {
property int maxColWidth: 400
id: labelFullName
objectName: "labelFullName"
font.pixelSize: 13
wrapMode: Text.Wrap
anchors.leftMargin: 38
anchors.left: parent.left
horizontalAlignment: styleData.textAlignment
anchors.verticalCenter: parent.verticalCenter
visible: parent.visible
width: parent.width - this.anchors.leftMargin * 2
text: styleData.value !== undefined ? styleData.value : ""
color: "#474747"
renderType: Text.NativeRendering
}
}
This is the rowDelegate
property Component rowDelegate: Rectangle {
id: rowDel
objectName: "RowDelegate"
height: parent.parent.children[1].children[2].children[0].children[0].height < 50 ? 50 : parent.parent.children[1].children[2].children[0].children[0].height
property color selectedColor: styleData.hasActiveFocus ? primaryColor : secondaryColor
property bool selectionMaskVisible
property bool selected: false
}
In rowDelegate Im binding height with terrible expression, but it works. Works only for column 3 (where FullName). If i drag this column in another space my code doesnt work.
Can I change rows height in TableView QML without this terrible expressions? Mb You know some way to solve this problem?
Rostislav.
I had the same problem.
My solution:
TableView {
id: skillsGroupSkills
model: root.updated ? skillsProxy : null
property var rects: ({})
TableViewColumn {
title: "ID"
role: "id"
width: 30
}
TableViewColumn {
id: skillColumn
title: "Название"
role: "skill"
width: 200
}
TableViewColumn {
title: "Sort"
role: "sort_id"
width: 60
}
itemDelegate: Item {
Text {
id: text
color: styleData.textColor
elide: styleData.elideMode
text: styleData.value
width: parent.width
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
onContentHeightChanged: {
if (styleData.column === 1 && styleData.row !== -1) {
var id = skillsGroupsSkillsTableModel.get(skillsProxy.mapRowToSource(styleData.row))["id"]
var rect = skillsGroupSkills.rects[id];
if (rect) rect.height = contentHeight;
}
}
}
}
rowDelegate: Rectangle {
id: rect
Component.onCompleted: {
var id = skillsGroupsSkillsTableModel.get(skillsProxy.mapRowToSource(styleData.row))["id"]
skillsGroupSkills.rects[id] = rect;
}
}
}
In this example I'm dynamically changing second column height in each row.
Every rowDelegate rectangle is saving in the rects property.
My model has unique value in every row - id. I used it to ident rectangles because I have proxyModel. Probably you can use styleData.row directly.
P.S. Yes, I know that this question was in a year ago. May be my solution will be useful for somebody. :)

Resources