How to set QML TableViewStyle to show Middle Ellipses (ElideMiddle) - qt

I'm creating a QML TableView and I want the text (in both the rows AND headers) to middle-ellipse whenever the text is too long to fit into its column. For example: This_is_really_long_text might display as This...text
I've got it successfully working without using a TableViewStyle, however I would like to use TableViewStyle to easily stylize multiple columns at once.
I've read the documentation for:
TableView QML (Item Delegate)
TableViewStyle QML Type
Item Delegate QML Type
Customizing QT Quick Controls (With Delegate)
I also tried making minor tweaks to some code on someone's previously asked question, simply swapping out the elide: Text.ElideRight for Text.ElideMiddle which also didn't work. It seems like changing the header color and height works, but not the elide.
The below code generates a table that does not show ellipses at all, though I expect middle-ellipses. If I remove the overrides, it will right-elide.
Image showing 2nd column cutting off 1st, but no ellipses
import QtQuick 2.9
import QtQuick.Controls 1.4 as QC1
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: 400
height: 400
ListModel {
id: myListModel
ListElement {
cell1Text: "This_is_some_really_long_text"
cell2Text: "Shorter_text"
}
}
QC1.TableView {
id: tableView
anchors.fill: parent
model: myListModel
QC1.TableViewColumn {
role: "cell1Text"
title: "Cell1Text"
}
QC1.TableViewColumn {
role: "cell2Text"
title: "Cell2Text"
}
style: TableViewStyle {
Text {
elide: Text.ElideMiddle
}
headerDelegate: Rectangle {
height: 20
color: "lightsteelblue"
Text {
text: styleData.value
elide: Text.ElideMiddle
}
}
rowDelegate: Rectangle {
Text {
elide: Text.ElideMiddle
}
}
itemDelegate: Rectangle {
Text {
text: styleData.value
elide: Text.ElideMiddle
}
}
}
}
}

The elide is applied taking as reference the width of the item, but in this case the size of the item is given by the content and not by the header, the solution in this case is to establish the width of the text as the father, also is not necessary to modify the rowDelegate
style: TableViewStyle {
headerDelegate: Rectangle {
height: 20
color: "lightsteelblue"
Text {
width: parent.width // <---
text: styleData.value
elide: Text.ElideMiddle
}
}
itemDelegate: Rectangle {
Text {
width: parent.width // <---
text: styleData.value
elide: Text.ElideMiddle
}
}
}
Another solution to set the elide in the TableViewColumn so as not to override the itemDelegate:
QC1.TableView {
id: tableView
anchors.fill: parent
model: myListModel
QC1.TableViewColumn {
role: "cell1Text"
title: "Cell1Text"
elideMode: Text.ElideMiddle
}
QC1.TableViewColumn {
role: "cell2Text"
title: "Cell2Text"
elideMode: Text.ElideMiddle
}
style: TableViewStyle {
headerDelegate: Rectangle {
height: 20
color: "lightsteelblue"
Text {
width: parent.width
text: styleData.value
elide: Text.ElideMiddle
}
}
}
}

Related

Is there a way to make unselectable a "list item" in ListView?

I am new to Qt. Wondering if there a possibility to make an item "unselectable" in ListView.
I see there are a lot of other things, e.g: collapsing , expanding, etc.
**
I have not find any simple example for this problem. **
Can you provide some minimalistic examples to make a specific item in the list unselectable?
I have the following minimalistic example. How can I set list item index 2 to be unselectable?
Window {
id: mainWindow
width: 130
height: 240
visible: truetitle: qsTr("Hello")
Rectangle {
id: bg
color: "#ffffff"
anchors.fill: parent
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
Component {
id: nameDelegate
Text {
text: model.name
font.pixelSize: 24
}
}
ListView {
anchors.fill: parent
model: nameModel
delegate: nameDelegate
clip: true
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
//height: parent.height
color: "lightgrey"
}
}
}
}
I found numerous issues with your code snippet, so I attempted to address them all:
I made use of Page and set Page.background instead of declaring an outer Rectangle. This removes a level of indentation
I refactored NameComponent.qml to reduce the complexity of your main program
I change the delegate from Text to ItemDelegate so that it is clickable, and, it being clickable, I can (1) make the ListView have active focus so that it can receive keyboard events, (2) change the current item in the ListView => I think this achieves your criteria of being able to select a different item
I removed unnecessary anchoring from your highlight - your highlight will default anchor to your selected item
I set the width of your delegate to listView.width - I also made use of the ListView.view attached property so that your delegate and access properties from the ListView
Finally, I added a 20 pixel width vertical ScrollBar
import QtQuick
import QtQuick.Controls
Page {
background: Rectangle { color: "#ffffff" }
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
ListView {
anchors.fill: parent
model: nameModel
delegate: NameDelegate { }
clip: true
highlight: Rectangle {
color: "lightgrey"
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}
// NameDelegate.qml
import QtQuick
import QtQuick.Controls
ItemDelegate {
property ListView listView: ListView.view
width: listView.width - 20
text: model.name
font.pixelSize: 24
onClicked: {
listView.forceActiveFocus();
if (listView.currentIndex === index) {
listView.currentIndex = -1;
} else {
listView.currentIndex = index;
}
}
}
You can Try it Online!

Landing Page Button Organization

I am using a template to create an app using QT Creator and QML and am hoping to create a landing page that allows users to select which "page" they want to navigate to by clicking an icon.
I've figured out how to get a button on the landing page and have it open another page. However, I am using x and y positions of the button and it doesn't scale correctly when the window size changes.
Ultimately, I am trying to put 6 buttons on the landing page in a way that scales correctly.
I have attached an image of my ideal Landing Page design and have also attached code for what I already have.
I hope I was able to explain this well enough. Please let me know if I can clarify anything.
import QtQuick 2.2
import QtQuick 2.6
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.4
import "components" as Components
//BACKGROUND COLOR
Rectangle {
signal signInClicked(string tourId)
color: "#242424"
AnimatedImage {
anchors.fill: parent
source: app.landingpageBackground
fillMode: Image.PreserveAspectCrop
visible: source > ""
}
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#00000000";}
GradientStop { position: 1.0; color: "#00000000";}
}
}
//TITLE TEXT
Text {
id: titleText
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: app.height/10
}
font.family: app.customTitleFont.name
text: app.info.title
font {
pointSize: 60
pointSize: app.titleFontSize * 1.4
}
color: "#00000000"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
Button {
id: signInButton
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 60 * app.scaleFactor
}
opacity: 0.0
style: ButtonStyle {
id: btnStyle
property real width: parent.width
label: Text {
id: lbl
text: signInButton.text
anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
width: parent.width
maximumLineCount: 2
elide: Text.ElideRight
wrapMode: Text.WordWrap
color: app.titleColor
font.family: app.customTextFont.name
font.pointSize: app.baseFontSize
}
background: Rectangle {
color: Qt.darker(app.headerBackgroundColor, 1.2)
border.color: app.titleColor
radius: app.scaleFactor * 2
}
}
height: implicitHeight < app.units(56) ? app.units(56) : undefined // set minHeight = 64, otherwise let it scale by content height which is the default behavior
width: Math.min(0.5 * parent.width, app.units(250))
text: qsTr("Let's Play!")
MouseArea{
anchors.fill: parent
onClicked: {
signInClicked("");
}
}
NumberAnimation{
id: signInButtonAnimation
target: signInButton
running: false
properties: "opacity"
from: 0.0
to: 1.0
easing.type: Easing.InQuad
duration: 1000
}
}
AboutPage {
id: aboutPage
}
NewsAndUpdates {
id: newsPage
}
ProgramsPage {
id: programsPage
}
Connections {
target: app
onUrlParametersChanged: {
if (app.urlParameters.hasOwnProperty("appid")) {
signInClicked(app.urlParameters.appid)
}
}
}
Component.onCompleted: {
signInButtonAnimation.start()
}
}
I think this doc should help you. You haven't really defined what you want very well, but I'll show you some examples so you can hopefully take from it what you need.
QML has the concept of "positioners" and "layouts". Positioners help automatically position your objects neatly on the screen. And Layouts try to do that too, but can also stretch your objects to fill available space.
Row:
You can arrange all your buttons in a row and center the row horizontally.
Row {
anchors.horizontalCenter: parent.horizontalCenter
Button { id: btn1 }
Button { id: btn2 }
...
}
Grid:
Similarly, Grid is a positioner that arranges objects into a grid:
Grid {
anchors.horizontalCenter: parent.horizontalCenter
columns: 3
Button { id: btn1 }
Button { id: btn2 }
...
}
GridLayout:
A GridLayout is just like a Grid, but it can also resize the objects to fill up the space. My opinion is layouts can do more, but they're often trickier to use. In this example, the first button should be a fixed size, while the second button should fill up the remaining width.
GridLayout {
anchors.fill: parent
rows: 2
Button { id: btn1; Layout.preferredWidth: 200 }
Button { id: btn2; Layout.fillWidth: true}
...
}

Checkbox becomes big when clicked on in QML tableview

This code does produce checkboxes in a tableview but when I click on the checkbox it becomes big. I want it to remain of a constant size.
Please guide.
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
Rectangle
{
id: rightside
anchors.fill: parent
height: parent.height
width: 1500
TableView
{
anchors.fill: parent
TableViewColumn
{
role: "selectall"
title: "Select All"
width: 100
delegate: CheckBox
{
anchors.fill: parent
checked: false
}
}
TableViewColumn {
role: "size"
title: "Size"
width: 100
}
TableViewColumn
{
role: "last_updated"
title: "Last Updated"
width: 100
delegate: Component
{
Rectangle
{
height: 100
width: 120
id: head
RowLayout
{
height: parent.height
width: parent.width
Rectangle
{
height: 20
width: 20
color: "red"
border.color: "black"
radius: 100
MouseArea
{
anchors.fill: parent
onClicked: parent.color = "grey"
}
}
}
}
}
}
model: ListModel
{
id: mymodel
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
}
}
There are lots of way to solve your problem. But first, let's do proper distinction between Qt Qtuick Controls versions. To do it, use this import statement:
import QtQuick.Controls 1.4 as QC1
And respectively use all components that requires QC1, e.g.: QC1.TableView, QC1.TableViewColumn.
In your example you are getting overlapping of components. To avoid it in terms of QC1 you can define a higher row delegate for your TableView. But this discards the default style. Simple example of its usage with style goes here:
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base
return styleData.selected ? myPalette.highlight : baseColor
}
}
As result you'll get this:
Another option in terms of QC2 is to redefine indicator style of CheckBox. Below you'll find an example that could possibly fit your app, based on Customizing CheckBox documentation; so your CheckBox delegate will look like this:
delegate: CheckBox {
id: control
anchors.fill: parent
checked: false
indicator: Rectangle {
id: outer
readonly property int size: 18
implicitWidth: size
implicitHeight: size
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 4
border.color: control.down ? "orangered" : "orange"
Rectangle {
id: inner
anchors.centerIn: parent
width: outer.size/2
height: width
radius: 3
color: control.down ? "orangered" : "orange"
visible: control.checked
}
}
}
As result you'll get this:

How to update or read TextFiled inside GridLayout which is in TabView

I have below stack of components and I want to read and set value of the TextFiled:
-Rectangle
-----TabView
---------Tab
-----------Rectangle
--------------GridLayout
------------------Rectangle
--------------------TextField <--- I want to access this TextField
I have also a case where I need to access Repeater inside the Tab:
-Rectangle
-----TabView
---------Tab
-----------Rectangle
--------------GridLayout
------------------Repeater
--------------------TextField <--- I want to access this TextField also
I have tried to access it using:
var tab0 = myTabView.getTab(0);
tab0.children[0].text = "Some Text"; // I get Undefined Error
I have tried to access the component using a function inside the Tab:
import QtQuick 2.0
import QtQuick.Controls 2.14 as QQC2
import QtQuick.Layouts 1.14
import QtQuick.Controls 1.4 as QQC1
QQC2.Item {
QQC1.TabView {
QQC1.Tab {
title: "tab1"
function printValue () {
console.log("myTextFld.txt: "+myTextFld.txt); // <-- Getting Error myTextFld undefined.
}
Rectangle {
id: tabHolderRext
color: "blue"
GridLayout {
id: myGrid
model: 7
Repeater {
id: herderRepeater
model: header
delegate: Rectangle {
TextField {
// I want to Access This TextField also
}
}
}
Rectangle {
id: row0Rect
Layout.row: 0
Layout.column: index
TextFiled {
id: myTextFld
text: modelData
}
}
// Rest of the rows
}
}
}
}
}
Item id can be used to access the values from TextField if you have all items in same qml file. If you have different qml files then make use of alias types link to access the values.
Repeater case: The Textfield has to update the underlying modelview --> model first then we can make use of the model's data.
Here is a sample code. I have stacked all item's in the same qml file so that access by id works here.
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
Item {
anchors.fill: parent
anchors.margins: 10
TabView {
anchors.fill: parent
Tab {
title: "TextField"
Item {
anchors.fill: parent
Grid {
spacing: 20
anchors.fill: parent
anchors.margins: 10
Rectangle {
height: 40
width: 150
TextField {
id: inputId
anchors.fill: parent
placeholderText: "enter text"
}
}
Button {
height: 40
width: 150
text: "show txt"
onClicked: labelId.text = inputId.text
}
Rectangle {
height: 40
width: 150
Label {
id: labelId
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
}
}
Tab {
title: "Repeater"
Item {
anchors.fill: parent
Grid {
spacing: 20
anchors.fill: parent
anchors.margins: 10
columns: 3
ListModel {
id: fruitModel
ListElement { name: "Apple" }
ListElement { name: "Orange" }
ListElement { name: "Banana" }
}
Repeater {
width: parent.width
height: parent.height / 2
model: fruitModel
delegate: Rectangle {
height: 40
width: 150
TextField {
anchors.fill: parent
text: name
onTextChanged: fruitModel.setProperty(index, "name", text) // update model data
}
}
}
Repeater {
width: parent.width
height: parent.height / 2
model: fruitModel
delegate: Rectangle {
height: 40
width: 150
Label {
text: name
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
}
}
}
}
}
}

Qt QML dropdown list like in HTML

Simple thing, but can't get find it. I want a simple dropdown selection box with a couple of selections. Like in HTML
<select>
<option>1</option>
<option>2</option>
</select>
what is the code for QML for that ?
Here's a simple example that could maybe be used as a starting point:
import QtQuick 1.0
Rectangle {
width:400;
height: 400;
Rectangle {
id:comboBox
property variant items: ["Item 1", "Item 2", "Item 3"]
property alias selectedItem: chosenItemText.text;
property alias selectedIndex: listView.currentIndex;
signal comboClicked;
width: 100;
height: 30;
z: 100;
smooth:true;
Rectangle {
id:chosenItem
radius:4;
width:parent.width;
height:comboBox.height;
color: "lightsteelblue"
smooth:true;
Text {
anchors.top: parent.top;
anchors.left: parent.left;
anchors.margins: 8;
id:chosenItemText
text:comboBox.items[0];
font.family: "Arial"
font.pointSize: 14;
smooth:true
}
MouseArea {
anchors.fill: parent;
onClicked: {
comboBox.state = comboBox.state==="dropDown"?"":"dropDown"
}
}
}
Rectangle {
id:dropDown
width:comboBox.width;
height:0;
clip:true;
radius:4;
anchors.top: chosenItem.bottom;
anchors.margins: 2;
color: "lightgray"
ListView {
id:listView
height:500;
model: comboBox.items
currentIndex: 0
delegate: Item{
width:comboBox.width;
height: comboBox.height;
Text {
text: modelData
anchors.top: parent.top;
anchors.left: parent.left;
anchors.margins: 5;
}
MouseArea {
anchors.fill: parent;
onClicked: {
comboBox.state = ""
var prevSelection = chosenItemText.text
chosenItemText.text = modelData
if(chosenItemText.text != prevSelection){
comboBox.comboClicked();
}
listView.currentIndex = index;
}
}
}
}
}
Component {
id: highlight
Rectangle {
width:comboBox.width;
height:comboBox.height;
color: "red";
radius: 4
}
}
states: State {
name: "dropDown";
PropertyChanges { target: dropDown; height:40*comboBox.items.length }
}
transitions: Transition {
NumberAnimation { target: dropDown; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 }
}
}
}
For new users, there is a built in ComboBox in Qt5.3 QtQuick.Controls ComboBox - Reference.
Example from Documentation:
import QtQuick 2.2
import QtQuick.Controls 1.2
ComboBox {
id: combo
editable: true
model: ListModel {
id: model
ListElement { text: "Banana"; color: "Yellow" }
ListElement { text: "Apple"; color: "Green" }
ListElement { text: "Coconut"; color: "Brown" }
}
onAccepted: {
if (combo.find(currentText) === -1) {
model.append({text: editText})
currentIndex = combo.find(editText)
}
}
}
Note: I had to post it as an answer, since the text is too long for a comment.
I've been using approaches with ComboBoxStyle (customization capabilities limited) and completely custom implementations, but they have a lot of limitations with focus management and z-index management.
I've end up with the implementation of ComboBox which consists of 2 parts: a header which you actually put somewhere and a dropdown component which you create dynamically. The latter consists of an Item covering everything (and intercepting mouse activity) and a dropdown which is carefully positioned below the header.
Code is pretty massive to included here so you can see details in my blogpost with all the code
If you targeting Nokia devices (Symbian or Meego), you could use high-level Qt Quick components. I believe Menu is something similar to html's select.
See http://doc.qt.nokia.com/qt-components-symbian/qml-menu.html or http://harmattan-dev.nokia.com/docs/library/html/qt-components/qt-components-meego-menu.html
If you are targeting Symbian, there is SelectionListItem and SelectionDialog:
http://doc.qt.nokia.com/qt-components-symbian/qml-selectionlistitem.html

Resources