I have a QML GridView with a scrollbar and hover effect, when I move the curso to the page's bottom the hover make an automatic scrolling, I want to stop it. I tried to set the interactive property of Flickable to false "interactive: false" but it didn't work. How can I stop this behavior?
Obs: When I remove the hover effect the scroll behave in the expected way, just moving through the scrollbar.
GridView{
id: grid
anchors.margins: 20
anchors.fill: parent
cellHeight: 80
cellWidth: 80
model: MyModel{}
highlight: Rectangle {
color: "lightsteelblue"
height: parent.cellHeight
width: parent.cellWidth
z:2
opacity: 0.7
}
delegate: Column {
Rectangle {
color: myColor;
height: grid.cellHeight * 0.7
width: grid.cellWidth * 0.7
border.color: "white"
anchors.margins: 5
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
id: mouseRegion
anchors.fill: parent
hoverEnabled: true
onEntered: grid.currentIndex = model.index
}
}
Text {
text: name;
anchors.horizontalCenter: parent.horizontalCenter }
}
}
Here is the Link to a simple project that reproduces the behavior: https://drive.google.com/open?id=0B7WUSCDDdwtIbWVDWVFvMjM1djA
My workmate help me to figured out a solution to my problem. I was using currentIndex property to set the hover position in the gridview, as described on documentation this property will smoothly scroll the GridView in the way that the current item becomes visible if the highlightFollowsCurrentItemis set to true (default value) and will not scroll if highlightFollowsCurrentItem set to false.
However, after set highlightFollowsCurrentItem property to false, the automatic scroll stopped together with my hover effect, which is clearly unwanted. I couldn't figure out what was wrong and we came out with a different approach.
To make the hover work without the automatic scrolling provided by currentIndex behavior, we remove it from gridview and used onEntered and onExited to control hover behavior, changing the rectangle visibility (id:selectedItem) used to simulate the hover effect as showed below.
GridView{
id: grid
anchors.margins: 20
anchors.fill: parent
cellHeight: 80
cellWidth: 80
model: MyModel{}
delegate: Item{
height: grid.cellHeight * 0.9
width: grid.cellWidth * 0.7
Rectangle {
id: selectedItem
color: "lightsteelblue"
height: parent.height
width: parent.width
z:12
opacity: 0.7
visible: false
}
Rectangle {
id:rect
color: myColor;
height: parent.height-textName.height
width: parent.width
border.color: "white"
anchors.margins: 5
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
id: mouseRegion
anchors.fill: parent
hoverEnabled: true
onEntered: selectedItem.visible = true
onExited: selectedItem.visible = false
}
}
Text {
id: textName
text: name;
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
}
}
}
It allowed me to avoid automatic scroll and keep the hover effect work properly.
Related
I had created a video player in QML having zooming functionality. I want to add the Google Map like zooming functionality in it that is zoom from the center of the current visible frame. I can center the image using:
videoScrollControl1.flickableItem.contentX = (videoScrollControl1.flickableItem.contentWidth-imgVideo.width)/2
videoScrollControl1.flickableItem.contentY= (videoScrollControl1.flickableItem.contentHeight-imgVideo.height)/2
but the problem is that it always zoom to the center of the Image. I want to zoom from any point or from the center of current visible frame. my Code is as follows:
ScrollView {
id: videoScrollControl1
anchors.fill: parent
anchors.margins: 5
frameVisible: false
contentItem: Rectangle {
id: videoAreaMain1
width: 620
height: 470
color: "#000000"
Image {
id: imgVideo
width: parent.width
height: parent.height
anchors.left: parent.left
anchors.top: parent.top
fillMode: Image.PreserveAspectFit
MouseArea {
id: zooingWheeler
anchors.fill: parent
hoverEnabled: true
}
}
}
}
Thanks in advance.
I have to take 4 continues pictures using the webcamera in QML i can take only one picture after that
I get an error from the QML debugger which states "Camera not ready for capture" how do i get the camera to be in ready state after the first capture this is the code i have tried
even if i set the ready state to true: it does not seem to be working? is there an easy way to get my way around this?
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
width: parent.width
height: parent.height
ColumnLayout{
width: parent.width;height: parent.height
spacing: 15;
Camera{
id:cam
captureMode: Camera.CaptureStillImage
imageCapture {
onImageCaptured: {
ready:true
console.log(ready)
}
}
}
VideoOutput{
id:vid1
source: cam
height:parent.height
width: 800
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle{
id:rect1
width: 100
height: 30
Layout.fillWidth: true
Layout.alignment:bottom
color: "#365688"
Text {
id: text1
anchors.centerIn: parent
text:"capture"
font.pointSize: 10
}
MouseArea{
anchors.fill:parent
onClicked: {
console.log("clicked");
for(var i=0;i<=3;i++){
cam.start()
cam.imageCapture.captureToLocation("C:/Users/vinay/Documents")
console.log(cam.cameraStatus)
}
}
}
}
}
}
}
If I have the following:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property var myArray: [1, 2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: 5
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
ListView {
id: myListView
width: 300
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: myButton.bottom
anchors.topMargin: 5
anchors.bottom: parent.bottom
currentIndex: -1
//highlightFollowsCurrentItem: false
highlight: Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
//y: myListView.currentItem.y
anchors.horizontalCenter: parent.horizontalCenter
}
clip: true
model: myArray
delegate: Rectangle {
width: parent.width - 10
height: 25
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: myArray[index]
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: myListView.currentIndex = index
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
When clicking the Clear Selection button I receive the following:
qrc:/main.qml:67: TypeError: Cannot read property of null
qrc:/main.qml:64: TypeError: Cannot read property of null
How can I clear the selection without getting the error? It doesn't appear to crash the application but I have a list view that changes based on another list view selection and the error occurs several times, cluttering up the debug output in Qt Creator. I have noticed this in Qt 5.4 and 5.5
The documentation for ListView says:
An instance of the highlight component is created for each list. The geometry of the resulting component instance is managed by the list so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
So you don't need to try to manage the position of the highlight item yourself. If you want to position the highlight, create an intermediate parent item instead:
highlight: Item {
Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
anchors.horizontalCenter: parent.horizontalCenter
}
}
As for why it happens, it's likely because the highlight item is reparented, leaving it in a state where its parent property is null. You can test this out with the following code:
anchors.horizontalCenter: { print(parent); parent.horizontalCenter }
The problem in general is that if you have a foo, which is supposed to have a bar, then you reference it as foo.bar, however, if foo was not properly initialized, then it cannot have a bar, since it does not exist (yet). In your case it seems that parent is not properly initialized, so it does not have a width and horizontalCenter (in the delegate, maybe), respectively. The solution is to initialize properly the object whose members are to be used, in our case, parent.
I had asked this question over on the Qt forum (https://forum.qt.io/topic/62328/clearing-a-qml-listview-selection) as well, but stack was quicker with a response. Checking the parent value works:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property int myMargin: 5
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: myMargin
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
Rectangle {
width: 300
anchors.top: myButton.bottom
anchors.topMargin: myMargin
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
ListView {
id: myListView
anchors.fill: parent
currentIndex: -1
spacing: 3
highlightMoveDuration: 25
highlight: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "pink"
radius: 3
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
}
clip: true
model: ListModel {
id: myArray
Component.onCompleted: {
for (var i = 1; i < 46; i++)
append({number: i})
}
}
delegate: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
Text {
text: number
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = index
}
}
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
I am trying to create a scroll view around a ColumnLayout, unfortunately my current code doesn't work. I know about ListView, but in my case I need to create scrollable Layout, because it will contain heterogeneous elements.
ApplicationWindow {
id: mainwindow
title: qsTr("Hello World")
width: 300
height: 300
visible: true
ScrollView {
anchors.fill: parent
ColumnLayout {
width: mainwindow.width
Image {
anchors.bottomMargin: 10
source: "img/button.jpg"
width: parent.width
height: 400
}
Image {
source: "img/button.jpg"
width: parent.width
height: 500
}
}
}
}
This renders to this (which is clearly not what I want):
There are two problems:
Images are not stretched across the entire window width, parent.width is ignored. I want images to have exact same width as ScrollView (no horizontal scroll)
Image height property is ignored
What am I doing wrong?
I would go with a plain column and access the desired width property directly by id. As I understand these container elements are measuring their size depending on their content, that might be the reason why setting the ColumnLayouts width has no effect.
This works for me:
ScrollView
{
anchors.fill: parent
Column {
Repeater {
model: 4;
delegate: Item {
width: root.width;
height: image.sourceSize.height;
Image {
id: image;
anchors.centerIn: parent;
width: parent.width;
fillMode: Image.Stretch;
source: "img" + (index+1) + ".png"
}
}
}
}
}
In my case root is just the parent's id. Hope this helps!
Same problem on my side. This worked for me :
ScrollView {
width: parent.width
height : parent.height
contentWidth: column.width // The important part
contentHeight: column.height // Same
clip : true // Prevent drawing column outside the scrollview borders
Column {
id: column
width: parent.width
// Your items here
}
}
In OpenGL terms, what I want to do is modify the projection matrix of a Qt GUI.
Pretend the window is 480x640. It is displayed as normal, and rendered to a texture.
I then take that texture, and stretch it across the entire screen.
Does Qt have something like that? I don't want the GUI looking fine and having appropriately-sized text on a 480x640 tablet, but then it gets loaded up on a 1536x2048 tablet and you need a magnifying glass for the text.
I've written my own GUI in OpenGL before, calculating a vid.width/BASEWIDTH, vid.height/BASEHEIGHT ratio and multiplying the modelview matrix of elements to ensure that a GUI always fills a screen and stays the same size -- obviously this only works perfectly providing the aspect ratio is the same, but I digress.
I messed with layouts in Qt Quick for awhile, and it offers some nice anchoring options, but nothing for stuff like scaling up the text if the parent window is larger. Or am I missing something here?
An OpenGL GUI I wrote had a few options for control position coordinates:
Origin for transforms (Top, Center, Bottom, Left, Center, Right)
PosIsPercentage (specified whether the position coordinates were to be interpreted as a percentage of screen width/height)
This allowed you to set the position as a distance from any edge of the screen, or you could set PosIsPercentage = true and set the X value to 75 to have the coordinate always be at 3/4ths of whatever the screen size was.
There was also a SizeIsPercentage value, so you could set a button to be 10% of the screen width.
I see some of these options in the Qt Quick designer, but they aren't behaving as I expect.
I know this is hard to explain, so here is an image to demonstrate:
http://www.spaddlewit.com/QtLayoutProblem.png
(not what I'm using Qt for, but a good example of the problem I'm having)
Scaling items based on the width and height of the screen works well enough, except when you move to a high DPI device. A better method is to scale items based on the height of the default font. The default font size of a Text item, for example, will always be legible on platforms supported by Qt, no matter the DPI. You can use the same principle to scale font sizes; multiply the default font size by some amount.
Below I've done a quick mock up of the screenshot you linked to:
import QtQuick 2.3
import QtQuick.Controls 1.2
ApplicationWindow {
id: window
contentItem.implicitWidth: 640
contentItem.implicitHeight: 480
contentItem.minimumWidth: 640
contentItem.minimumHeight: 480
contentItem.maximumWidth: 1024
contentItem.maximumHeight: 768
/*
With Qt 5.4, you can also use the new FontMetrics item,
which saves you the overhead of creating a Text item:
For example:
FontMetrics {
id: fontMetrics
}
Then:
font.pixelSize: fontMetrics.font.pixelSize * 4
anchors.margins: fontMetrics.implicitHeight * 2
*/
Text {
id: defaultText
}
Image {
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
}
Item {
id: container
anchors.fill: parent
anchors.margins: defaultText.implicitHeight * 2
Column {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: container.anchors.margins
Text {
id: yourGameText
text: "Your Game!"
font.pixelSize: defaultText.font.pixelSize * 4
wrapMode: Text.Wrap
}
ListView {
interactive: false
anchors.right: parent.right
width: yourGameText.width
height: container.height * 0.3
model: ["Play Game!", "Options", "Exit"]
delegate: Button {
text: modelData
width: ListView.view.width
}
}
}
Row {
anchors.left: parent.left
anchors.bottom: parent.bottom
spacing: container.anchors.margins
Image {
source: "http://www.facebookbrand.com/img/assets/asset.f.logo.lg.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://g.twimg.com/Twitter_logo_white.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://www.youtube.com/yt/brand/media/image/YouTube-logo-full_color.png"
width: defaultText.implicitHeight * 3
height: width
}
}
}
}
Window Size
The first thing I did was set the default, minimum and maximum size of the window.
Scaling
Next, I created an empty Text item which items and text sizes will be based off. It might seem hackish, and it is a bit, but it also works really well. As mentioned in the comment, in Qt 5.4 there will be a FontMetrics type which you can use instead of creating a Text item that will never actually be shown.
Another alternative is to use Screen's pixelDensity property.
Margins
You said you wanted to:
set the position as a distance from any edge of the screen
I did that by creating an Item that fills the window, and then setting the margins from the edges of the window as some factor of the default font's implicit height. This ensures that the content within the item will be the same physical distance (e.g., in millimetres) from the edge of the window regardless of the DPI of the device you're viewing it on. If you'd rather the distance be larger if the window is larger, you can do this instead:
anchors.margins: window.width * 0.1
Font Sizes
Take a look at the Text item within the Column. If you want to ensure the text is also the same physical size on the screen, you can set font.pixelSize to be the default font's size multiplied by some amount. Again, if you'd rather base it off the size of the screen rather than the DPI, you can do this instead:
font.pixelSize: window.height * 0.05
More Information
The Scalability documentation also gives a nice overview on this topic.
Below is a screenshot of the application running:
The following works, but it's annoying -- you have to create a scaleWidth and scaleHeight function and wrap any constant coordinates in them.
Font sizes scale along the shortest edge of the screen -- this application is a Portrait-only orientation, so it uses scaleWidth(pointSize) for font sizes.
Would be nice to find a solution that's compatible with the QML designer.. is there any way to automatically insert this calculation, maybe afterwards in C++ code at runtime?
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
ApplicationWindow {
id:window
visible: true
width: 480
height: 640
function scaleWidth(w)
{
return w * (width / 480.0)
}
function scaleHeight(h)
{
return h * (height / 640.0)
}
Text {
id: defaultText
}
Image {
id: image1
x: 0
y: 0
width: window.width
height: window.height
fillMode: Image.Stretch
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
Label {
id: lblTitle
x: 0
y: scaleHeight(8)
text: qsTr("Welcome to the App")
anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: scaleWidth(36)
horizontalAlignment: Text.AlignHCenter
}
Label {
id: lblSubtitle
x: 0
text: qsTr("Login to Continue")
font.pointSize: scaleWidth(24)
anchors.top: lblTitle.bottom
anchors.topMargin: scaleHeight(8)
anchors.horizontalCenter: lblTitle.horizontalCenter
}
Item {
id: itemCenterAlign
x: 0
y: 0
width: 0
height: 200
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
id: lblUsername
x: 0
text: qsTr("Username:")
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.bold: true
font.pointSize: scaleWidth(24)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
}
TextField {
id: txtUsername
width: scaleWidth(224)
height: scaleHeight(43)
anchors.left: itemCenterAlign.right
anchors.leftMargin: scaleWidth(8)
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.pointSize: scaleWidth(24)
placeholderText: qsTr("Username")
}
Label {
id: lblPIN
x: 0
y: scaleWidth(-8)
text: qsTr("PIN:")
font.bold: true
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(12)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
anchors.top: lblUsername.bottom
}
TextField {
id: txtPIN
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(43)
placeholderText: qsTr("PIN")
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(8)
anchors.leftMargin: scaleWidth(8)
anchors.left: itemCenterAlign.right
anchors.top: txtUsername.bottom
}
Row {
id: row1
x: 0
y: scaleHeight(277)
width: scaleWidth(464)
height: scaleHeight(115)
spacing: scaleWidth(8)
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: cmdQuit
text: qsTr("Quit")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdGPSOnly
text: qsTr("GPS Only")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdLogin
text: qsTr("Login")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
}
Button {
id: cmdAbout
width: cmdQuit.width
height: scaleHeight(44)
text: qsTr("About")
anchors.top: row1.bottom
anchors.topMargin: scaleHeight(8)
anchors.left: row1.left
anchors.leftMargin: 0
}
Label {
id: lblVersion
y: 619
text: qsTr("v3.0.0.0")
font.pointSize: scaleWidth(16)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.left: parent.left
anchors.leftMargin: scaleWidth(8)
}
Label {
id: lblBooks
x: 0
y: lvBooks.y
text: qsTr("Books Loaded:")
horizontalAlignment: Text.AlignRight
font.pointSize: scaleWidth(24)
anchors.right: lvBooks.left
anchors.rightMargin: scaleWidth(8)
}
Rectangle
{
x: lvBooks.x
y: lvBooks.y
width: lvBooks.width
height: lvBooks.height
color: "white"
border.color: "black"
}
ListView {
id: lvBooks
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(160)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.right: parent.right
anchors.rightMargin: scaleWidth(8)
model: ListModel {
ListElement {
name: "Book1"
}
ListElement {
name: "Book2"
}
}
delegate: Item {
x: 5
width: scaleWidth(80)
height: scaleHeight(40)
Row {
Text {
text: name
font.bold: true
font.pointSize: scaleWidth(24)
anchors.verticalCenter: parent.verticalCenter
}
spacing: 0
}
}
}
}
}