MouseArea in qml(onEntered, onExited, onReleased) - qml

I have one button. I want to change the states of button e.g:
Default image is black.
onEntered i want image as blue, onExited i want image as black(equal to default state), and onReleased i want image as blue(equal to onEntered state).
Note:
onRelease should be active inside the button and outside the button onRelease shouldn't work.
How this can be achieved?
Mouse area looks like this:
MouseArea
{
anchors.fill: firstImage(parent)
onEntered:
{
firstImage.source = "blue.img"
}
onExited:
{
firstImage.source = "black.img"
}
onReleased:
{
firstImage.source = "blue.img"
}
}
Problem i am facing is:
onRelease is active outside the button.
I want onRelease to be active when press is released inside the button.

You can leverage the fact that you can give every object in qml an extra custom property.
I came up with the following, which seems to be what you ask, however, I see a flaw, because when you are 'entered' and press, the button will go to entered state, so there is not difference in the 'released' state, and after leaving the MouseArea it will again go to 'exited' state.
Note, I did not copy the firstImage.source stuff, but you can easily tailor this example to your situation
import QtQuick.Controls 2.4
Button {
hoverEnabled: true
property bool touched : false
onHoveredChanged: touched = hovered
onReleased: touched = true
text: touched ? "touched" : "not touched"
}
The hoverEnabled needs to be set

Related

Qt QML Settings.hasTouchScreen returns false

I am trying to find out why flicking is not working with a TreeView example on my Raspberry Pi3 with touch screen.
Looking at the qml code of TreeView.qml, e.g.
https://github.com/RSATom/Qt/blob/master/qtquickcontrols/src/controls/TreeView.qml:
BasicTableView {
...
__mouseArea: MouseArea {
id: mouseArea
parent: __listView
width: __listView.width
height: __listView.height
z: -1
propagateComposedEvents: true
focus: true
// If there is not a touchscreen, keep the flickable from eating our mouse drags.
// If there is a touchscreen, flicking is possible, but selection can be done only by tapping, not by dragging.
preventStealing: !Settings.hasTouchScreen
...
}
}
By similarly looking at the qml code for BasicTableView.qml, it seems that behavior is controlled by Settings.hasTouchScreen.
According to:
https://code.woboq.org/qt5/qtquickcontrols/src/controls/Private/qquickcontrolsettings.cpp.html
it corresponds to the following method:
bool QQuickControlSettings1::hasTouchScreen() const
{
const auto devices = QTouchDevice::devices();
for (const QTouchDevice *dev : devices)
if (dev->type() == QTouchDevice::TouchScreen)
return true;
return false;
}
However, in my case, Settings.hasTouchScreen returns false; i.e. the touch screen (although working for the rest), is not
correctly detected by the QML environment, which probably explains why the flicking does not work.
According to https://doc.qt.io/qt-5/qtouchdevice.html, my touch device should have been registered somehow by the private QWindowSystemInterface::registerTouchDevice() method, but wasn't.
How can I get this to work?
Thanks!
It seems not to work correctly with tslib, but works by using the evdevtouch plugin which is enabled by adding the following command line arguments when launching the program:
-plugin evdevtouch:/dev/input/eventX
where eventX is the event assigned to the touch input.
With that, QTouchDevice::devices() is no longer empty, and the flicking of the TreeView works.

QtQuick: view allowing multiple selection at cell level

I'd like to implement a table view, using QtQuick, allowing multiple selection at cell level, emulating the behaviour of old style QTableView with QAbstractItemView::SelectItems and QAbstractItemView::ExtendedSelection flags enabled.
Which of the QtQuick components may I use?
TableViewonly allow to select rows by default, but you can override the selection behavior by customizing its cell delegate (itemDelegate).
First you'll have to disable the default selection behavior with :
selectionMode: SelectionMode.NoSelection
Then in the itemDelegate you can do something like that :
itemDelegate: Item {
property bool isSelected: false
// When user clicks on a cell, turn the isSelected flag on
MouseArea {
anchors.fill: parent
onClicked: isSelected = !isSelected
}
Text {
anchors.verticalCenter: parent.verticalCenter
// If this cell is selected, color the text in blue
color: isSelected ? "blue" : "black"
text: styleData.value
}
}
Be careful as the signals emitted by your TableView will not work as your cells are accepting mouse events. But of course you can implement them easily if you need them.

Trouble setting activeFocus to Item in a QML TabView

When the user changes the current tab in my TabView. I would like to set the activeFocus to the top level Item in the current tab, e.g. using forceActiveFocus. However for some weird reason the TabView is setting the activeFocus to the first Button it finds in the Tab, even if that Button has "focus: false" set.
As shown in the output below. When I use forceActiveFocus to set the focus to the top-level Item. First that Item gets focus, then it immediately loses focus and the Button gains focus instead. If there is no Button in the tab, then it works as expected. I need advice on a work-around for this problem. I would like to know if this is a Bug or whether I'm doing something wrong here?
Below is the program output when the user clicks on the 2nd tab.
qml: Item Focus gained: Tab2
qml: Button focus gained: Tab2
qml: Item Focus lost: Tab2
Code example follows (tested in Qt 5.4.2):
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
width: 640
height: 480
visible: true
TabView {
id: tabView
onCurrentIndexChanged: {
getTab(currentIndex).forceActiveFocus();
}
}
Component.onCompleted: {
var tab1 = tabView.addTab("tab1", tabComp);
tab1.active = true;
tab1.item.objectName = "Tab1";
var tab2 = tabView.addTab("tab2", tabComp);
tab2.active = true;
tab2.item.objectName = "Tab2";
}
Component {
id: tabComp
Item {
focus: true
onActiveFocusChanged: {
if(activeFocus)
console.log("Item Focus gained: " + objectName);
else
console.log("Item Focus lost: " + objectName);
}
Button {
focus: false
onActiveFocusChanged: {
if(activeFocus)
console.log("Button focus gained: " + parent.objectName);
else
console.log("Button focus lost: " + parent.objectName);
}
}
}
}
}
When a tab is clicked, TabView is setting the activeFocus to the first Item with activeFocusOnTab set. Button has this set to true by default. I solved this by setting activeFocusOnTab to false for the Button. This is a bit inconsistent with usual focus management in QML because I think normally the "focus" property is meant to take precedence over "activeFocusOnTab" for initial focus, but in this case it is ignored.

Zoom Flickable's content on wheel event

By default, Flickable scrolls on mouse wheel event: horizontally if Shift modifier is pressed, and vertically if no modifier is active. I'd like to override this behaviour to make it zoom in/out.
I tried to use MouseArea as a child of Flickable. Defining desired behaviour inside onWheel handler I get what I want, but it breaks flicking feature. Motion of two touch points is recognised as a wheel event on my Mac, what prevents Flickable to steel this event (MouseArea.preventSteeling is false by default). So I get somewhat mixed zooming feature that respects velocity/acceleration behaviour of Flickable.
Add an onWheel handler underneath your MouseArea:
MouseArea
{
onWheel: {
if (wheel.modifiers & Qt.ControlModifier){
if (wheel.angleDelta.y > 0)
{
zoomin()
}
else
{
zoomout()
}
}
else{
wheel.accepted=false
}
}
}

Saving the text to label from textfield blackberry

I want to display the recently entered text to the label. Here's the code for the qml:
Container {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Top
topPadding: 100
leftPadding: 50
rightPadding: leftPadding
/*TextArea {
id: taComment
preferredHeight: 270
editable: quoteBubble.editMode
enabled: enableSave
input.flags: TextInputFlag.SpellCheckOff
}*/
Label {
verticalAlignment: VerticalAlignment.Top
horizontalAlignment: HorizontalAlignment.Center
text: cppObj.desc
}
}
Container {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Bottom
leftPadding: 50
rightPadding: leftPadding
bottomPadding: 40
TextField {
id: tfComment
hintText: qsTr("add comment")
inputMode: TextFieldInputMode.Text
input {
submitKey: SubmitKey.Submit
onSubmitted: {
cppObj.onCommentSubmitClicked(tfComment.text, "");
}
}
}
}
}
So when the user enters a phrase from the first textfield, I want that phrase to display in the label below it. More like a text messaging. How do I do that? And after displaying the entered text from textfield to label I want to save the label's text, so when I enter new comment it'll be saved to other label
Add id to Label like following
Label {
id: label
....
}
Then on TextField on submit handler, you can get text from textField and set it to label, like below
onSubmitted: {
label.text = tfComment.text;
}
This is all related to Qt signals/slots and properties mechanism. Your items, TextField and Label, have properties. A specific property they share in common is text (note that the name is the same, but what really matters is the type - two properties with different names could be binded too). You can bind a property to another one:
Label {
text: myTextField.text
}
TextField {
id: myTextField
}
Now, whenever the TextField's text changes, the Label's one is updated accordingly. Note that the TextField's text property is updated only when it looses its focus or when it's submitted.
This is the simple way to do what you need. There's a more generic way to do it. Qt's property system is based on signals/slots mechanism. A signal is something which a QObject can send, to notify other QObject children. Slots are a specific kind of methods, which can be connected to signals. Then, if a signal A is connected to a slot B, whenever the signal A will be emitted, the slot B will be called.
The TextField object has an input child, which has an submitted signal. As you can guess, this signal is emitted whenever the user submits the TextField. Eh, that's every time you want to change your Label's text property! Let's do this in a slot:
Label {
id: myLabel
}
TextField {
id: myTextField
input {
onSubmitted: {
myLabel.text = myTextField.text;
}
}
}
Here, the onSubmitted function is a slot, which will be called automatically by Qt whenever the submit signal is emitted. You can of course do whatever you want in this slot: update properties, on this object or other ones, invoke a C++ method, … you're free.
You'll find a complete reference about signals and slots here, and about properties here (couldn't find this one on BlackBerry's documentation, but it's exactly what's used by BlackBerry).
Give your label an id (for example id : myLabel), then in your onSubmitted slot assign the text of the TextField to that label like this:
onSubmit :{
myLabel.text = tfComment.text
}
First you must set objectNames in the relevant places in the QML.
...
Label {
objectName: "label"
...
}
...
TextField {
objectName: "textField"
...
}
Of course I'm not suggesting that these are good names.
Once this is done, from where you use the QML in C++ i.e.:
QmlDocument *qml = QmlDocument::create("asset///qml/YourQml.qml");
Container *container = qml->createRootObject<bb::cascades::Container>();
You can then find the root object's (just assumed container here) children and manipulate them by name.
TextField *textField = container->findChild<TextField*>("textField");
Label *label = container->findChild<Label*>("label");
...
label->setText(textField->text()); //take the text from textField and display in label