I am using a QML TextArea as a text input. It seems like this TextArea automatically removes leading and trailing whitespaces. If I start the text with a couple of spaces, the cursor doesn't move. If I then type a normal character, the cursor jumps the amount of spaces typed before.
I managed to include trailing whitespaces by changing the TextOptions of the underlying QQuickTextDocument on the C++-side, but couldn't find a way to show leading whitespaces.
Is there a way to do that?
EDIT: It's really just a (very slightly styled) TextArea
T.TextArea {
id: control
padding: 6
opacity: enabled ? 1 : 0.8
font.pixelSize: TextStyle.font.size.regular
color: Color.gray_09
selectionColor: Color.cyan_066
selectedTextColor: color
wrapMode: TextEdit.Wrap
InputFieldPlaceholderText {
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: parent.topPadding
anchors.leftMargin: parent.leftPadding
textBox: control
}
TextEditFormatter {
id: textAreaFormatter
Component.onCompleted: onCompleted()
}
}
Which I call like this:
Flickable {
anchors.fill: parent
flickableDirection: Flickable.VerticalFlick
TextArea {
id: textArea
anchors.fill: parent
}
}
For Completion: This is what the TextEditFormatter does, but not using it doesn't change the behaviour...:
void TextEditFormatter::onCompleted()
{
auto document = parent()
->property("textDocument")
.value<QQuickTextDocument *>()
->textDocument();
auto textOptions = document->defaultTextOption();
textOptions.setFlags(QTextOption::IncludeTrailingSpaces);
document->setDefaultTextOption(textOptions);
}
Related
Repeater {
model: myModel.buttonParameters
delegate: Button
{
width: 47
height: 47
contentItem: Text {
id: content
text: modelData.name
font.family: MyStyle.fontFamily
fontSizeMode: Text.Fit
font.pixelSize: 30
font.styleName: "Bold"
topPadding: height / 6
color: modelData.visibility ? MyStyle.colorFromSeriesName(this.text) : MyStyle.dividerColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle
{
anchors.fill: parent
radius: 4
color: MyStyle.backgroundColor
border.color:MyStyle.dividerColor
border.width: 2
}
onClicked: {
cntModel.visibilityOfChartChanged(modelData.name, "plot");
}
}
}
On the C++ side.
myModel.buttonParameters is a QList<MyModel*> , where MyModel is a class inherited from QObject.
Q_PROPERTY(QVariant buttonParameters READ buttonParametersList NOTIFY buttonParametersChanged)
QVariant buttonParametersList()
{
return QVariant::fromValue(m_buttonParametersList );
}
The problem is that with a certain change in the model
(the signal buttonParametersChanged is sent), namely,
if the number of objects was equal to one and after the update there
is also one object, but with different characteristics, no redrawing
takes place, the old button remains. Moreover, it somehow depends on
the runtime. Also, if I remove the line with color, the model will update.
The issue is that buttonParametersChanged is a signal that triggers on the assignment of a new container (QList<>) to buttonParameters. It doesn't trigger on changes to the contents of an existing QList<> assigned to that property.
However, you can always manually trigger buttonParametersChanged when you know you've modified the contents of the QList<> which should give you the effect you want.
Note, a QML ListModel or C++ equivalent would likely be more appropriate for this use case. Many QML components are designed to specifically integrate with them and handle the cases of container contents changing.
I'm trying to make an equivalent to wpf stackpanel, I already had a logic and implemented it but something is wrong about width, I don't know how to create new components without getting into width loop binding, here is my stackpanel:
StackPanel.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import KiMa.Models 1.0
Item {
id:root
property var orientation : UOrientation.Horizontal
property int itemSpacing : 10
default property list<Item> pageData
Loader{
property var childs
anchors.fill: parent
id:loader
onChildsChanged: {
if(root.pageData != null){
for(var z = 0;z<root.pageData.length;++z){
root.pageData[z].parent = loader.childs
}
}
}
}
state: orientation == UOrientation.Horizontal ? "row": "col"
states: [
State {
name: "row"
PropertyChanges {
target: loader
sourceComponent : row
}
},
State{
name: "col"
PropertyChanges {
target: loader
sourceComponent : col
}
}
]
Component{
id:col
Column{
Component.onCompleted: {
childs = _col;
}
id:_col
width: parent.width
spacing: root.itemSpacing
}
}
Component{
id:row
Row{
Component.onCompleted: {
childs = _row
}
id:_row
width: parent.width
layoutDirection: Qt.RightToLeft
spacing: root.itemSpacing
}
}
}
and my orientation enum is like this:
#ifndef UORIENTATION_H
#define UORIENTATION_H
#include<QObject>
class UOrientation
{
Q_GADGET
public:
explicit UOrientation();
enum Orientation{
Horizontal,
Vertical
};
Q_ENUM(Orientation)
};
#endif // UORIENTATION_H
and usage example should be like this:
StackPanel{
x: 320
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 25
Button{
}
Button{
}
}
you need to add this into main.cpp:
qmlRegisterUncreatableType<UOrientation>("KiMa.Models",1,0,"UOrientation","its not creatable type!");
This code is working , if you have anything to suggest me to change or you think I made a mistake let me know, the only problem I can see here is width binding.
I already tried using childrenRect but it is not working:
width: childrenRect.width
height: childrenRect.height
Note : stackpanel allowing you to stack item after item on top of each other you can set orientation to horizontal or vertical so in qt its a column and row together which i made it already.
vertical one :
horizontal one :
You can do this easily with a Grid by setting the number of columns.
If you want a separate component, you can create your StackPanel.qml with the following:
import QtQuick 2.0
Grid {
property int orientation: Qt.Horizontal
columns: orientation === Qt.Horizontal ? -1 : 1
}
If you want a scrollable object, you could also use a ListView with an ObjectModel model. ListView has an orientation property.
I'm looking for a simple way to make widgets for a touch-screen that will allow users to set the time and IP address on the computer running the code and provide a simple (uppercase Latin-alphabetic) name.
This question is not about how to actually set the system time or IP address; I'm just looking for information about how to make the graphical widgets themselves.
What I want is for each editable property (time, address, and name) to be divided into "scrollable" fields, where the fields for "time" are hours, minutes, possibly seconds, and AM/PM/24-hr, and the fields for address/name are the individual characters. Each field would have an arrow above and below it, and touching on an arrow would scroll through the valid values for that field.
I think this is a pretty common UX pattern, especially in meatspace (e.g. on alarm clocks), but just in case it's not clear what I'm trying to describe, here's an example with a user editing the "name" property:
^^^
BN
vvv
User presses "down" below the "N":
^^^
BO
vvv
User presses "down" below the empty space:
^^^^
BOA
vvvv
...and again on the same down-arrow:
^^^^
BOB
vvvv
I'm writing this using C++14 with Qt 5. (If worst comes to worst, I'd be open to writing a separate app using a different language and/or framework, but I'm not asking for framework suggestions here; if you have one, let me know and I'll open a corresponding question on Software Recommendations SE.)
I don't see anything in the Qt 5 widget library like this; most of the input widgets are text fields. QSpinBox looks somewhat promising, but the arrows are probably too small for my touchscreen, and using a separate spinbox for each letter would probably be confusing and ugly.
I don't really know enough about Qt or GUI-programming in general to feel confident trying to write my own widgets from scratch, but this interface looks simple enough that I would expect a couple lines of QML would get me well on my way.
ListView as well as PathView can produce the desired result with slightly different behaviors and slightly different performances. Differently from ListView, PathView is circular, i.e. elements can be iterated continuously by using just one of the selection controls. It is also easier to fully customize the behavior of the path in PathView via the PathAttribute type. Anyhow path customization seems not to be a required feature, according to the question.
If you implement the solution via a ListView you should ensure that just one element is shown and that any model is processed.
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
ListView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
highlightRangeMode: ListView.StrictlyEnforceRange // <--- ensures that ListView shows current item
delegate: Text {
width: ListView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
The checks over the model ensure that any type of model can be passed to the component. Here is an example using three very different models:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 400
height: 300
ListModel {
id: mod
ListElement {texty: "it1"}
ListElement {texty: "it2"}
ListElement {texty: "it3"}
}
Row {
Repeater {
id: rep
model: 3
delegate: spinnnnnnnner
Component.onCompleted: {
rep.itemAt(0).model = mod // listmodel
rep.itemAt(0).textRole = "texty"
rep.itemAt(1).model = 10 // number model
//
rep.itemAt(2).model = ["foo", "bar", "baz"] // array model
}
}
}
}
PathView implementation is not so different from the ListView one. In this case it is sufficient to define a vertical path and specify that just one one element is visible at a time via pathItemCount. Finally, setting preferredHighlightBegin/preferredHighlightEnd ensures that the visible element is centered in the view. The revisited component is the following:
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
PathView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
pathItemCount: 1
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
path: Path {
startX: list.width / 2; startY: 0
PathLine { x: list.width / 2; y: list.height }
}
delegate: Text {
width: PathView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
I have a TreeView
TreeView {
id: dndView
rowDelegate: Item {
height: 30
}
itemDelegate: dndDelegate
model: myModel
TableViewColumn {
title: "Name"
resizable: true
}
}
and its delegate which does work
Rectangle {
id: dragRect
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: 'gray'
width: dndView.width - 20
height: 30
Image {
id: menuItemImage
anchors.verticalCenter:parent.verticalCenter
source:model.CommandIcon
}
Text {
anchors.left:menuItemImage.right
anchors.verticalCenter:parent.verticalCenter
text:model.CommandTitle
font.pixelSize: 14
}
Roles in C++ file:
QHash<int, QByteArray> MenuTreeModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TitleRole] = "CommandTitle";
roles[IconRole] = "CommandIcon";
return roles;
}
It displays text and icon correctly but nevertheless when I expand the items or close the application I have warnings:
qrc:/DraggableRectangle.qml:15: TypeError: Cannot read property 'CommandIcon' of null qrc:/DraggableRectangle.qml:20: TypeError: Cannot read property 'CommandTitle' of null*
What's wrong with it?
If the warnings only appear on specific events, it may mean the model is destroyed or not yet created when your QML view tries to use it.
E.g. if the model is destroyed before the view when you close the application, the view still tries to use a destroyed object for a short time (before it's destroyed too).
Try this :
text: model ? model.CommandTitle : ""
Its the anchor in the root of your delegate.
anchors.horizontalCenter: parent.horizontalCenter.
You can't anchor the left hand side of a TreeView's delegate. Remove that line and I bet it will work.
I have a QML textInput element like this:
TextBox.qml
FocusScope {
id: focusScope
property int fontSize: focusScope.height -30
property int textBoxWidth: parent.width * 0.8
property int textBoxHeight: 45
property string placeHolder: 'Type something...'
property bool isUserInTheMiddleOfEntringText: false
width: textBoxWidth
height: textBoxHeight
Rectangle {
width: parent.width
height: parent.height
border.color:'blue'
border.width: 3
radius: 0
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
Text {
id: typeSomething
anchors.fill: parent; anchors.rightMargin: 8
verticalAlignment: Text.AlignVCenter
text: placeHolder
color: 'red'
font.italic: true
font.pointSize: fontSize
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
TextInput {
id: textInput
anchors {
right: parent.right
rightMargin: 8
left: clear.right
leftMargin: 8
verticalCenter: parent.verticalCenter
}
focus: true
selectByMouse: true
font.pointSize: fontSize
}
Text {
id: clear
text: '\u2717'
color: 'yellow'
font.pointSize: 25
opacity: 0
visible: readOnlyTextBox ? false : true
anchors {
left: parent.left
leftMargin: 8
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
textInput.text = ''
focusScope.focus = true;
textInput.openSoftwareInputPanel()
}
}
}
states: State {
name: 'hasText'; when: textInput.text != ''
PropertyChanges {
target: typeSomething
opacity: 0
}
PropertyChanges {
target: clear
opacity: 0.5
}
}
transitions: [
Transition {
from: ''; to: 'hasText'
NumberAnimation {
exclude: typeSomething
properties: 'opacity'
}
},
Transition {
from: 'hasText'; to: ''
NumberAnimation {
properties: 'opacity'
}
}
]
}
I want to add autocomplete and suggestions like google search to this text box. Autocomple get data from database and database return a list of dictionaries by a pyside SLOT.(or c++ slot)
How I can do this work?
Take a look at this code: https://github.com/jturcotte/liquid/blob/master/qml/content/SuggestionBox.qml
I bet it will do the job.
Edit:
Code that linked above is somewhat complicated and requires C++ backend, so I simplified it and made pure Qml example application, that you can play with, edit a little and apply to your needs. Sources can be found here. Most important things there are:
This implementation of SuggestionBox that uses some sort of model as it's source for completing/suggesting something
Its signal itemSelected(item) will be emitted every time user clicks on item
Main component of application that binds its LineEdit component to SuggestionBox
Note that code is quite rough and written for a sake of example.
I was looking for something very similar: a QML autocomplete component built around QML TextField, rather than the lower-level, more flexible but also more work intensive TextInput as in the question.
Since I could not find that, I implemented it. If anyone wants to use it: it's licensed under MIT and available as part of an application I am developing. You find the component in src/qml/AutoComplete.qml, and the application may serve as usage example. Features:
highlighting of autocompleted characters in bold, as in Google Search
Key bindings (navigating with arrow keys, Return / Enter, Esc to close completion box, Esc Esc to unfocus)
uses a simple QStringList as model for now, with the application showing how to update the model with live SQL database queries when the next key is pressed
heavily documented code, so it should be easy enough to adapt
Let me know if this is useful, I might then package it as a Qt QPM package or even try to make it mature enough to be added to the QML UI library KDE Kirigami.