QML : Drop-down menu that opens upward - qt

I need to have drop-down that opens upwards on clicking on Menu button in QML.
I have tried to use the listview for the same, but in the implementation we are getting drop-down which opens downwards.
Any suggestions with reference to below snippet.
import QtQuick 1.1
Rectangle {
width: 800
height: 480
Rectangle {
id:comboBox
property variant items: ["Red", "Blue", "Green"]
signal comboClicked;
x: 651
y: 344
width: 141
height: 30;
z: 0
smooth:true;
Rectangle {
id:chosenItem
radius:4;
width:parent.width;
height:comboBox.height;
color: "#454b4d"
smooth:true;
Text {
anchors.top: parent.top;
anchors.margins: 8;
id:chosenItemText
x: 11
y: 5
color: "#ffffff"
text:"Menu";
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 12
font.family: "Arial"
font.pointSize: 14;
smooth:true
}
MouseArea {
width: 400
height: 30
anchors.bottomMargin: 0
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: "lightblue"
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 = ""
chosenItemText.text = modelData;
listView.currentIndex = index;
}
}
}
}
}
states: State {
name: "dropDown";
PropertyChanges { target: dropDown; height:30*comboBox.items.length }
}
transitions: Transition {
NumberAnimation { target: dropDown; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 }
}
}
}

Try to change the anchors of the dropDown item:
that
anchors.top: chosenItem.bottom;
should become
anchors.bottom: chosenItem.top;

Related

plus button under listview

I can create "+" (plus) button under all listview items.
This button will add a new item.
I can place it under all exsisting items. But ideály as a part as list.Because of scrolling, scrollbars and other standard listview functions. If listview will be not fill all available page size, scrolls will be ended in the middle of the screan etc...
I tested counting onpaint signal or something like this, but have no success. Because signal for one row goint more than one times, counting is mismatched and button is one time in seccond row, one time below third, sometimes is missing etc...
Example image:
Source code:
import QtQuick 2.10
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0
Page {
title: qsTr("Page 1")
anchors.fill: parent
focus: true
property int myIndex: 0
function setVisibility()
{
if(myModel.rowCount()*3 === myIndex)
{
myIndex = 0
return true
}
else
{
myIndex = myIndex + 1
return false
}
}
/*
*
*
* ListView Component
*
*
*/
ListView
{
id: listView1
model: myModel
currentIndex: 0
//property int actualHeight
anchors.fill: parent
clip: true
//spacing: 40
highlightMoveDuration: 1
highlightMoveVelocity: 1
highlightResizeDuration: 0.0
highlight: Rectangle
{
color: "#2e6377"
opacity: 0.3
}
delegate: hDelegate
}
/*
*
*
* ListViewItem Component
*
*
*/
Component
{
id: hDelegate
Item
{
width: parent.width
height: taskInfo.implicitHeight
property variant mainData: model
MouseArea
{
anchors.fill: parent
onClicked:
{
listView1.currentIndex = index
gIdd = listView1.currentItem.mainData.task_idd
gSubject = listView1.currentItem.mainData.task_subject
gBody = listView1.currentItem.mainData.task_body
listView1.currentIndex = index
}
onDoubleClicked:
{
listView1.currentIndex = index
stackView.push("page3.qml")
}
onPressAndHold:
{
listView1.currentIndex = index
stackView.push("page3.qml")
}
hoverEnabled: true
}
Row
{
id: taskInfo
spacing: 5
Rectangle
{
id: dificultStatus
height: taskColumn.height
width: taskColumn.height
color: "transparent"
Rectangle
{
id: rect22
color: "green"
width: parent.width - 20
height: parent.height - 20
radius: 15
border.color: "lightsteelblue"
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Column
{
id: taskColumn
width: listView1.width - editButton.width - dificultStatus.width - 10
Row
{
Text
{
text: task_subject
color: "lightsteelblue"
horizontalAlignment: Text.AlignRight
wrapMode: Text.WordWrap
font {family: localFont.name; pointSize: 14; letterSpacing: 1; wordSpacing: 1}
}
Text
{
text: task_subject
color: "lightsteelblue"
wrapMode: Text.WordWrap
font {family: localFont.name; pointSize: 14; letterSpacing: 1; wordSpacing: 1}
}
}
Text
{
id: text1
height: 50
width: parent.width
clip: true
text: task_body
color: "lightsteelblue"
wrapMode: Text.WordWrap
font {family: localFont.name; pointSize: 14; letterSpacing: 1; wordSpacing: 1}
}
}
Button
{
id: editButton
height: taskColumn.height
width: taskColumn.height
background:
Rectangle
{
anchors.fill: parent
color: "transparent"
Rectangle
{
color: "transparent"
width: parent.width - 20
height: parent.height - 20
radius: 15
border.color: "lightsteelblue"
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Text {
anchors.fill: parent
text: qsTr("...")
color: "lightsteelblue"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
anchors.centerIn: parent
}
onClicked:
{
listView1.currentIndex = index
gIdd = listView1.currentItem.mainData.task_idd
gSubject = listView1.currentItem.mainData.task_subject
gBody = listView1.currentItem.mainData.task_body
listView1.currentIndex = index
stackView.push("page3.qml")
}
}
/*
*
*
* AddButton Component
*
*
*/
Button
{
height: taskColumn.height
width: taskColumn.height
x: 0
y: 80
visible: setVisibility()
//visible: (myModel.rowCount() === ++myIndex) ? true : false
background:
Rectangle
{
anchors.fill: parent
color: "transparent"
Rectangle
{
color: "transparent"
width: parent.width - 20
height: parent.height - 20
radius: 15
border.color: "lightsteelblue"
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Text {
anchors.fill: parent
text: qsTr("+")
color: "lightsteelblue"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
anchors.centerIn: parent
}
onClicked:
{
listView1.currentIndex = index
gIdd = listView1.currentItem.mainData.task_idd
gSubject = listView1.currentItem.mainData.task_subject
gBody = listView1.currentItem.mainData.task_body
listView1.currentIndex = index
stackView.push("page2.qml")
}
}
}
}
}
}
You can just use ListView's footer property. The default footerPositioning is what you want.

Long TabBar - adding a size and position indicator to reflect the presence of off-screen tabs

I have a tab bar with a stacklayout like the following:
Rectangle {
id: rect
height: 190
anchors.right: parent.right
anchors.left: parent.left
color: "transparent"
anchors.top: uniqueHandleText.bottom
anchors.topMargin: 100
TabBar {
id: frame
anchors.right: parent.right
anchors.left: parent.left
background: Rectangle {
color: "#737373"
}
x: -hbar.position * width
Repeater {
model: wizard.categories
TabButton {
id: tabData
property bool selected: false
text: modelData.name
width: 200
font.pixelSize: 18
contentItem: Text {
text: tabData.text
font: tabData.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.WordWrap
color: "#FFFFFF"
}
background: Rectangle {
implicitWidth: frame.width
implicitHeight: 180
opacity: enabled ? 1 : 0.3
color: tabData.checked ? "#BD9CBE": "#737373"
}
}
}
}
ScrollBar {
id: hbar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Horizontal
size: rect.width / frame.width
anchors.left: parent.left
anchors.right: parent.right
anchors.top: frame.bottom
}
Text {
font.pixelSize: 18
text: "Next"
anchors.right: parent.right
visible: frame.x != frame.width ? true: false
}
StackLayout {
id: stack1
anchors.left: parent.left
anchors.right: parent.right
anchors.top: frame.bottom
currentIndex: frame.currentIndex
Repeater {
model: wizard.categories
Item {
id: homeTab
TabBar {
id: homeTabTab
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
height: 180
background: Rectangle {
color: "#958096"
}
Repeater {
model: modelData.sub_categories
TabButton {
property bool selected: false
id: currentTab
text: modelData.name
width: 200
font.pixelSize: 18
background: Rectangle {
implicitWidth: frame.width
implicitHeight: 180
opacity: enabled ? 1 : 0.3
color: currentTab.checked ? "#958096": "#8D758E"
}
contentItem: Text {
text: currentTab.text
font: currentTab.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.WordWrap
color: "#FFFFFF"
MouseArea {
anchors.fill: parent
onClicked: {
if(currentTab.checked){
currentTab.checked = false
} else {
currentTab.checked = true
}
}
onDoubleClicked: {
currentTab.selected = true
var found = false;
var someText = frame.itemAt(stack1.currentIndex).text;
print(someText)
for(var i = 0; i<wizard.selectedSkills.count; i++){
if(wizard.selectedSkills.get(i).name === someText){
wizard.selectedSkills.get(i).sub_categories.append({"name":currentTab.text});
wizard.skills.push({"name": someText})
found = true;
}
}
if(!found){
print(currentTab.text)
wizard.selectedSkills.append({"name":someText, "sub_categories":[{"name":currentTab.text}]})
}
print(window.selectedSkills)
}
}
}
}
}
}
}
}
}
}
I've tried many different things to add a scrollbar or to figure out how to use the flickable functionality that TabBar has. However, the documentation doesn't specify how it works, it just does. Therefore, they are not accessible (or even rewritteable, to use those properties). I want to add a small indicator like an arrow to specify that there is more elements for ease of navigation on desktop on top of the TabBar functionality.
It doesn't seem like the necessary properties are exposed in order to make this happen the easy way.
However, since this is QML, it means the whole object tree is gaping wide open to introspection, allowing us to establish that the item that does the flicking is the contentItem of a ListView inside the Container the ToolBar inherits. The view happens to be the second visible child, although this is technically "private implementation" that one should not rely on. So it is better to take some extra care to establish whether or not you have the correct object.
ApplicationWindow {
id: main
width: 640
height: 480
visible: true
TabBar {
id: toolbar
width: parent.width
height: 50
Repeater {
model: 10
TabButton {
text: "test " + index
width: 100
}
}
}
Rectangle {
height: 5
width: main.width * (view ? view.visibleArea.widthRatio : toolbar.width / toolbar.contentWidth)
color: "red"
anchors.top: toolbar.bottom
x: view ? (main.width - width) * (view.contentX / (view.contentWidth - view.width)) : 0
}
property ListView view: {
var l = toolbar.visibleChildren.length
while (--l) if ("cacheBuffer" in toolbar.visibleChildren[l]) return toolbar.visibleChildren[l]
return null
}
}
And there you have it. We iterate the tabview children until we find one that has a property cacheBuffer which is fairly unique to ListView, and once we have that, we can access the needed properties. As you see, for the indicator width we can do even without the list view, as the toolbar exposes a contentWidth property, but for the indicator position there is no workaround.
And it works:

Need responsive height for DropDown List in QML for ComboBox?

I am creating a custom combobox model in which i need to assign a height of a dropDown list in responsive value. It is on length of items at present so unable to reduce or increase its height as per screen resolution. Here is my code :
Rectangle {
width:150;
height: 60;
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:30*comboBox.items.length }
}
transitions: Transition {
NumberAnimation { target: dropDown; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 }
}
}
}
Please suggest me some solution.

Cursor shape changed even over an overlapping rectangle in QML

With the following code, the green rectangle entirely overlaps the red rectangle, but when the mouse is over the (hidden) red rectangle, my cursor shape is still changed according to the red MouseArea cursorShape.
Any idea to prevent this behavior?
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Rectangle {
color: "red"
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 100
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: "ClosedHandCursor"
}
}
Rectangle {
color: "green"
anchors.fill: parent
MouseArea {
anchors.fill: parent
hoverEnabled: true
}
}
}
Simply use 'containsMouse' property in the binding of cursorShape, and don't use the String form of enum values :
import QtQuick 2.0
Rectangle {
color: "white";
width: 400;
height: 400;
Rectangle {
color: "red";
anchors.top: parent.top;
anchors.left: parent.left;
width: 300;
height: 300;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
cursorShape: (containsMouse
? (pressed
? Qt.ClosedHandCursor
: Qt.OpenHandCursor)
: Qt.ArrowCursor);
}
}
Rectangle {
color: "green";
anchors.bottom: parent.bottom;
anchors.right: parent.right;
width: 300;
height: 300;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
}
}
}
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Rectangle {
color: "red"
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 100
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: greenRectangle.hovered ? Qt.ArrowCursor : Qt.ClosedHandCursor;
}
}
Rectangle {
id: greenRectangle;
property bool hovered: false;
color: "green"
anchors.fill: parent
anchors.leftMargin: 20;
MouseArea {
anchors.fill: parent
hoverEnabled: true
onHoveredChanged: {
greenRectangle.hovered = !greenRectangle.hovered;
console.log(greenRectangle.hovered);
}
}
}
}

Scrollist issue in QML

I'm trying to make scrollable list in QML.
Though its running successfully but whenever am varying the size of main window the pattern of the list distorts or the items overlaps on each other.
Any suggestions where is the bug in my code.
Tried to vary the anchors but then also no luck on the issue.
Below is the code snippet
import QtQuick 1.1
Item{
....
Rectangle{
....
Rectangle {
....
color: "white"
anchors.centerIn: main.Center
Rectangle {
...
ListView {
id: list_min
....
snapMode: ListView.SnapToItem
model: 20
delegate: Rectangle{
width: list_min.width
height: list_min.height
color: "transparent"
Text {
anchors.verticalCenter: parent.verticalCenter
text: index+1
font.pixelSize: parent.width/1.5
}
Text {
text: index+2
font.pixelSize: parent.width/1.5
anchors.top: parent.top
anchors.topMargin: 150
}
Text {
text: index
font.pixelSize: parent.width/1.5
anchors.bottom: parent.bottom
anchors.bottomMargin: 150
}
}
onMovementEnded: list_min.currentIndex = list_min.visibleArea.yPosition * list_min.count
Component.onCompleted: list_min.visibleArea
}
Rectangle {
....
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
....
GradientStop { position: 1.0; color: "black" }
}
}
}
}
I would recommend using the Column tag to place the text elements in the delegate.
Also for overlay_min, you need to either set the height & width OR the anchors.fill, not both.
I have modified the source code as below:
import QtQuick 1.1
Item{
width: 300
height: 240
Rectangle{
id:main
width: parent.width
height: parent.height
Rectangle {
id :frame_min
width: 120
height: main.height
color: "white"
anchors.centerIn: main.Center
Rectangle {
id: mSpinner
anchors.centerIn: parent
width: frame_min.width - 10
height: frame_min.height
color: "white"
border.color: "black"
border.width: 5
ListView {
id: list_min
width: mSpinner.width
height: mSpinner.height
anchors.topMargin: 0
anchors.top: parent.top
clip: true
snapMode: ListView.SnapToItem
model: 20
delegate: Rectangle{
width: list_min.width
height: list_min.height
color: "transparent"
Column{
anchors.verticalCenter: parent.verticalCenter
Text {
//anchors.verticalCenter: parent.verticalCenter
text: index+1
font.pixelSize: list_min.width/1.5
}
Text {
text: index+2
font.pixelSize: list_min.width/1.5
//anchors.top: parent.top
//anchors.topMargin: 150
}
Text {
text: index
font.pixelSize: list_min.width/1.5
//anchors.bottom: parent.bottom
//anchors.bottomMargin: 150
}
}
}
onMovementEnded: list_min.currentIndex = list_min.visibleArea.yPosition * list_min.count
Component.onCompleted: list_min.visibleArea
}
Rectangle {
id: overlay_min
width: frame_min.width
height: frame_min.height
//anchors.fill: frame_min
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 0.34; color: "transparent" }
GradientStop { position: 0.35; color: "white" }
GradientStop { position: 0.66; color: "transparent" }
GradientStop { position: 1.0; color: "black" }
}
}
}
}
}
}

Resources