How to highlight image on mouse hoover QML - image

I'm new to QML and I am trying to highlight an image on mouse hoover. I have a row of movie images, like this:
Here is my code for image number 4 (tarzan):
Rectangle{
id:rect4
width: parent.width/5-row.spacing/5
height:parent.height
color:'transparent'
Image{
id: tarzan
fillMode: Image.PreserveAspectFit
anchors.fill: parent
source:'qrc:tarzan.jpg'
MouseArea{
id:area
width:parent.width
height: parent.height
hoverEnabled: true
anchors.fill:parent
onClicked:tarzan.forceActiveFocus()
}
I tried different ways, but nothing happens. Any ideas? Help would be appreciated.

There are 2 ways to do this if you are using the qt quick version 2.15
import QtQuick 2.15
you can use the HoverHandler object something like this
Image{
id: tarzan
fillMode: Image.PreserveAspectFit
anchors.fill: parent
source:'qrc:tarzan.jpg'
HoverHandler{
onHoveredChanged: {
if(hovered){
tarzan.scale = 1.2
}
else{
tarzan.scale = 1
}
}
}
if you are using qtquick anything below 2.15 then your mousearea object should look something like this
Then it would be something like this the mouse area code
MouseArea{
id:area
width:parent.width
height: parent.height
hoverEnabled: true
anchors.fill:parent
onContainsMouseChanged: {
if(containsMouse){
tarzan.scale = 1.2
}
else{
tarzan.scale = 1
}
}
onClicked:tarzan.forceActiveFocus()
}

Related

Qml OpacityMask reduces image quality

I have a Rectangle that contains an Image.
I'm trying to create a rounded image with a black border.
I've tried using an OpacityMask, but when I do, it reduces the image quality.
Also there is a very small amount of white space in some places between the border and the image.
I've provided the code below. The commented out lines are things I've tried to no avail. I've also tried making the Rectangle and Image siblings contained within an Item with a separate sibling OpacityMask but get the same result.
Does anyone know a better way of doing this.
Also does anyone know a better way of creating the border - at the moment I'm stopping the image covering the border by using
anchors.margins: imageRect.border.width
Rectangle {
id: imageRect
property int spacer: 10
property int spacedWidth: imageDel.width - spacer
anchors.horizontalCenter: parent.horizontalCenter
width: spacedWidth
height: spacedWidth / imageListModel.getImageWToHRatio()
border.color: "black"
border.width: 2
radius: imageRadius
//clip: true
Image {
id: image
source: "image://lmImageProvider/" + rowIndex + "_" + index
//sourceSize: Qt.size(parent.width, parent.height)
anchors.fill: parent
anchors.margins: imageRect.border.width
cache: false
//visible: false
//fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.smooth: true
//layer.textureSize: "600x900"
layer.effect: OpacityMask {
maskSource: imageRect
// cached: true
}
//mipmap: true
property bool reload: reloadImageRole
onReloadChanged: {
source = ""
source = "image://lmImageProvider/" + rowIndex + "_" + index
}
MouseArea {
anchors.fill: parent
onClicked: {
imageListModel.toggleSelected(rowIndex + "_" + index)
}
}
}
}
Still not sure why the above code doesn't work.
Also not sure why my original attempt at "making the Rectangle and Image siblings contained within an Item with a separate sibling OpacityMask" (which was based on another answer in Stack Overflow), didn't work.
But upon much further investigation, I found another answer which was a slight variation on the "making the Rectangle and Image siblings contained within an Item with a separate sibling OpacityMask" which did work. Updated code is below:
Rectangle {
id: imageRect
property int spacer: 10
property int spacedWidth: imageDel.width - spacer
anchors.horizontalCenter: parent.horizontalCenter
width: spacedWidth
height: spacedWidth / imageListModel.getImageWToHRatio()
border.color: "black"
border.width: indImageBorderWidth
radius: indImageRadius
Image {
id: image
source: "image://lmImageProvider/" + rowIndex + "_" + index
anchors.fill: parent
anchors.margins: imageRect.border.width - 2
cache: false
visible: false
property bool reload: reloadImageRole
onReloadChanged: {
source = ""
source = "image://lmImageProvider/" + rowIndex + "_" + index
}
}
Rectangle{
id: maskRect
anchors.fill: image
radius: indImageRadius - 3
visible: false
z: image.z + 1
}
OpacityMask {
anchors.fill: image
source: image
maskSource: maskRect
}
MouseArea {
anchors.fill: parent
onClicked: {
//imageListModel.toggleSelected(rowIndex + "_" + index)
console.log("Image Clicked: " + rowIndex + "_" + index)
}
}
}

Image atlas in QML

I have an image like this one:
http://www.imagemagick.org/Usage/basics/result.gif
(it contains two rows of individual data: three square images in the upper row, and below another square and two 'empty' squares)
I want to use it inside a repeater, so that I get four image buttons, each with one of the subimages.
Is there a "texture-atlas" modules in QML?
I only found http://doc.qt.io/qt-5/qml-qtquick-sprite.html and I hope there is something that is better for my use-case.
As I said in comment I would do that using QQuickImageProvider since that's the fastest and the least memory intensive way. But QML is very flexible and you can do with it whatever you want. As for your question you can do as following:
Tile.qml
import QtQuick 2.9
Item {
id: container
property alias source: img.source
property int cellWidth: 1
property int cellHeight: 1
property int slideIndex: 0
clip: true
Image {
id: img
property int cols: img.paintedWidth / container.cellWidth
property int rows: img.paintedHeight / container.cellHeight
x: -container.cellWidth * Math.floor(container.slideIndex % cols)
y: -container.cellHeight * Math.floor(container.slideIndex / cols)
}
}
and usage:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: window
title: "Test"
visible: true
width: 600
height: 400
Row {
spacing: 10
anchors.centerIn: parent
Repeater {
model: 4
Tile {
width: 32
height: 32
cellWidth: 32
cellHeight: 32
slideIndex: index
source: "http://www.imagemagick.org/Usage/basics/result.gif"
}
}
}
}
The idea is to wrap the entire image into a container and clip it appropriately. Here I use index-based access to a slide, you can do that as you want.

MacOS dock-like component in QML

Using QtQuick, I have a row of 5 images in a repeater. I'd like to implement an animation on hover that's similar to the MacOS dock animation. Here's a picture for reference:
To further break it down, here's what I'm trying to accomplish. These images, on hover, should act as follows:
Hovered images expand
Neighboring images expand, but slightly less
Images don't overlap on expansion
Here is the code I have so far
Row {
spacing: 2
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.horizontalCenter: parent.horizontalCenter
Repeater {
id: iconRepeater
model: iconColors()
Image {
source: "icons/" + modelData + ".png"
scale: mouseArea.containsMouse ? 1.5 : 1.0
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: endTimer()
}
Behavior on scale {
PropertyAnimation {
duration: 75
}
}
}
}
}
This expands the image you hover over, but I cannot seem to also effect the neighbors. Any advice is appreciated!
I'd suggest a little more robust solution, where you have control over the zoom factor and the spread and decay of influence:
Column {
Slider {
id: foff
from: 1
to: 5
stepSize: 1
value: 2
snapMode: Slider.SnapAlways
}
Slider {
id: sf
from: 0.5
to: 2.5
stepSize: 0.5
value: 0.5
snapMode: Slider.SnapAlways
}
Slider {
id: dmp
from: 1
to: 5
stepSize: 1
value: 1
snapMode: Slider.SnapAlways
}
}
Row {
id: row
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.horizontalCenter: parent.horizontalCenter
property int falloff: foff.value // how many adjacent elements are affected
property int current: -1
property real scaleFactor: sf.value // that's how much extra it scales
property real damp: dmp.value // decay of influence
Repeater {
id: iconRepeater
model: 10
Rectangle {
width: 50 * pseudoScale
height: width
anchors.bottom: parent.bottom
color: "red"
border.color: "black"
property real pseudoScale: {
if (row.current == -1) return 1
else {
var diff = Math.abs(index - row.current)
diff = Math.max(0, row.falloff - diff)
var damp = row.falloff - Math.max(1, diff)
var sc = row.scaleFactor
if (damp) sc /= damp * row.damp
diff = diff / row.falloff * sc + 1
return diff
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: row.current = containsMouse ? index : -1
}
Behavior on pseudoScale {
PropertyAnimation {
duration: 150
}
}
}
}
}
It could be something along the lines of this:
Row {
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
Repeater {
id: rep
model: ['red', 'yellow', 'pink', 'green', 'teal', 'orchid', 'blue', 'orange']
property int currentIndex: -10
delegate: Rectangle {
anchors.bottom: parent.bottom
// Calculate the width depending on the currently hovered element
width: (rep.currentIndex === index ? 100 : ((rep.currentIndex - index) === 1 || (rep.currentIndex - index) === -1 ? 80 : 50))
height: width
radius: width / 2
color: modelData
MouseArea {
anchors.fill: parent
hoverEnabled: true
// onEntered/Exited did not react. This will work.
onContainsMouseChanged: {
if (containsMouse) rep.currentIndex = index
else rep.currentIndex = -10 // -10 is safe
}
}
// Makes the movement smooth
Behavior on width {
NumberAnimation {}
}
}
}
}
I tried to put in the necessary explainations as comment in the code.
The only thing that would need some tweeking is, that the dots will be initially shifted when the first resizing happens. Putting it on a flickable and some manual labour for the right position handeling could deal with that. Basically you need to shift the flickable by half the width change (in my case ~ 55 or so) to the left, when the mouse enters, and to the right when it leaves again.
You could also do so with a ListView, most likely, but due to the ever changing estimated size of the background, it might be more challanging to get the positioning right.

Particles with different images. [qml]

I am using particle systems. My particles come out from the center but I want different images to come out.
The file path of these images are stored in an array. I made a function to go through that arrangement and return what is in each position.
What returns is the path of each image to be sent to the source of the ImageParticle.
The problem is that if you scroll through the entire array but only return the path of the last image and logically I get a single image instead of the twenty that are stored in the array.
Someone could help me?
Help and suggestions are well accepted.
Here is my code:
import QtQuick 2.0
import QtQuick.Particles 2.0
Rectangle {
id: bg
width: 1920 //360
height: 1080 //360
color: "black"
ParticleSystem {
id: particleSys
}
Emitter{
id: particles
anchors.centerIn: parent
height: 1; width: 1
system: particleSys
emitRate: 30
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 5
endSize: 200
velocity: TargetDirection{
targetX: 100; targetY: 100
targetVariation: 360
magnitude: 250
}
}
property var picturesList: [
"images/Image1.png", "images/Image2.png", "images/Image3.png", "images/Image4.png", "images/Image5.png", "images/Image6.png", "images/Image7.png", "images/Image8.png", "images/Image9.png", "images/Image10.png",
"images/Image11.png", "images/Image12.png", "images/Image13.png", "images/Image14.png", "images/Image15.png", "images/Image16.png", "images/Image17.png", "images/Image18.png", "images/Image19.png", "images/Image20.png"
]
function getImage(arr){
var flag = "";
for(var i = 0; i < arr.length ; i++){
flag = arr[i];
console.log("Image: " + arr[i] + " flag: " + flag ) //To check if array is traversing.
}
return flag;
}
ImageParticle{
property var link: getImage(picturesList)
source: link
system: particleSys
}
// To check which image is returned.
MouseArea {
anchors.fill: parent
onClicked: {
console.log(getImage(picturesList))
}
}
}
I am the person who asked the previous question and here I bring the answer.
I know very well that there can be several ways that solve the problem, if you know another way I invite you to share it.
Suggestions about the response are welcome.
Here I share the code:
import QtQuick 2.0
import QtQuick.Particles 2.0
Rectangle {
id: bg
width: 1920
height: 1080
color: "black"
ParticleSystem {
id: particleSys
}
Emitter{
id: particles
anchors.centerIn: parent
height: 1; width: 1
system: particleSys
emitRate: 30
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 5
endSize: 200
velocity: TargetDirection{ //4
targetX: 100; targetY: 100
targetVariation: 360
magnitude: 250
}
}
property var picturesList: [
"images/Image1.png", "images/Image2.png", "images/Image3.png", "images/Image4.png", "images/Image5.png", "images/Image6.png", "images/Image7.png", "images/Image8.png", "images/Image9.png", "images/Image10.png",
"images/Image11.png", "images/Image12.png", "images/Image13.png", "images/Image14.png", "images/Image15.png", "images/Image16.png", "images/Image17.png", "images/Image18.png", "images/Image19.png", "images/Image20.png"
]
ItemParticle {
id: particle
system: particleSys
delegate: itemDelegate
}
Component {
id: itemDelegate
Rectangle {
id: container
width: 26*Math.ceil(Math.random()*3); height: width
color: 'white'
Image {
anchors.fill: parent
anchors.margins: 3
source: 'images/Image'+Math.ceil(Math.random()*20)+'.png'
}
}
}
}
As you can see, all the images in the folder will be output.
I simply change the "ImageParticle" to "ItemParticle" and I add a "Component" as a delegate where the desired image will be.
So we would not use the array (omit it in the previous code) since now only the path of the image is concatenated and a random number (to select the image).
I hope you serve them, and if you have a better implementation, please let them know.

Qml Qt Quick Control 2: Font size difference between Text and ComboBox

Let's look at this very simple sample application, built with QT 5.9 on a Windows 10:
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: parent.right
anchors.rightMargin: 20
Text {
id: text
text: "This is a sample Text"
}
ComboBox {
model: [
"A",
"B",
"C"
]
}
Text {
text: "Another Text"
}
TextField {
anchors.left: parent.left
anchors.right: parent.right
text: "User Input"
}
}
}
If I run it without any further modifications from the QT Creator, I get a very weird relationship between the Font-Size of the Text and the ComboBox and TextField blocks. It looks like this:
The text is too small, and the ComboBoxes (and their Fonts) are HUGE.
If I change the main function to set the default font size explicitely to the system font size using this code (It's the same when I hardcode the setPointSizeF to 12, which is the supposed standard size on windows):
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
auto font = app.font();
QFontInfo fi(font.defaultFamily());
font.setPointSizeF(fi.pointSizeF());
app.setFont(font);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
It looks like this:
Now the "Relative Dimensions" are more balanced, but overall everything is just "too big". Additionally, if I'm opening the ComboBox, I get again very small text:
Did I miss to set some default here? How can I achieve a more balanced look that fit's better into the Operating Systems' native font sizes?
The combobox delegates use a different font to the application default.
Delegate font can be changed to match the rest of the application as follows:
ComboBox {
id: control
delegate: ItemDelegate {
width: control.width
text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
font.family: control.font.family
font.pointSize: control.font.pointSize
highlighted: control.highlightedIndex === index
hoverEnabled: control.hoverEnabled
}
}
Leave the font sizes as defaults and instead set the widths of your items. You could explicitly set the width of the ComboBox and TextField, or if you want to use the ColumnLayout to have consistent sizing of all the items, see example below,
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
anchors.left: parent.left
anchors.leftMargin: 20
width: text.width
Text {
id: text
text: "This is a sample Text"
}
ComboBox {
Layout.fillWidth: true
model: [
"A",
"B",
"C"
]
}
Text {
text: "Another Text"
}
TextField {
Layout.fillWidth: true
text: "User Input"
}
}
}
You can simply try setting: font.pointSize: 12 in both the combobox and text fields. This works for me on Qt 5.9 in Windows 10. I am still trying to figure how to change the font size inside the combobox drop down; will expand this answer when I know.

Resources