How to set a red outline border while using BorderImage - image

I am using BorderImage to display images on a GridView.
Following is sort of what I am doing:
BorderImage {
source: some_image
asynchronous: true
cache: false
}
I want to set a red outline border to my image. How can I do that ?
I looked at the Border.left, Border.right properties but they just stretch the image.

You add a Rectangle to your (Border)Image
BorderImage {
source: some_image
Rectangle {
anchors.fill: parent
anchors.margins: -border.width
z: -1
border.width: 4
color: 'red'
}
}

Related

QML slow performance animating a lot of rectangles

I'm creating a "dotted paper" component for my QML app. Essentially this components consists of a dotted background that the user can zoom upon. To create this I used the following code:
DottedPaper.qml
import QtQuick 2.15
Rectangle{
id: page
property int spacing: 50
// this property changes the spacing between the dots
property real contentScale: 1.0
Repeater{
id: rowRepeater
model: 200
Repeater{
id: row
property int rowIndex: index
model: 200
Rectangle{
id: circle
color: "red"
width: 4; height: 4
x: index * spacing * page.contentScale + width/2;
y: rowIndex * spacing * page.contentScale+ height/2
radius: width/2
}
}
}
}
Then in my main file I have the following:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Flickable{
clip: true // doesn't improve anything
anchors.fill: parent
contentWidth: paper.width
contentHeight: paper.height
DottedPaper{
id: paper
width: 10000; height: 10000;
clip: true
}
}
// the slider changes the content scale of the dotted paper
Slider{
from: 1
to: 3
onValueChanged: paper.contentScale = value
}
}
The problem with this code is that it's slow. Upon checking the application does not render the content at 60fps, but I get around 45 - 50 fps on my desktop. I suspect the issues is that QML is reevaluating the contentScale property binding for each circle in the background even if the circle is not visible on the screen. What is the best way to prevent this?
It works a lot better if you change your Repeaters to be ListViews. That's because a ListView is smart enough to only create enough delegates as needed for the visible space. (At first I thought a GridView would work, but that doesn't give you enough control over rows/columns.)
Rectangle{
id: page
property int cellWidth: 50 * contentScale
property int dotWidth: 4
// this property changes the spacing between the dots
property real contentScale: 1.0
ListView {
id: grid
model: 200
anchors.fill: parent
anchors.leftMargin: page.dotWidth / 2
anchors.topMargin: page.dotWidth / 2
spacing: page.cellWidth - page.dotWidth
delegate: ListView {
model: 200
width: window.width
height: page.dotWidth
orientation: ListView.Horizontal
spacing: page.cellWidth - page.dotWidth
property int rowIndex: index
delegate: Rectangle{
id: circle
color: "red"
width: page.dotWidth; height: page.dotWidth
radius: width/2
}
}
}
}

Change height of rows based on item depth in QML Treeview

I am trying to change the height of rows in my TreeView based on the item depth in the tree. The itemDelegate has access to the depth property (so I can change height of the item), but the row height can only be set from the rowDelegate, which can't see item depth.
As you can see from example I need to change row heights to match depth. How can the rowdelegate determine the item depth from the model?
Component {
id: delegateMenuItem
Column {
height: 100 // No effect
spacing: 20 // No effect
bottomPadding: 20 // No effect
Rectangle {
border {
color: "blue"
width: 2
}
color: "red"
height: itemText.height * 2
width: 300
Text {
id: itemText
text: qsTr(styleData.value)+"-"+height
color: "white"
font.pointSize: fontSize(styleData.depth)
}
}
}
}
Using TreeView from QQC1, I suggest that you try setting the implicitHeight for the itemDelegate and not setting any height for the rowDelegate. So try changing your snippet to:
itemDelegate: Rectangle {
id: delegateMenuItem
border { color: "blue"; width: 2 }
color: "red"
width: ...
implicitHeight: styleData.depth * ...
Text {
id: itemText
anchors.fill: parent
...
}
}
(In your current implementation delegateMenuItem does not have any implicitHeight. Meaning its height is probably 0. Also the ColumnLayout as you are using it is useless so I have removed it.)
I have not tried the above. However I have tried doing what you want to do with TreeView from Qt marketplace. It is designed to work with QQC2 and is based on TableView from QQC2 so you can use rowHeightProvider.

How to modify the shape of a control widget in FabricJS?

I'm using FabricJS in my web application. As I draw shapes, I notice that the control widget for all the objects are rectangular. Can the shape of a control widget be modified to fit the actual shape of the object? Say, a circle with a circular control widget.
I went through the Controls Customization demo. But there is no option to modify the shape of a control widget.
I need to modify the shape of the control widgets for the following purpose:
In my application whenever an object is clicked, its fill colour is toggled between black and white. In this case(refer the image below), because the circle has a rectangular control widget, clicking the pointed pixel selects the circle instead of the rectangle. I also hide the control widget from appearing by using hasControls property. So, the user will not know anything about the control widget. So, is the shape of the control widget editable?
I don't think there is an easy way to do that with fabric.js without writing a whole bunch of extra code. Fabric.js always draws a rectangle bounding box and uses it for selection controls. However, since you're planning on hiding the controls anyway, it sounds like you might be better off using perPixelTargetFind.
When true, object detection happens on per-pixel basis rather than on
per-bounding-box
Here's a quick demo:
const canvas = new fabric.Canvas('c', {
preserveObjectStacking: true,
perPixelTargetFind: true
})
const circle = new fabric.Circle({
radius: 50,
left: 50,
top: 50,
stroke:'green',
fill: 'white',
hasControls: false,
hasBorders: false
})
const rect = new fabric.Rect({
width: 200,
height: 150,
left: 50,
top: 25,
stroke: 'green',
fill: 'black',
hasControls: false,
hasBorders: false
})
canvas.on('mouse:down', (e) => {
const obj = e.target
if (obj) {
obj.set({
fill: obj.fill === 'white' ? 'black' : 'white'
})
canvas.requestRenderAll()
}
})
canvas.add(circle, rect)
circle.bringToFront()
canvas.requestRenderAll()
body {
background: ivory;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.min.js"></script>
<canvas id="c" width="300" height="200"></canvas>

QML/QtQuick2 Anchor Item to static location on a scaled image

What I am attempting to do is anchor an Item over a particular place over an Image. The Image needs to use Image.PreserveAspectFit for the fillMode. The problem I am having is that the height/width/paintedWidth/paintedHeight of the Image are for the entire image "canvas" (I'm not sure what it's actually called), not the drawn part of the image itself. So I can't anchor to the actual image.
See code below for an example I tried with anchors (red rectangle) and with a child rectangle and x,y coordinates (green rectangle).
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
height: 400
width: 400
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image.jpg"
Rectangle {
id: bottomRight
width: 40
height: 40
color: "green"
x: parent.width * 0.75
y: parent.height * 0.75
}
}
Rectangle {
id: topLeft
width: 40
height: 40
color: "red"
anchors.top: image.top
anchors.left: image.left
anchors.topMargin: image.height * 0.25
anchors.leftMargin: image.width * 0.25
}
}
When you change the size of the window the placement of the rectangles is not in the same place over the image. I'd post some screenshots but I don't have enough reputation yet!
I poked around through the widget tree using the debugger but I can't seem to find any properties that provide the information about the scaling that I could use to calculate placement of the rectangles.
Update
I used the following functions to calculate the margins since I will be using potentially lots of these overlays.
function horMargin(val)
{
return ((image.width - image.paintedWidth)/2 + image.paintedWidth * val)
}
function verMargin(val)
{
return ((image.height - image.paintedHeight)/2 + image.paintedHeight * val)
}
Did you try to use paintedWidth and paintedHeight? :)
This will give you a rectangle that fills the painted image:
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
height: 400
width: 400
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image.jpg"
}
Rectangle {
x: (image.width - image.paintedWidth) / 2
y: (image.height - image.paintedHeight) / 2
width: image.paintedWidth
height: image.paintedHeight
color: "transparent"
border.color: "darkorange"
border.width: 2
}
}
From there, you can work out how to apply the margins that you need.

Qt5 QML ListView contents zoom

I am trying to implement an image viewer (sort of):
model/view approach
using both c++ and qml
the images are just a ListView filled up with Image (delegate) items
Here is a piece of code:
property double zoomFactor: 1.5;
property double imgScale: 1;
CustomToolBar
{
id: toolBar
onZoomInSignal:
{
imgScale = imgScale*zoomFactor;
}
onZoomOutSignal:
{
imgScale = imgScale/zoomFactor;
}
onZoomFitSignal:
{
imgScale = 1;
}
}
Rectangle
{
id: bgRect
Layout.fillWidth: true
Layout.fillHeight: true
color: "Grey"
anchors.margins: 10
ScrollView
{
id: scrollView
anchors.fill: parent
ListView
{
id: listView
anchors.fill: parent
clip: true
spacing: 10
model: listItemModel
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
boundsBehavior: Flickable.StopAtBounds
delegate: Image
{
id: item_id
anchors.horizontalCenter: parent.horizontalCenter
source: item_img_path + "/" + Math.random()
scale: imgScale
}
}
}
}
The images are loaded correctly, I need to be able to zoom them.
In order to zoom I just modify the scale property of the Image delegate.
Images not scaled (scale = 1) CORRECT:
Images unzoomed (scale = 1/1.5) WRONG! images spacing (?) is being incremented:
Images zoomed (scale = 1.5) WRONG! images overlap:
As you can see, zoom minus increments the spacing (I'm quite not sure it is really the spacing) between the images, and zoom plus overlaps the images.
Furthermore, it would be nice to have the horizontal scrollbar for the ScrollView when zooming in, but I cannot achieve this.
Can anyone help me?
Thanks
EDIT:
Following the solution proposed by grillvott the images are zoomed in/out correctly, but the whole ListView is getting smaller/bigger with them:
The result should be instead something like this (gimp mode ON):
Any idea?
I don't think that scale will take any boundaries into consideration. You could encapsulate the image and use fillMode to make sure the image scales accordingly:
delegate: Item {
anchors.horizontalCenter: parent.horizontalCenter
width: img.sourceSize.width * imgScale
height: img.sourceSize.height * imgScale
Image {
id: img
anchors.fill: parent
source: item_img_path + "/" + Math.random()
fillMode: Image.Stretch
}
}

Resources