how to imitate the button in QML - qt

I want to imitate the Button in QML, but why does it only work with containsMouse and !containsMouse, it doesn't work with OnPressed. can you help me ? Thank you.
Item {
id: area
property string str_noPressed;
property string str_hover;
property string str_pressed;
Image {
id: background
width: 75; height: 75
source: userArea.containsMouse ? str_hover : str_noPressed
MouseArea {
id: userArea
anchors.fill: parent
onClicked: {}
onPressed: background.source = str_pressed
hoverEnabled: true
}
}
}

Obviously, in the button is pressed, it also contains the mouse.
I assume containsMouse takes precedence over onPressed. Try:
onContainsMouseChanged: {
if (containsMouse && !pressed) {
background.source = str_pressed
}
}

Related

QML SplitView auto collapse on handlebar mouse release

I have a QML Controls 2 SplitView and a redefined handle, which works well, but I want detect mouse release event on the handler, so I could collapse the SplitView under a certain threshold of width. Adding a MouseArea on top of the existing handle will absorb drag events, so I'm unable to move the handlebar. Any idea how could I gather the mouse release event, or any other solution which solves this problem?
Alright, I have created an example application. As you can see in this example, my MouseArea is marked with yellow and collapses the right view programmatically when double clicked, which is nice, but I also want to drag the handlebar and upon mouse release under a certain width threshold I want to collapse the view as well. The black part of the handlebar where my MouseArea is not covering the handlebar, responds to drag, but since there is no signal I can gather from it, the width threshold already set shouldCollapse boolean property, so the view won't update. Probably I could solve this issue with a timer, but I need a more sophisticated solution.
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 800
height: 400
visible: true
SplitView {
id: splitView
anchors.fill: parent
orientation: Qt.Horizontal
function toggleCollapse() { collapsibleRect.shouldCollapse = !collapsibleRect.shouldCollapse }
handle: Rectangle {
implicitWidth: 20
implicitHeight: 20
color: "black"
MouseArea {
anchors.centerIn: parent
width: parent.width
height: parent.height / 2
onDoubleClicked: splitView.toggleCollapse()
Rectangle {
anchors.fill: parent
color: "yellow"
Text {
anchors.centerIn: parent
text: "Double click to collapse"
rotation: 90
}
}
}
}
Rectangle {
id: mainRect
color: "green"
SplitView.fillWidth: true
Text {
anchors.centerIn: parent
font.pixelSize: 24
text: "Main scene"
}
}
Rectangle {
id: collapsibleRect
property bool shouldCollapse: false
SplitView.preferredWidth: shouldCollapse ? 0 : 300
color: "purple"
clip: true
onWidthChanged: {
if(width < 200) shouldCollapse = true
else shouldCollapse = false
}
Text {
anchors.centerIn: parent
rotation: parent.shouldCollapse ? 90 : 0
font.pixelSize: 24
text: parent.shouldCollapse ? "SHOULD BE COLLAPSED" : "NOT COLLAPSED"
Behavior on rotation { NumberAnimation { duration: 100 } }
}
}
}
}
I had a similar problem and was able to solve it thanks to the hint of #Ponzifex that the SplitView's resizing property will be set to true as soon as the handle is clicked. Using a Timer I managed to detect whether the handle was quickly pressed twice in a row.
SplitView {
id: view
...
handle: Rectangle {
...
}
//============================================================
// double click behavior
Timer {
id: doubleClickTimer
interval: 300 // number of ms between clicks that should be considered a double click
}
property bool doubleClicked: false
// `resizing` will be set to true even if the handle is just pressed
onResizingChanged: {
if (view.resizing) {
if (!doubleClickTimer.running) {
doubleClickTimer.start();
return;
}
view.doubleClicked = true;
} else {
if (view.doubleClicked) {
// do any manual resizing in here
view.doubleClicked = false;
}
}
}
}
It is important to note, however, that it is only possible to resize the contents of a SplitView when resizing is false. That's why I need to have the doubleClicked helper property.
Add this to MouseArea:
onPressed: {
mouse.accepted = (mouse.flags & Qt.MouseEventCreatedDoubleClick);
}
propagateComposedEvents: true
cursorShape: Qt.SplitHCursor

QML: Mouse wheel event propagation in ListView

Have strange situation with ListView scrolling on mouse wheel. Have Items structure similar to this:
MainAppWindow {
// Some zoomable map item
Map {
anchors.fill: parent
}
PopupMenu { // Simple Rectangle item
anchors.top: parent.top
width: 200
height: parent.height / 2
z: parent.z + 1
ListView {
anchors.fill: parent
clip: true
...
delegate: Item {
...
MouseArea {
anchors.fill: parent
onClick: {
someHandler()
}
}
}
}
}
}
ListView with vertical scroll works and scrolls just fine until it stops at bounds (top or bottom - whatever) and after this mouse event starts to propagate to underlying layer and ZoomableMap starts to zoom which is not we want: should be propagated there only if PopupMenu is not visible. Adding
onWheel: wheel.accepted = true
into MouseArea inside ListView delegate could partially solve the problem - it disables wheel and allows scrolling only by dragging the content. However better allow scrolling by the wheel as well. MouseArea in PopupMenu blocks wheel and dragging in the ListView completely as well - not helps also.
So what is problem here, how to fix? Or we doing something wrong here?
Need to add another MouseArea into PopupMenu which blocks all mouse events and is disabled by default and enable it only if popup is visible (optional):
enabled: popupMenu.visible
MainAppWindow {
// Some zoomable map item
Map {
id: map
anchors.fill: parent
}
PopupMenu { // Simple Rectangle item
id: popupMenu
anchors.top: parent.top
width: 200
height: parent.height / 2
z: parent.z + 1
MouseArea {
id: mapMouseArea
anchors.fill: parent
enabled: popupMenu.visible
preventStealing:true
hoverEnabled: true
onWheel: { wheel.accepted = true; }
onPressed: { mouse.accepted = true; }
onReleased: { mouse.accepted = true; }
}
ListView {
anchors.fill: parent
clip: true
...
delegate: Item {
...
MouseArea {
anchors.fill: parent
onClick: {
someHandler()
}
}
}
}
}
}
Note: however this solution does not work if ListView (or any other control) is a Map descendant item: item dragging causes map panning. To make it work need to make it at least sibling.

On button click, increase displayed number qt qml

I'm trying to get a displayed number to change when a button is clicked. How would I do that?
Here is my QML code
Button {
id:button
x:232
y:250
width:18
height:18
// Makes button have a transparent background
palette {
button: "transparent"
}
Image {
anchors.fill: Button
source:"Images/image.png"
}
// Moves rectangle down, on button click
onClicked: rectangle.y-=10
}
Text{
text: qsTr("12.0")
}
I want the number 12 to increase each time the button is clicked
You have to declare a property of type int, visible for both Text and Button items.
So an example code can be:
import QtQuick 2.0
import QtQuick.Controls 2.0
Window {
id: rootWindow
visible: true
width: 300; height: 300
property int displayValue: 12
Text {
id: displayTextId
anchors.left: addOneButtonId.right
text: displayValue.toString() //more clear if you explicit the parent rootWindow.displayValue.toString()
}
Button {
id: addOneButtonId
text: "Add 1"
onClicked: {
rootWindow.displayValue += 1
}
}
}
Alternatively, the property can be declared local to the Text element (so defined inside it), but pay attention, because a property is visible only for its child.
By the way, your code is full of error. If you want to create a button, that contains an image and a text, the best way is that you create a Rectangle object and define a Mouse area inside it.
The code structure should be like:
Rectangle {
id: root
property int number: 12
width: 100; height: 50
color: "transparent"
border.width: 1
border.color: "black"
Image { id: imageId }
Text { id: textId; text: root.number.toString() }
MouseArea {
anchors.fill: parent
onClicked: {
root.y += 10 // shift the y position down
root.number += 1
}
}
}

QML/QtQuick Binding delegate's property with ListView's currentIndex

Inside the delegate, I bind Image's source property to ListView's currentIndex which determines which image to load. This works great:
ListView {
id: answerListView
model: 5
currentIndex: -1
delegate: answerDelegate
}
Component {
id: answerDelegate
Item {
width: 100
height: 100
Image {
source: answerListView.currentIndex === index
? "selected.png" : "not_selected.png"
}
MouseArea {
anchors.fill: parent
onClicked: {
answerListView.currentIndex = index
}
}
Component.onCompleted: {
answerListView.currentIndex = 1; // doesn't work!!
}
}
}
Since currentIndex: -1, it will always show not_selected.png. To show selected.png, I change currentIndex in Component.onLoaded inside delegate.
I was expecting image to load selected.png since currentIndex was updated.
What is the correct way and what am I misunderstanding here?
Ok, new guess:
You want to have the posibility to select multiple Items. As currentIndex only stores one value, which is the value you assigned it last, you can use it to mark only one Item.
Therefore you need to find another way to store your selection. You might for example have a property in the delegate: property bool selected: false which you set to true upon selection.
The problem with this solution is, that it only works if all Items are instantiated at all times. As soon as one Item will be destroyed again, the information will be lost, and uppon the next creation, the selection/unselection is undone.
The better way would be to introduce a role in your model, that stores the selection outside of the non-persistant delegates for you:
ListView {
id: answerListView
model: lm
delegate: answerDelegate
width: 100
height: 220
}
ListModel {
id: lm
ListElement { selected: false }
ListElement { selected: false }
ListElement { selected: false }
ListElement { selected: false }
ListElement { selected: false }
}
Component {
id: answerDelegate
Item {
width: 100
height: 100
Image {
anchors.fill: parent
source: model.selected ? "selected.png" : "notselected.png"
}
Text {
text: (model.selected ? 'selected ' : 'notselected ')
}
Component.onCompleted: {
model.selected = true // doesn't work!!
}
MouseArea {
anchors.fill: parent
onClicked: {
model.selected = !model.selected
}
}
}
}
Another option would probably be a ItemSelectionModel, but I don't know atm, how it works.
Otherwise your example works as expected:
The Item with index 1 is shown, and displays the Image selected.png. All other Items are not shown (for the ListView is to small) but if the would be shown, they would show notselected.png for the answerListView.currentIndex is not equal to their index.

Unable to access QML variable / id globally

I have QtQuick 1.0
I use the following code:
Rectangle {
Component {
id: appDelegate
MouseArea{
id:myMouseArea
hoverEnabled: true
onClicked:{
onClicked: load.source = page;
}
}
Loader {
id: load
}
}
GridView {
id: view
// I am unable to access myMouseArea here.
highlight: myMouseArea.containsMouse ? appHighlight : !appHighlight
delegate: appDelegate
}
}
It gives me the following error:
ReferenceError: Can't find variable: myMouseArea
/usr/lib/i386-linux-gnu/qt4/bin/qmlviewer exited with code 0
I don't know if the details I provided are sufficient, please let me know if theres anything else I am missing.
I am using this code as an example:
http://docs.knobbits.org/qt4/declarative-modelviews-gridview-qml-gridview-example-gridview-example-qml.html
You cannot access myMouseArea because it's created inside delegate context. You cannot access delegate other then currentItem. But you can freely access view inside the context of delegate, to set currentIndex to attached property index.
This is a corrected code:
Rectangle {
width: 360
height: 360
Component { // It must be a component, if we want use it as delegate
id: appDelegate
// its not possible to have more than one element inside component
Rectangle
{
// need to set size of item, anchors wont work here
// could use view.cellWidth and view.cellHeight to keep it DRY
width: 96
height: 66
color: "green" // color only to see the place of MouseArea
MouseArea {
id:myMouseArea
anchors.fill: parent // this setup the size to whole rectangle
// it this item have the size 0,0 it will simple do not work
hoverEnabled: true
onEntered: {
// we know the mouse is inside this region
// setting this value will show the highlight rectangle
view.currentIndex = index;
}
onClicked:{
onClicked: load.source = page;
}
}
Loader {
// this is not needed but it's wise to not keep zero size
anchors.fill: parent
id: load
}
}
}
GridView {
id: view
// the size of GridView must be set,
// as otherwise no delegate will not show
anchors.fill: parent
anchors.margins: 5
cellWidth: 100
cellHeight: 70
// Rectangle will act as a border.
// Size and position is set by GridView
// to the size and position of currentItem.
// This is no a item, this makes a Component
// as highlight property needs one.
// You can create a Component like appDelegate.
highlight : Rectangle {
border.width: 2
border.color: "blue"
}
// some ListModel to setup the page variable inside delegate context
model: ListModel {
ListElement { page: "test1.qml"; }
ListElement { page: "test2.qml"; }
ListElement { page: "test3.qml"; }
}
delegate: appDelegate
}
}

Resources