Create a context menu with QML - qt

The question is quite simple: How to create a context menu with QML and javascript?
I have found this manual about 'Menu' component on qt-project.org but quite unusable: http://qt-project.org/doc/qt-5.1/qtquickcontrols/qml-qtquick-controls1-menu.html#details
The Qt Creator IDE says: "Unknown component" on the word 'Menu' in my QML file. I'm using Qt 5.2.1 stable. And I'm coding with Qt Quick 2.

Need to import Qt Quick Controls along with Qt Quick:
import QtQuick 2.0
import QtQuick.Controls 1.1
For a context menu, you need to call popup() which opens the menu at the cursor position.

I have created one customized context menu for my desktop application. This is working perfect for me. I think this may be helpfull.
ContextMenu.qml
import QtQuick 1.1
Rectangle {
id: contextMenuItem
signal menuSelected(int index) // index{1: Select All, 2: Remove Selected}
property bool isOpen: false
width: 150
height: menuHolder.height + 20
visible: isOpen
focus: isOpen
border { width: 1; color: "#BEC1C6" }
Column {
id: menuHolder
spacing: 1
width: parent.width
height: children.height * children.length
anchors { verticalCenter: parent.verticalCenter; left: parent.left; leftMargin: 3 }
ContextButton {
id: selectedAll
button_text: "Select All"
index: 1
onButtonClicked: menuSelected(index);
}
ContextButton {
id: removeSelected
button_text: "Remove Selected"
index: 2
onButtonClicked: menuSelected(index);
}
}
}
ContextItem.qml
import QtQuick 1.1
Item {
id: contextButtonItem
property string button_text;
property bool clicked;
property int index;
property string target;
property bool enable: true;
signal buttonClicked;
height: 25
width: parent.width - 5
function viewButtonHovered() {
viewButton.state = "hovered";
outerArea.z= -10;
}
function viewButtonExited() {
outerArea.z= 1;
if(clicked == false) {
viewButton.state = "";
} else {
viewButton.state = "clicked"
}
}
Rectangle {
id: viewButton;
height: vButton.height + 4
width: parent.width
Text {
id: vButton
text: qsTr(button_text)
width: parent.width
anchors { verticalCenter: parent.verticalCenter; left: parent.left; leftMargin: 10 }
font { pixelSize: 14 }
}
MouseArea {
hoverEnabled: enable
anchors.fill: parent
enabled: enable
onClicked: buttonClicked();
onEntered: viewButtonHovered();
onExited: viewButtonExited();
}
states: [
State {
name: "clicked";
PropertyChanges { target: vButton; color: "#286E1E"; }
},
State {
name: "hovered";
PropertyChanges { target: vButton; color: "#BEA1C6"; }
},
State {
name: "normal";
PropertyChanges { target: vButton; color: "#232323"; }
}
]
}
}

Related

Moving qml Item out of left side of window

I want to move a qml Item out of the left side of the app window.
While this task works perfectly for the right side of the window by defining a state like this
states: State {
name: "hidden"
when: is_hidden == true
AnchorChanges {
target: right_item_to_move
anchors.right: undefined
}
PropertyChanges {
target: right_item_to_move
x: main_window.width
}
}
and defining the appropriate Transition, I can't get it to work on the left side of the main window because negative x coordinates are not allowed.
I.e. this does not work:
states: State {
name: "hidden"
when: is_hidden == true
AnchorChanges {
target: left_item_to_move
anchors.left: undefined
}
PropertyChanges {
target: left_item_to_move
x: -left_item_to_move.width
}
}
How can I achieve this task? I'm using Qt 5.8 and QtQuick 2.0.
In my opinion, one should strive to stay true to one way of positioning, so you should either use anchors or x/y-coordinates.
Here you can find an overview how to make the right choice.
In short: When in doubt, use anchors. When the positioning is only relative to the parent (static) use x and y and if not possible otherwise do so even when not relative to the parent.
As you have chosen anchors, in my opinion you should stick to that - meaning: change the anchoring, so that instead of the left anchor line of the object, the right anchor line will be anchored to the window's left.
This would look like this:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: myWindow
visible: true
width: 600
height: 600
color: 'white'
Rectangle {
anchors.centerIn: parent
width: 300
height: 600
color: 'green'
Button {
id: but
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked: {
state = (state === 'left' ? '' : 'left')
}
states: [
State {
name: 'left'
AnchorChanges {
target: but
anchors.left: undefined
anchors.right: parent.left
}
}
]
transitions: [
Transition {
AnchorAnimation {
duration: 200
}
}
]
}
}
}
An example, how it might look, if you choose to modify the x value, it might look like this:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: myWindow
visible: true
width: 600
height: 600
color: 'white'
Rectangle {
anchors.centerIn: parent
width: 300
height: 600
color: 'green'
Button {
id: but
property bool shown: true
anchors {
verticalCenter: parent.verticalCenter
}
onClicked: {
shown = !shown
}
x: (shown ? 0 : -width)
Behavior on x {
XAnimator {
duration: 200
}
}
}
}
}

How to propertly connect signal in Loader's item?

I want connect one signal from QObject to various pages, loaded by the "Loader" qml element. My problem similar Dead QML elements receiving signals? but loaded items destroyed before calling the "onDestruction" method.
For example below, if switch from page1 to page2 in console writed:
"QML: Loading status: 1 Item: QDeclarativeRectangle(0x8dcd408, "page2")
QML Item: Loaded QDeclarativeRectangle(0x8dcd408, "page2") 1
qrc:/page1.qml:12: TypeError: Result of expression 'parent' [null] is not an object.
qrc:/page1.qml:15: ReferenceError: Can't find variable: page1text"
every second. So there can't disconnect from signal because parent object is destroyed.
How to handle signals from QObject (root) in loaded items? or How to disconnect signal from unloaded page?
main.qml
import QtQuick 1.1
Rectangle {
id: root
objectName: "root"
width: 360
height: 360
state: "page1"
color: "white"
Item {
width: parent.width
height: parent.height/2
anchors.top: parent.top
Loader {
id: pageLoader
objectName: "pageLoader"
anchors.fill: parent
anchors.centerIn: parent
signal textMsg(variant params)
onStatusChanged: console.log("QML: Loading status: ", status, " Item: ", item)
onLoaded: { console.log("QML Item: Loaded",item,status); }
}
}
states: [
State {
name: "page1"
PropertyChanges { target: pageLoader; source: "qrc:/page1.qml"}
}
,State {
name: "page2"
PropertyChanges { target: pageLoader; source: "qrc:/page2.qml"}
}
]
Timer {
// simulate signals from QObject
interval: 1000; running: true; repeat: true
onTriggered: pageLoader.textMsg({"msg2page1":"test","msg2page2":"test"})
}
Rectangle {
anchors.left: parent.left
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "yellow"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 1"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page1";
}
}
}
Rectangle {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "red"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 2"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page2";
}
}
}
}
page1.qml
import QtQuick 1.1
Rectangle {
id: page1
objectName: "page1"
color: "yellow"
Component.onCompleted: {
parent.textMsg.connect(msgHandler);
}
Component.onDestruction: {
parent.textMsg.disconnect(msgHandler);
}
function msgHandler(params) {
page1text.text += " "+params.msg2page1;
}
Text {
id: page1text
anchors.fill: parent
wrapMode: Text.WordWrap
text: "page1"
}
}
page2.qml
import QtQuick 1.1
Rectangle {
id: page2
objectName: "page2"
color: "red"
}
That's nicely described in Loader documenation. It reads:
Any signals emitted from the loaded item can be received using the Connections element.
There is also an example, I copy it below for the sake of clarity:
// Application.qml
import QtQuick 1.0
Item {
width: 100; height: 100
Loader {
id: myLoader
source: "MyItem.qml"
}
Connections {
target: myLoader.item
onMessage: console.log(msg)
}
}
// MyItem.qml
import QtQuick 1.0
Rectangle {
id: myItem
signal message(string msg)
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: myItem.message("clicked!")
}
}
Clearly, if item is destroyed, any signal handlers are ignored until the target is recreated again.
My answer is: Don't use the "Loader", create child object by JS and destroy it as no needed, for example:
main.qml
import QtQuick 1.1
import "qrc:/pageloader.js" as Pageloader
Rectangle {
id: root
objectName: "root"
width: 360
height: 360
state: "page1"
color: "white"
signal textMsg (variant params)
states: [
State {
name: "page1"
StateChangeScript{ script: Pageloader.createPageObject("qrc:/page1.qml");}
}
,State {
name: "page2"
StateChangeScript{ script: Pageloader.createPageObject("qrc:/page2.qml");}
}
]
Timer {
// simulate signals from QObject
interval: 1000; running: true; repeat: true
onTriggered: textMsg({"msg2page1":"test","msg2page2":"test"})
}
Rectangle {
anchors.left: parent.left
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "yellow"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 1"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page1";
}
}
}
Rectangle {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "red"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 2"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page2";
}
}
}
}
pageloader.js
var component;
var sprite;
function createPageObject(path) {
if(sprite){
console.log("sprite.destroy() ",typeof sprite);
sprite.destroy();
console.log("component.destroy() ",typeof component);
component.destroy();
}
component = Qt.createComponent(path);
if (component.status === Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(root);
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else{
if (component.status === Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}else{
console.log("Component status changed:", component.status);
}
}
}
page1.qml and page2.qml not changed.
I got it. My setup:
qml file to display ListViews
Several qml files defining Listviews, each takes a different column of different SQL tables. The model comes from C++
So here is the shortened code:
Dialog {
id: dialog
width: 1000; height: 400
property Component listViewItem
signal newDatabaseEntry( string text ) [1]
contentItem: Rectangle {
[...]
TextInputWithButton { [3]
id: newRecords
onInputAccepted: { newDatabaseEntry( text ) } [1]
}
}
[...]
Loader {
id: listViewPlaceholder
anchors.fill: parent
sourceComponent: dialog.listViewItem
onLoaded: {
if( typeof listViewPlaceholder.item.insertRecord === "function" )
// newRecords.inputAccepted.connect( listViewPlaceholder.item.insertRecord ) [1]
dialog.newDatabaseEntry.connect( listViewPlaceholder.item.insertRecord ) [2]
}
The above code is the general view of ListViews. The signal roundtrip [1] is necessary, otherwise no data is passed. How to chain signals is described here:
http://doc.qt.io/qt-5/qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals
The input button [3] delivers the confirmed data to be inserted into the db.
A ListView passed to the above function looks like this:
DialogSqlSingleColumnEdit {
listViewItem: ListView {
function insertRecord( text ) {
console.log( "done:" + text )
sqlModel.insertRecord( text )
}
[...]
The insertRecord is called forwards the text to the sql-C++ model.

Custom Button inheritance (like in OOP rules)

I have made custom Button in QML and I want it to be the base item for all buttons in my project. What I want is to derive (like in OOP) buttons from it to change functionality. At first, every derived button should have its own onClicked response.
Is this possible in QML and if it is, how?
It's possible.
Here is an example of my BaseButton type. When BaseButton is clicked it emits a custom signal, in my code it's sgnClicked.
BaseButton.qml
import QtQuick 2.0
Item {
id:idButton
signal sgnClicked()
signal sgnClickMaintained()
signal sgnEntered()
signal sgnExited()
signal sgnReleased()
signal sgnPressed()
signal sgnCanceled()
property alias label: idText
property alias text: idText.text
property string iconSourceUp:""
property string iconSourceDown:""
property string iconSourceDisabled:""
property alias backgroundWidth: background.width
property alias backgroundHeight: background.height
property alias backgroundRect: backgroundRect
property alias hover: touchArea.enabled
width: 100
height: 20
Text{
id:idText
//text: "Button"
color:"white"
anchors.centerIn: parent
font.pointSize: 12
}
//if maintained at each 300 ms resend signal
Timer{
id:timer
running: false
repeat: true
interval: 300
onTriggered: sgnClickMaintained()
}
Image{
id:background
z: -1
width: parent.width
height: parent.height
source:iconSourceUp
visible: source.toString() !== ""
}
Gradient {
id:idGradient
GradientStop { position: 0 ; color: touchArea.pressed ? "#ccc" : "#eee" }
GradientStop { position: 1 ; color: touchArea.pressed ? "#aaa" : "#ccc" }
}
Rectangle {
id: backgroundRect
width: parent.width
height: parent.height
border.color: "#888"
color: enabled ?"":"lightgrey"
radius: 4
z: -1
visible: !background.visible
gradient: enabled ?idGradient:null
}
MouseArea{
id: touchArea
anchors.fill: parent
hoverEnabled: true
onCanceled: idButton.sgnCanceled()
onClicked:
{
idButton.sgnClicked()
}
onEntered: idButton.sgnEntered()
onExited: idButton.sgnExited()
onPressAndHold: {
timer.restart()
idButton.sgnClickMaintained()
}
onReleased:{
idButton.state = "up"
timer.stop()
idButton.sgnReleased()
}
onPressed:
{
idButton.state = "down"
idButton.sgnPressed()
}
}
onEnabledChanged: {
if(enabled === false)
{
idButton.state = "disabled"
timer.stop()
}
else{
idButton.state = "up"
}
}
states: [
State {
name: "down"
PropertyChanges {
target: background
source: iconSourceDown
}
},
State {
name: "disabled"
PropertyChanges {
target: background
source: iconSourceDisabled
}
},
State {
name: "up"
PropertyChanges {
target: background
source: iconSourceUp
}
}
]
Component.onCompleted:{
if(enabled)
{
state = "up"
}
else
{
state = "disabled"
}
}
}
To make a new Button inheriting from BaseButton you should instantiante the BaseButton as root item and in the slot onSgnClicked write what you want your button should do when clicked.
CustomButton.qml
import QtQuick 2.0
BaseButton {
width: 100
height: 50
onSgnClicked: {
//do something
}
}

How to create scrollbar in QtQuick 2.0?

I am trying to create a scrollbar in QtQuick 2.0,
I found that Scrollbar component is available in QtQuick 1.0 but I can't find such component in QtQuick 2.0. How can I create scrollbar for ListView in QtQuick 2.0?
Any help? Thanks in advance.
ScrollBar/ScrollIndicator is easy to do, and the code would be identical in QQ1 or QQ2 (except the import) :
///////// ScrollBar.qml //////////////
import QtQuick 2.0;
Item {
id: scrollbar;
width: (handleSize + 2 * (backScrollbar.border.width +1));
visible: (flickable.visibleArea.heightRatio < 1.0);
anchors {
top: flickable.top;
right: flickable.right;
bottom: flickable.bottom;
margins: 1;
}
property Flickable flickable : null;
property int handleSize : 20;
function scrollDown () {
flickable.contentY = Math.min (flickable.contentY + (flickable.height / 4), flickable.contentHeight - flickable.height);
}
function scrollUp () {
flickable.contentY = Math.max (flickable.contentY - (flickable.height / 4), 0);
}
Binding {
target: handle;
property: "y";
value: (flickable.contentY * clicker.drag.maximumY / (flickable.contentHeight - flickable.height));
when: (!clicker.drag.active);
}
Binding {
target: flickable;
property: "contentY";
value: (handle.y * (flickable.contentHeight - flickable.height) / clicker.drag.maximumY);
when: (clicker.drag.active || clicker.pressed);
}
Rectangle {
id: backScrollbar;
radius: 2;
antialiasing: true;
color: Qt.rgba(0.5, 0.5, 0.5, 0.85);
border {
width: 1;
color: "darkgray";
}
anchors { fill: parent; }
MouseArea {
anchors.fill: parent;
onClicked: { }
}
}
MouseArea {
id: btnUp;
height: width;
anchors {
top: parent.top;
left: parent.left;
right: parent.right;
margins: (backScrollbar.border.width +1);
}
onClicked: { scrollUp (); }
Text {
text: "V";
color: (btnUp.pressed ? "blue" : "black");
rotation: -180;
anchors.centerIn: parent;
}
}
MouseArea {
id: btnDown;
height: width;
anchors {
left: parent.left;
right: parent.right;
bottom: parent.bottom;
margins: (backScrollbar.border.width +1);
}
onClicked: { scrollDown (); }
Text {
text: "V";
color: (btnDown.pressed ? "blue" : "black");
anchors.centerIn: parent;
}
}
Item {
id: groove;
clip: true;
anchors {
fill: parent;
topMargin: (backScrollbar.border.width +1 + btnUp.height +1);
leftMargin: (backScrollbar.border.width +1);
rightMargin: (backScrollbar.border.width +1);
bottomMargin: (backScrollbar.border.width +1 + btnDown.height +1);
}
MouseArea {
id: clicker;
drag {
target: handle;
minimumY: 0;
maximumY: (groove.height - handle.height);
axis: Drag.YAxis;
}
anchors { fill: parent; }
onClicked: { flickable.contentY = (mouse.y / groove.height * (flickable.contentHeight - flickable.height)); }
}
Item {
id: handle;
height: Math.max (20, (flickable.visibleArea.heightRatio * groove.height));
anchors {
left: parent.left;
right: parent.right;
}
Rectangle {
id: backHandle;
color: (clicker.pressed ? "blue" : "black");
opacity: (flickable.moving ? 0.65 : 0.35);
anchors { fill: parent; }
Behavior on opacity { NumberAnimation { duration: 150; } }
}
}
}
}
To use it :
import QtQuick 2.0;
Rectangle {
width: 400;
height: 300;
ListView {
id: list;
anchors.fill: parent;
model: 100;
delegate: Rectangle {
height: 50;
width: parent.width;
color: (model.index %2 === 0 ? "darkgray" : "lightgray");
}
}
ScrollBar {
flickable: list;
}
}
Enjoy !
Loved the solution by TheBootroo (+1 for him!) but found his solution only few days ago, by following a comment to a recent question.
Meanwhile, I've independently developed mine for a project I was working on and I'm going to share such a solution here. Hope it can be useful. :)
My scrollbar has a (sort of) "OS X feel" (intended) so e.g. it does not include scrolling arrows on the sides.
Here is the code:
import QtQuick 2.0
Item {
id: scrollbar
property Flickable flk : undefined
property int basicWidth: 10
property int expandedWidth: 20
property alias color : scrl.color
property alias radius : scrl.radius
width: basicWidth
anchors.right: flk.right;
anchors.top: flk.top
anchors.bottom: flk.bottom
clip: true
visible: flk.visible
z:1
Binding {
target: scrollbar
property: "width"
value: expandedWidth
when: ma.drag.active || ma.containsMouse
}
Behavior on width {NumberAnimation {duration: 150}}
Rectangle {
id: scrl
clip: true
anchors.left: parent.left
anchors.right: parent.right
height: flk.visibleArea.heightRatio * flk.height
visible: flk.visibleArea.heightRatio < 1.0
radius: 10
color: "gray"
opacity: ma.pressed ? 1 : ma.containsMouse ? 0.65 : 0.4
Behavior on opacity {NumberAnimation{duration: 150}}
Binding {
target: scrl
property: "y"
value: !isNaN(flk.visibleArea.heightRatio) ? (ma.drag.maximumY * flk.contentY) / (flk.contentHeight * (1 - flk.visibleArea.heightRatio)) : 0
when: !ma.drag.active
}
Binding {
target: flk
property: "contentY"
value: ((flk.contentHeight * (1 - flk.visibleArea.heightRatio)) * scrl.y) / ma.drag.maximumY
when: ma.drag.active && flk !== undefined
}
MouseArea {
id: ma
anchors.fill: parent
hoverEnabled: true
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: 0
drag.maximumY: flk.height - scrl.height
preventStealing: true
}
}
}
And here is the code to use it. All the fields are optional expect for the flickable, obviously. Values set are the default ones:
ScrollBar {
flk: privacyFlick
radius: 10 // Optional
basicWidth: 10 // Optional
expandedWidth: 20 // Optional
color: "grey" // Optional
}
I think this will do the trick
http://qt-project.org/doc/qt-5.1/qtquickcontrols/qml-qtquick-controls1-scrollview.html
import QtQuick 2.0
import QtQuick.Controls 1.0
ScrollView{
ListView {
...
}
}
Qt 5.6 introduces new controls as the technical preview "Qt Labs Controls". Among other stuff, the controls introduce a built-in ScrollBar type (interactive) and ScrollIndicator type (not interactive).
In Qt 5.7 new controls exited technical preview and are now renamed "Quick Controls 2", to stress the fact that they superseed the previous controls.
If you are using Qt 5.6, which is an LTS version and will be around for quite sometime, ScrollBar can be used as follows:
import QtQuick 2.6
import Qt.labs.controls 1.0
import QtQuick.Window 2.2
ApplicationWindow {
visible: true
width: 400
height: 600
Flickable {
anchors.fill: parent
contentWidth: image.width
contentHeight: image.height
//ScrollIndicator.vertical: ScrollIndicator { } // uncomment to test
ScrollBar.vertical: ScrollBar { }
ScrollBar.horizontal: ScrollBar { }
Image {
id: image
source: "http://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg"
}
}
}
Whereas in Qt 5.7 and onward you can use ScrollBar or ScrollIndicator as follows:
import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
ApplicationWindow {
visible: true
width: 600
height: 300
Flickable {
anchors.fill: parent
contentWidth: image.width
contentHeight: image.height
ScrollIndicator.vertical: ScrollIndicator { }
//ScrollBar.vertical: ScrollBar { } // uncomment to test
Image {
id: image
source: "http://s-media-cache-ak0.pinimg.com/736x/92/9d/3d/929d3d9f76f406b5ac6020323d2d32dc.jpg"
}
}
}
Usage syntax is pretty much the same whereas a major refactoring occured in the styling code as can be seen in e.g. Labs Controls ScrollIndicator customization page in comparison to Quick Controls 2 ScrollIndicator customization page.

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