Can I constraint QML Map zoomlevel to be integer? - qt

I'm using QtLocation Map to display a map on desktop and using mouse wheel to zoom the map. Now I want to constraint the zoomlevel property to be only integers so that when I rotate the mouse wheel the map goes directly to the next integer zoomlevel(from 1 to 2 to 3 to 4 etc). Can someone help?

This seems to be impossible if you want to use only qml, at least for me. Let's look why it is.
First thing I have tried is applying a simple rounding to zoomLevel property of the map object whenever onZoomLevelChanged is triggered.
Map {
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.91, 10.75) // Oslo
zoomLevel: 14
id: map
onZoomLevelChanged: {
map.zoomLevel = Math.round(zoomLevel)
console.log(map.zoomLevel)
}
}
However, since QML processes data so fast, you can't even change zoom level from its initial value, like whenever you move the mouse wheel whenever it changes from (such as) 14 to 14.0001 QML makes it again 14. So this way doesn't work.

Related

Why QDeclarativeGeoMap::visibleRegion is non-NOTIFYable in QtLocation Map?

I'm using QtLocation QML Map to display a big amount of items on a map. As with the number of items visible on the map the performance decreases, i would like to set visible only the items actually visible on the viewport. For this it would be handy to just calculate the visibility based on whether the item's coordinate is within the viewport, like:
visible: mapBase.visibleRegion.contains(model.item.coordinate)
But unfortunately the visibleRegion property is non-NOTIFYable, as stated in the documentation at http://doc.qt.io/qt-5/qml-qtlocation-map.html#visibleRegion-prop.
Is there any specific reason (like performance-issues) to not implement a notify signal for this property? Is there any way to workaround this, and set the visibility of a map item based on whether it's within the viewport?
I suppose the reason could be that it's expensive to calculate.
But visibleRegion changes when one of the following properties change: zoomLevel, center, bearing, tilt, fieldOfView. You could, for example, define your own "property var visRegion", and update it when reacting on those properties above by fetching visibleRegion and assigning it to visRegion.

Keep cursor shape while pressed as it moves outside its MouseArea

I am implementing narrow resize handles which give me annoying behavior. The cursor shape is as expected while the mouse is directly over the handle, but once dragging the handle is initiated, the cursor shape becomes inconsistent. There are two causes of this:
when the cursor moves fast and goes ahead of the handle until the handle "catches up" (or when "fluid qml" is too fluid) - this is particularly nasty as the cursor shape rapidly changes and blinks
when the cursor moves outside of the allowed degree of freedom for the handle
I looked up the doc but it doesn't seem to contain anything about locking the cursor until the press is released.
I did manage to find a hack to fix it - using a dummy overlay MouseArea with acceptedButtons: Qt.NoButton - this actually helps to fake cursor consistency, but comes with an issue of its own. Having that overlay mouse area doesn't allow the cursor to change to a resize shape when it is over the handle, since the handle is under the overlay mouse area it doesn't get to modify the cursor shape at all. So the resize shape kicks in only after the handle is clicked, which is far from ideal. Setting the overlay mouse area to enabled: false doesn't change that - it still keeps blocking cursor shape changes from underlying mouse areas. There is a workaround for that as well, for example setting the overlay mouse area size to 0x0, but it is kind of ugly.
Ideally, the cursor shape should persist until the mouse area is pressed, regardless of whether it is in or outside of its area - after all, the press is not released if you go outside of it, thus the mouse area is still in control and should persist its cursor shape. For example - the window resize handles remain resize shape even if it is moved to resize the window smaller than its minimal size, until the press is released.
To me it seems that there are flaws in the implementation of MouseArea - the cursor shape is not kept while pressed, and the cursor shape is changed even if the mouse area is disabled.
I didn't find a way to do this out-of-the-box, it is pretty easy to create a helper for this though. On the qml side you can e.g. have:
CursorChanger {
cursor: Qt.SizeHorCursor
active: dragArea.containsMouse || dragArea.drag.active
}
On the C++ side you'll need a helper class like this:
class CursorChanger : public QObject
{
Q_OBJECT
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(int cursor READ cursor WRITE setCursor NOTIFY cursorChanged)
// ...
}
In the implementation you can use QGuiApplication::setOverrideCursor and QGuiApplication::restoreOverrideCursor to actually set/reset the cursor. Don't forget to also reset in the CursorChanger destructor if active at that point. If you then register the type:
qmlRegisterType<CursorChanger>(uri, 1, 0, "CursorChanger");`
You can use this type from qml.
I think there are some use cases for the current behavior. For instance, the cursor could convey some relationship between the currently hovered object and the one where the mouse was pressed. Another example, a drag could have its speed intentionally limited, and when the user goes too fast there is a consequence that depends on the item behind.
dtech's demand is more common for sure, and I also would like to see that as an optional feature, but not as a change. The way it is now provides more versatile pieces for apps. I don't like polished components that can be used only exactly as the library writer imagined.
Another QML only solution for a persistent drag cursor is to have a MouseArea behind all itens to hold the persistent shape when needed:
Item
{
id: scene; width: 800; height: 600
MouseArea
{
id: mouse
anchors.fill: scene
}
Rectangle
{
id: draggable; width: 40; height: 30; color: "red"
MouseArea
{
anchors.fill: draggable
drag.target : draggable
//set and unset a persistent cursor
onPressed : mouse.cursorShape = Qt.DragMoveCursor;
onReleased: mouse.cursorShape = Qt.ArrowCursor; //QT default cursor
//let non default scene cursors prevail over the item's
cursorShape: mouse.cursorShape === Qt.ArrowCursor ?
Qt.OpenHandCursor : mouse.cursorShape;
}
}
}

Binding expression + animation causes object to disappear and reappear randomly

I have a visual tree of the following object:
Row {
spacing: 4
y: 1
U_Icon {
width: 48
height: 48
scale: (activeo === main.object ? 1.18 : 1) * (main.expand ? 1 : 0.75)
Behavior on scale { SpringAnimation { spring: 10; damping: 0.2; duration: 100 } }
color: activeo == object ? "white" : "#262626"
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: -10
Text {
text: object.type + "type"
font.pointSize: 10
font.family: sysfont
}
Text {
text: "name"
font.pointSize: 20
font.family: sysfont
font.italic: true
font.letterSpacing: -1
}
}
}
The scale of the icon depends on whether the current object is selected or expanded. Expanding causes the object to draw its children objects. However, on re-expanding after contracting, depending on the tree structure, children objects are missing their text, which mysteriously reappears when another object is selected or created. Selecting another object might cause one, several or all missing texts to appear, the same goes for creating another object. When the tree is expanded, the texts are there for an instant, after which they disappear.
I made a few observations:
if the binding for the scale is only either of the two expressions without the other, the problem does not manifest
if the animation is removed, the problem does not manifest
interfacing the icon scale as an alias property of the row in order to move the binding out of the component and to the place it is instantiated has no effect, the problem persist
breaking down the binding expression by adding dedicated activefactor and expandfactor property for each expression and reducing the scale binding to activefactor * expandfactor has no effect, the problem persists
refactoring the binding expression to a code block with a return statement (sometimes that helps when single liners fail) has no effect, the problem persists
Here is an illustration of what's going on:
1 - the tree builds OK
2 - the tree is collapsed
3 - the tree is expanded again, the text flashes for a moment and disappears
4 - clicking arbitrary object causes all text to reappear
Any ideas what's going on? Yet another bug or am I missing something? Why would a slightly more complex expression cause the column with the text to disappear? It is not a problem of the changing scale in particular, since both expressions change it and both work on their own.
Note that the text is still there, just not being rendered by the scene-graph, that is evident from the size of the light-grey rounded rectangle which is sized to match the row width. The scale of the icon itself is evaluated and displayed property, but for some reason causes the text to disappear.
EDIT: Another curious observation, if the text column is replaced by a common rectangle, the bug does not manifest. If the column is wrapped inside a rectangle the same width as the column, but only as high as the small text, this causes only the large text to go missing:
This adds more weight to my suspicion that this is a bug in the scene-graph, and wrapping it in a rectangle forces the renderer to update only that portion of the missing text. Note that the rectangle is not clipping the column. Furthermore, if the rectangle color is set to #00000000, that is fully transparent, the text is missing again, the scene graph disregards it, and thus there is nothing to force the update of the text part. As expected, wrapping in an Item is no help either, nor is using text directly, without the column. If the rectangle is extended further down, it cuts through the big text, as a result, only the upper half of the big text is visible. Even the tiniest amount of transparency in the rectangle causes the text to go missing, even if the rectangle is 99.99% opaque. Only a 100% opaque rectangle forces the visibility of the text.
I have tested it with latest Qt 5.7 on windows 7 x64 (stock x86 qt build + custom x64 opengl static) and linux x64 (using the mesa drivers).

Circular progress indicator widget in PyQt5 [duplicate]

Create Spin Progress bar in Qt, I want to show progress bar like the one which appears while loading. Please Find Image
My code goes like this
QProgressBar *pgbar = new QProgressBar();
pgbar->resize(500,25);
pgbar->setOrientation(Qt::Horizontal);
pgbar->setRange(0,99);
pgbar->setValue(10);
pgbar->show();
installOnDevice(destinationSavePath);
pgbar->hide();
here installOnDevice(destinationSavePath); takes time to process. Currently I am showing Processbar, I dont want to show processbar. Can't I replace with some progress which shows loading image (Rotating) or something similar to that
Have a look at the Twitter Mobile example application. In the file demos/declarative/twitter/qml/twitter/TwitterCore/Loading.qml there is an implementation in QML of the exact thing you want to achieve:
import QtQuick 1.0
Image {
id: loading
source: "images/loading.png"
NumberAnimation on rotation {
from: 0
to: 360
running: loading.visible == true
loops: Animation.Infinite
duration: 900
}
}
Update 1 (reflecting the newly posted code):
Employing QML just for a spinning load indicator in your otherwise Qt Widgets based application seems overkill to me. I would use a QMovie in conjunction with a QLabel to display an animated GIF image containing the spinner:
QMovie* spinnerMovie = new QMovie(":/spinner.gif");
QLabel *spinnerLabel = new QLabel(this);
spinnerLabel->setMovie(spinnerMovie);
spinnerMovie->start();
You should also have a look at the documentation for the Qt Resource System to learn how to bundle images with your application and how to load them.
In order to change the cursor wou have to use the setCursor function or the setOverrideCursor in order to apply it to the application. You can construct any cursor you want using a QPixmap as constructor argument.
In order to achieve an animation effect you will need a QTimer. At every timer event you have to change the cursor's pixmap in order give the feel of animation.
Try Qml Busy Indicator, implemented in pure C++:
http://qt-project.org/wiki/Busy-Indicator-for-QML

QML Minimum drag/flick distance for changing item

I have a ListView in QML using theese properties :
ListView {
id : list
boundsBehaviour: Flickable.StopAtBounds
snapMode: PathView.SnapOneItem
highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
...
}
My problem is the following :
I'm trying to determine exactly when the drag/flick will made the list move to the next/previous item or staying on the same one when releasing the touch.
Is there a property to modify or something useful to know which behaviour will happen ?
Thanks.
you are looking for startDragDistance property in QApplication class, the default value of startDragDistance is 10 pixels for Windows (it depends on OS)
In order to set drag distance to 50 pixels, you can use the following line
QApplication::setStartDragDistance(50);

Resources