How to display different sizes for inactive items in Tumbler component - qt

I am trying to build an application and for the time settings i am trying to use Tumbler component for this item. I checked on qml documentation for Tumbler but i couldn't find any size settings for Tumbler. I can change the whole Tumbler font size but what i am looking for is changing the sizes for not current items. If i choose time as 12:24:AM i want to see 11,13,23and 25 on some different font sizes. Here is the example
import QtQuick
import QtQuick.Window
import QtQuick.Controls
Rectangle {
width: frame.implicitWidth + 10
height: frame.implicitHeight + 10
function formatText(count, modelData) {
var data = count === 12 ? modelData + 1 : modelData;
return data.toString().length < 2 ? "0" + data : data;
}
FontMetrics {
id: fontMetrics
}
Component {
id: delegateComponent
Label {
text: formatText(Tumbler.tumbler.count, modelData)
opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: fontMetrics.font.pixelSize * 1.25
}
}
Frame {
id: frame
padding: 0
anchors.centerIn: parent
Row {
id: row
Tumbler {
id: hoursTumbler
model: 12
delegate: delegateComponent
}
Tumbler {
id: minutesTumbler
model: 60
delegate: delegateComponent
}
Tumbler {
id: amPmTumbler
model: ["AM", "PM"]
delegate: delegateComponent
}
}
}
}
The line of "font.pixelSize: fontMetrics.font.pixelSize * 1.25" is changing the whole component's font size. How can i change font sizes for upper and lower values on Tumbler?

You can use the Tumbler.displacement property that represents how far away this item is from being the current item.
Tumbler {
anchors.centerIn: parent
model: 60
delegate: Text {
text: modelData
font.pixelSize: 16 + Math.abs(Tumbler.displacement) * 10
horizontalAlignment: Text.AlignHCenter
}
}

Try setting your font.pixelSize by checking Tumbler.displacement === 0 as follows:
font.pixelSize: Tumbler.displacement === 0
? fontMetrics.font.pixelSize * 1.25
: fontMetrics.font.pixelSize
After looking at #folibis answer, it inspired me to write this variation which causes the font to diminish in value the further it is away from the current item:
font.pixelSize: fontMetrics.font.pixelSize * 1.25 / ( 1 + Math.abs(Tumbler.displacement))

Related

How to have a numerical model start at 1 in a combobox from QML

In the combobox from qml we can give them a model with a numerical value.
The options of the combobox then start from 0 to the model value minus 1.
What i want is to show the values on the combobox plus 1.
But still, if i try to access, with qml javascript, the value that is selected in that combobox is the original value, what i mean is, if it's the first option it's the value 0. The numbers shall only start from 1 in the display part of combobox.
I'm going to give an example (with a model=32):
display of the combobox
the options:
what i want is them to start at one, like this:
The code used was the following:
import QtQuick 2.9
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
title: "Stack"
visible: true
height: 200
width: 400
Item {
id: page
anchors.fill: parent
width:parent.width
height: parent.height
Column{
width:parent.width
spacing:10
ComboBox {
id:comboBox
model: 32
objectName: "test"
implicitHeight: 30
displayText: currentText
// delegate:
// Button {
// id:buttonCombo
// width: parent.width
// text: index+1
// height:40
// contentItem: Text {
// text: buttonCombo.text
// font: comboBoxCustom.font
// leftPadding: 5
// horizontalAlignment: Text.AlignLeft
// verticalAlignment: Text.AlignVCenter
// elide: Text.ElideRight
// }
// background: Rectangle {
// color: buttonCombo.hovered ? (buttonCombo.pressed ? "#d8d8d8" : "#e8e8e8" ) : "#fff"
// }
// }
anchors.topMargin: 10
}
}
}
}
Maybe this could be done:
displayText: Number(currentText)+1
but i don't know if its the best solution...

Multi item swipedelegate

Edited due to insufficient intial posting.
Hi,
thanks for your help!
You're right, I guess it is better to include the whole file, in spite of the size:
import QtQuick 2.5
import QtQuick.LocalStorage 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 2.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import QtQuick.Controls.Material 2.1
import "./database.js" as Database
ApplicationWindow {
visible: true
width: 640
height: 480
id: appWindow
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
title: qsTr("Project Stats")
Material.theme: Material.Dark
ListModel {
id: projectModel
ListElement {
projectID: "123654"
manager: "Schneider"
sponsor: "3466"
}
}
Component {
id: projectDelegate
SwipeDelegate {
id: projectSwipeDelegate
width: parent.width
height: projectDelegateItem.implicitHeight
anchors.horizontalCenter: parent.horizontalCenter
spacing: 10
contentItem: Item {
id: projectDelegateItem
Text {
id: projectID_text
text: "Project ID: " + projectID
font.pointSize: 20
anchors.horizontalCenter: parent.horizontalCenter
font.weight: Font.Black
color: "white"
}
Text {
id: manager_text
text: 'Manager: ' + manager + " Sponsor: " + sponsor
anchors.top: projectID_text.bottom
anchors.horizontalCenter: parent.horizontalCenter
font.weight: Font.Thin
color: "lightgrey"
}
}
onClicked: {
console.log(index, projectModel.get(index).projectID)
if (swipe.complete)
projectModel.remove(index)
else {
//var component= Qt.createComponent("timepointsstackview.qml")
//var loadwin = component.createObject(appWindow)
//loadwin.selected_project = projectModel.get(index).projectID
// stackView.push(Qt.resolvedUrl("timepointsstackview.qml"), {properties: {selected_project: projectModel.get(index).projectID}})
stackView.push(component, {properties: {selected_project: projectModel.get(index).projectID}})
}
}
swipe.right: Label {
id: deleteLabel
text: qsTr("Delete")
color: "white"
verticalAlignment: Label.AlignVCenter
padding: 12
height: parent.height
anchors.right: parent.right
SwipeDelegate.onClicked: projectListView.model.remove(index)
background: Rectangle {
color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
}
}
}
}
Item {
Component.onCompleted: {
Database.getDatabase()
Database.getProjects()
}
}
StackView {
id: stackView
anchors.fill: parent
// Implements back key navigation
focus: true
Keys.onReleased: if (event.key === Qt.Key_Back && stackView.depth > 1) {
stackView.pop();
event.accepted = true;
}
initialItem: Item {
width: parent.width
height: parent.height
ListView {
id: projectListView
anchors.fill: parent
clip: true
model: projectModel
delegate: projectDelegate
}
}
}
onClosing: {
if (Qt.platform.os == "android") {
close.accepted = false;
// if (stack.depth > 1) stack.pop();
}
}
}
Meanwhile I already had removed the row/column stuff, which I put in to get it working somehow though I started without it.
I also experimented with implicitheight before intially posting, but sadly to no avail. The above is my current code, though putting in
height: projectDelegateItem.implicitHeight
in that spot (probabaly not the correct one or the wrong reference? Had to change it from your suggestion as I already took out the row) leads to rendering in one spot only.
Thanks for your time so far and also if you still have the patience to give me a clue where to turn the screws...
Ok, first of all:
Take warnings serious. If qml tells you, you should not try to use anchors within rows or columns, don't do it!
QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.
QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.
Also don't do it, if you can't see those warnings. It will mess up a lot.
A row automatically anchors all its children side by side to each other. A column does the same, just horizontraly. If you mess with it, everything breaks.
Frankly: I don't even understand why you use this strange Row/Column-Setup.
For your case it seems way better to just resort to anchoring. If you have reasons for that, why not take a grid?
Secondly: You need to specify a height for your delegate. Unfortunately it seems like, it does not calculate an implicit height.
The SwipeDelegate calculates its own implcitHeight based on the implicitHeight of its contentItem.
The problem is, that you don't assign the row (which has a proper implicitHeight) as the contentItem, but add it as a child instead.
Assigning it as contentItem would fix that for you.
Regarding your edit, and removal of the Row: The Item you use now does not calculate a implicitHeight based on its children. So you need to provide your calculation yourself.
This will set a proper height to your delegate, and your delegates won't overlap.
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
Window {
width: 1024
height: 800
visible: true
ListView {
width: 400
height: 800
model: ListModel {
ListElement { projectID: 0; manager: 'I'; sponsor: 'mom' }
ListElement { projectID: 1; manager: 'YOU'; sponsor: 'dad' }
ListElement { projectID: 1; manager: 'HE'; sponsor: 'auntie' }
}
delegate: SwipeDelegate {
id: projectSwipeDelegate
width: parent.width
// height: <--- provide a height, if the contentItem does not provide it.
contentItem: Row{ // <--- Add your content as contentItem.
id: rowProjectDelegate
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
Column {
id: column
// anchors.horizontalCenter: parent.horizontalCenter <--- Don't do that!
width: parent.width
Rectangle{ // If you don't want to have them in a column, they can't be siblings. If you want to, then you should.
height: 10
width: 250
color: "red"
Rectangle {
height: 10
width: 200
color: "blue"
}
}
Label {
id: projectID_text
text: "Project ID: " + projectID
font.pointSize: 20
font.weight: Font.Black
color: "white"
}
Label {
id: manager_text
text: 'Manager: ' + manager + " Sponsor: " + sponsor
// anchors.top: projectID_text.bottom <--- Don't do that!
font.weight: Font.Thin
color: "lightgrey"
}
}
}
}
}
}

Keep input field in view while using on-screen keyboard

I've a virtual keyboard which pops-up from the bottom of the screen and always stays on top. I'm going to use this in my application and have a small problem.
If the text input field which accepts input from this keyboard is in middle / bottom of the view (main window / screen), it gets hidden behind the keyboard i.e., can't see whats been entered until the keyboard is hidden.
Keyboard is running as platforminputcontext plugin which will know the field that is accepting the input.
void KeyboardPlatformInputContext::setFocusObject(QObject* object)
{
qDebug() << m_focusedObject << object;
m_focusedObject = object;
}
When the keys are pressed, they are passed as QEvents like this
void KeyboardPlatformInputContext::processNormalKeyClick(const QString& key)
{
qDebug() << m_focusedObject << key;
if (m_focusedObject) {
QInputMethodEvent inputEvent;
inputEvent.setCommitString(key);
QGuiApplication::sendEvent(m_focusedObject, &inputEvent);
}
}
Now, with the available information (m_focusedObject and QGuiApplication) can it be possible to do something to keep the input field in view. Always.
Kuba has the right idea; I'll just expand on it. You can use Flickable, for example, to manage the content of your application. For example, suppose your application was laid out like a form:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
id: root
width: 480
height: 800
visible: true
Column {
anchors.fill: parent
anchors.margins: 20
spacing: 20
Repeater {
model: 20
Row {
spacing: 20
Text {
text: "Input #" + (index + 1)
anchors.verticalCenter: parent.verticalCenter
}
TextInput {
width: 100
height: 30
onActiveFocusChanged: {
if (activeFocus)
keyboardRect.visible = activeFocus
}
Rectangle {
border.width: 1
anchors.fill: parent
anchors.margins: -1
z: -1
}
}
}
}
}
Rectangle {
id: keyboardRect
width: parent.width
height: parent.height * 0.3
anchors.bottom: parent.bottom
color: "grey"
visible: false
}
}
To make it usable with a virtual keyboard, move the content into a Flickable:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
id: root
width: 480
height: 800
visible: true
Flickable {
id: flickable
anchors.fill: parent
anchors.margins: 20
anchors.bottomMargin: keyboardRect.visible ? keyboardRect.height : anchors.margins
contentWidth: column.implicitWidth
contentHeight: column.implicitHeight
flickableDirection: Flickable.VerticalFlick
Column {
id: column
spacing: 20
Repeater {
model: 20
Row {
spacing: 20
Text {
text: "Input #" + (index + 1)
anchors.verticalCenter: parent.verticalCenter
}
TextInput {
width: 100
height: 30
onActiveFocusChanged: {
if (activeFocus) {
keyboardRect.visible = activeFocus
var posWithinFlickable = mapToItem(column, 0, height / 2);
flickable.contentY = posWithinFlickable.y - flickable.height / 2;
}
}
Rectangle {
border.width: 1
anchors.fill: parent
anchors.margins: -1
z: -1
}
}
}
}
}
}
Rectangle {
id: keyboardRect
width: parent.width
height: parent.height * 0.3
anchors.bottom: parent.bottom
color: "grey"
visible: false
}
}
A few things to note:
anchors.bottomMargin: keyboardRect.visible ? keyboardRect.height : anchors.margins
This ensures that the content is "pushed" up when the keyboard is visible, so that nothing is hidden below it.
onActiveFocusChanged: {
if (activeFocus) {
keyboardRect.visible = activeFocus
var posWithinFlickable = mapToItem(column, 0, height / 2);
flickable.contentY = posWithinFlickable.y - flickable.height / 2;
}
}
This code doesn't account for losing focus and hence the keyboard always stays open.
We focus the Flickable on the current input field by mapping the position of the field to the Column.
Finally, you'll see a bit of jumping around when you click on the fields near the top or bottom of the column. This can be probably solved by not setting the contentY if the field is near the top or bottom. An exercise for the reader. :)
For me correct answer is above (first one) plus following:
https://doc.qt.io/qt-5/qtvirtualkeyboard-deployment-guide.html#creating-inputpanel
import QtQuick 2.0
import QtQuick.VirtualKeyboard 2.1
Item {
id: root
Item {
id: appContainer
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: inputPanel.top
...
}
InputPanel {
id: inputPanel
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
}
Quote:
The input panel must be a sibling element next to the application
container. It is important not to put the input panel within the
application container, as it would then overlap with the contents of
the application. Also, the input panel height will be automatically
updated according to the available width; the aspect ratio of the
input panel is constant.

How to limit the size of drop-down of a ComboBox in QML

I am using a ComboBox in QML and when populated with a lot of data it exceeds my main windows bottom boarder. From googling I have learned that the drop-down list of a ComboBox is put on top of the current application window and therefore it does not respect its boundaries.
Ideally I would want the ComboBox to never exceed the main applications boundary, but I can not find any property in the documentation.
A different approach would be to limit the number of visible items of the drop-down list so that it do not exceed the window limits for a given window geometry. I was not able to find this in the documentation either and I have run out of ideas.
Take a look to the ComboBox source code, the popup is of a Menu type and it doesn't have any property to limit its size. Moreover, the z property of the Menu is infinite, i.e. it's always on top.
If you Find no way but to use the ComboBox of Qt you can create two models one for visual purpose, I will call it visual model, you will show it in your ComboBox and the complete one , it will be the reference model. Items count in your VisualModel wil be equal to some int property maximumComboBoxItemsCount that you declare . you'll need o find a way that onHovered find the index under the mouse in the visualmodel if it's === to maximumComboBoxIemsCount you do visualModel.remove(0) et visualModel.add(referenceModel.get(maximum.. + 1) and you'll need another property minimumComboBoxIemsCount, same logic but for Scroll Up , I dont know if it will work. but it's an idea
I think there is no solution using the built-in component and you should create your own comboBox. You can start from the following code.
ComboBox.qml
import QtQuick 2.0
Item {
id: comboBox
property string initialText
property int maxHeight
property int selectedItem:0
property variant listModel
signal expanded
signal closed
// signal sgnSelectedChoice(var choice)
width: 100
height: 40
ComboBoxButton {
id: comboBoxButton
width: comboBox.width
height: 40
borderColor: "#fff"
radius: 10
margin: 5
borderWidth: 2
text: initialText
textSize: 12
onClicked: {
if (listView.height == 0)
{
listView.height = Math.min(maxHeight, listModel.count*comboBoxButton.height)
comboBox.expanded()
source = "qrc:/Images/iconUp.png"
}
else
{
listView.height = 0
comboBox.closed()
source = "qrc:/Images/iconDown.png"
}
}
}
Component {
id: comboBoxDelegate
Rectangle {
id: delegateRectangle
width: comboBoxButton.width
height: comboBoxButton.height
color: "#00000000"
radius: comboBoxButton.radius
border.width: comboBoxButton.borderWidth
border.color: comboBoxButton.borderColor
Text {
color: index == listView.currentIndex ? "#ffff00" : "#ffffff"
anchors.centerIn: parent
anchors.margins: 3
font.pixelSize: 12
text: value
font.bold: true
}
MouseArea {
anchors.fill: parent
onClicked: {
listView.height = 0
listView.currentIndex = index
comboBox.selectedItem = index
tools.writePersistence(index,5)
comboBoxButton.text = value
comboBox.closed()
}
}
}
}
ListView {
id: listView
anchors.top: comboBoxButton.bottom
anchors.left: comboBoxButton.left
width: parent.width
height: 0
clip: true
model: listModel
delegate: comboBoxDelegate
currentIndex: selectedItem
}
onClosed: comboBoxButton.source = "qrc:/Images/iconDown.png"
Component.onCompleted: {
var cacheChoice = tools.getPersistence(5);
listView.currentIndex = tools.toInt(cacheChoice)
selectedItem = listView.currentIndex
comboBoxButton.text = cacheModel.get(selectedItem).value
}
}
ComboBoxButton.qml
import QtQuick 2.0
Item {
id: container
signal clicked
property string text
property alias source : iconDownUp.source
property string color: "#ffffff"
property int textSize: 12
property string borderColor: "#00000000"
property int borderWidth: 0
property int radius: 0
property int margin: 0
Rectangle {
id: buttonRectangle
anchors.fill: parent
color: "#00000000"
radius: container.radius
border.width: container.borderWidth
border.color: container.borderColor
Image {
id: image
anchors.fill: parent
source: "qrc:/Images/buttonBackground.png"
Image {
id: iconDownUp
source: "qrc:/Images/iconDown.png"
sourceSize.height:20
sourceSize.width: 20
anchors.verticalCenter: parent.verticalCenter
}
}
Text {
id:label
color: container.color
anchors.centerIn: parent
font.pixelSize: 10
text: container.text
font.bold: true
}
MouseArea {
id: mouseArea;
anchors.fill: parent
onClicked: {
container.clicked()
buttonRectangle.state = "pressed"
startTimer.start()
}
}
Timer{
id:startTimer
interval: 200
running: false;
repeat: false
onTriggered: buttonRectangle.state = ""
}
states: State {
name: "pressed"
when: mouseArea.pressed
PropertyChanges { target: image; scale: 0.7 }
PropertyChanges { target: label; scale: 0.7 }
}
transitions: Transition {
NumberAnimation { properties: "scale"; duration: 200; easing.type: Easing.InOutQuad }
}
}
}
I've used it in some software of mine, hence it is possible that It could not work "out of the box". I use it like this:
ComboBox{
id:cacheChoice
initialText: "None"
anchors.top: baseContainer.top
anchors.topMargin: 2
anchors.right: baseContainer.right
maxHeight: 500
listModel: cacheModel
onExpanded: {
cacheChoice.height = 500
}
onClosed: {
cacheChoice.height = 20
}
}
In case you are working with ComboBox from Qt Quick Controls 2, here's the source code for it:
https://github.com/qt/qtquickcontrols2/blob/5.12/src/imports/controls/ComboBox.qml
Based on that, this override of the behavior works to limit the height to something reasonable:
myComboBox.popup.contentItem.implicitHeight = Qt.binding(function () {
return Math.min(250, myComboBox.popup.contentItem.contentHeight);
});
It is possible to access the hidden MenuStyle within the ComboBoxStyle component. There you can use all the things and hidden things you have within a MenuStyle, including its maximum height.
The thing looks roughly like this.
Not pretty but it works well enough.
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.3
import QtQuick.Window 2.2
ComboBox {
id: comboBox
style: ComboBoxStyle {
// drop-down customization here
property Component __dropDownStyle: MenuStyle {
__maxPopupHeight: 400
__menuItemType: "comboboxitem" //not 100% sure if this is needed
}
}
As it came up resonantly in our team, here is a updated version of the idea shown above. The new version restricts the size automatically to the size of your application.
ComboBox {
id: root
style: ComboBoxStyle {
id: comboBoxStyle
// drop-down customization here
property Component __dropDownStyle: MenuStyle {
__maxPopupHeight: Math.max(55, //min value to keep it to a functional size even if it would not look nice
Math.min(400,
//limit the max size so the menu is inside the application bounds
comboBoxStyle.control.Window.height
- mapFromItem(comboBoxStyle.control, 0,0).y
- comboBoxStyle.control.height))
__menuItemType: "comboboxitem" //not 100% sure if this is needed
} //Component __dropDownStyle: MenuStyle
} //style: ComboBoxStyle
} //ComboBox

qml listview improve speed of changing items

i have a listview, how to change a speed of changing items, tried highlightMoveSpeed(highlightMoveDuration), but that does not working
Is there any way to increase the spped
slider.qml
import QtQuick 1.0
Rectangle {
id: slider
anchors.fill: parent
Component {
id: pageDelegate
Rectangle {
id: page
height: parent.height
Component.onCompleted: page.width = slider.width
Rectangle {
anchors.fill: parent
// anchors.margins: 15
Image{
anchors.top: parent.top
anchors.fill: parent
source: modelData
}
}
}
}
ListView {
id: list_model
anchors.fill: parent
model: modelData
delegate: pageDelegate
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
spacing: 5
highlightMoveSpeed: 10000000
}
}
You can either use the default highlight and set its speed, e.g.
highlightMoveDuration : 200
highlightMoveVelocity : 1000
or, in case you use your custom highlight, let the highlight component handle the behaviour. E.g.
// Set the highlight delegate. Note we must also set highlightFollowsCurrentItem
// to false so the highlight delegate can control how the highlight is moved.
highlightFollowsCurrentItem: false
highlight: Rectangle {
y: myListView.currentItem.y;
Behavior on y {
SmoothedAnimation {
easing.type: Easing.Linear
duration:200;
maximumEasingTime:300
velocity : 1000
}
}
}
Check the qt highlight example
A note about the other highlight move property: if you want to use highlightMoveDuration instead of highlightMoveVelocity (highlightMoveSpeed in Qt 4), you need to set the latter to -1:
highlightMoveDuration: 1000
highlightMoveVelocity: -1

Resources