I have a TextEdit inside a Scrollview inside a SplitView. I have a Q_INVOKABLE function that I call when a row in a TableView gets selected to jump to a desired line in the TextEdit, this works fine. However, I need to adjust the ScrollView focus so that it moves when the selection of the TextEdit moves.
Identical behavior to selecting a compiling error on an IDE.
//main.qml
ScrollView {
id: palGenTextScrollView
anchors.fill: parent
TextEdit {
id: mainTextEdit
text: fileio.palFileText
wrapMode: TextEdit.Wrap
selectByMouse: true
}
TableView {
id: errorsTableView
onClicked: {
mainTextEdit.select(palerrorviewmodel.goToLine(errorsTableView.currentRow),
palerrorviewmodel.goToLine(errorsTableView.currentRow))
mainTextEdit.forceActiveFocus()
//Call something to adjust ScrollView here
//palGenTextScrollView. ??
}
I omitted some irrelevant code.
You need to use palGenTextScrollView.flickableItem.contentY to set the position of your text. Here after is a small example working: you have a button for each line of the text, and clicking on it selects the line and centers the text on it. You can work on it for your own issue.
I couldn't manage to have your example working because the palerrorviewmodel element is missing.
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ScrollView {
id: palGenTextScrollView
width: 200
height: 100
TextEdit {
id: mainTextEdit
text: "I have a TextEdit\ninside a Scrollview\ninside a SplitView.\nI have a Q_INVOKABLE\nfunction that I call\nwhen a row in a TableView\ngets selected to jump\nto a desired line\nin the TextEdit,\nthis works fine.\nHowever, I need to adjust\nthe ScrollView focus\nso that it moves\nwhen the selection\nof the TextEdit moves.\nIdentical behavior\nto selecting a compiling\nerror on an IDE."
wrapMode: TextEdit.Wrap
selectByMouse: true
}
}
Row{
spacing: 5
anchors.top: palGenTextScrollView.bottom
anchors.topMargin: 20
Repeater{
model: mainTextEdit.lineCount
delegate: Rectangle{
width: 20
height: 20
color: "blue"
Text{
anchors.centerIn: parent
text: index
}
MouseArea{
anchors.fill: parent
onClicked: {
var lines = mainTextEdit.text.split("\n");
var count=0;
for (var i=0; i<index;i++){
count+=(lines[i].length+1);
}
mainTextEdit.select(count, count+lines[index].length);
mainTextEdit.forceActiveFocus()
var maxY = mainTextEdit.contentHeight-palGenTextScrollView.height
var lineHeight = mainTextEdit.contentHeight/mainTextEdit.lineCount
var centeredY=index*lineHeight-palGenTextScrollView.height/2
if (centeredY < 0){
palGenTextScrollView.flickableItem.contentY=0
}else if (centeredY<=maxY){
palGenTextScrollView.flickableItem.contentY=centeredY
}else{
palGenTextScrollView.flickableItem.contentY=maxY
}
}
}
}
}
}
}
Related
I created a nested rectangular block i.e. a rectangle inside a main rectangular block in QML. Now I have to hide the inner rectangular block on some operation and once the operation is finished make it visible again. I am trying the following:
Rectangle {
id: window
width: 450
height: 550
property bool isTopToolBarAreaVisible : true
Rectangle {
id: toolBarArea
width: 1
height: parent.height
color: toolBarColor
visible : isTopToolBarAreaVisible
ToolButton {
contentItem: Text {
text: "Save as"
}
onClicked: {
...
isTopToolBarAreaVisible = false // hide the inner rectangule
window.grabToImage(function(result) {
result.saveToFile(fileName);
}, Qt.size(window.width*2,window.height*2));
isTopToolBarAreaVisible = true // show the inner rectangle again
}
}
}
}
I created a boolean isTopToolBarArea to control the visibility but it does not work. Can anyone help.
This seems to work. I'm hiding the Rectangle containing the ToolButton when onClicked is triggered and show it again inside the callback assigned to grabToImage(callback, targetSize). Adding the RowLayout was just to make the ToolButton horizontally centered in the Rectangle.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle {
id: window
anchors.fill: parent
color: "green"
Rectangle {
id: toolBarArea
width: parent.width
height: 40
color: "red"
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Text { text: "Save as" }
onClicked: {
toolBarArea.visible = false
window.grabToImage(function(result) {
result.saveToFile("test.png")
toolBarArea.visible = true
}, Qt.size(window.width * 2, window.height * 2))
}
}
}
}
}
}
If you're just calling your delayGrab() function inside your onClicked handler, that still won't work. You're delaying the work but not allowing the UI thread to continue running while it's waiting. If your function takes a long time, a worker thread would be preferable. But for fairly short tasks, a timer will work. The timer should look something like this:
Rectangle {
...
Rectangle {
...
ToolButton {
onClicked: {
isTopToolBarAreaVisible = false // hide the inner rectangle
myTimer.start();
}
}
Timer {
id: myTimer
interval: 10 // Adjust this as needed
onTriggered: {
window.grabToImage(function(result) {
result.saveToFile(fileName);
}, Qt.size(window.width*2,window.height*2));
isTopToolBarAreaVisible = true // show the inner rectangle again
}
}
}
}
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.
I have a ListView which has dynamically added Items, and what I kinda want to know is how I could access items for example by index. Specifically, I want to have the color of the item rectangle change when I change the color using the Color Dialog. I guessed it should be maybe possible to first set a variable to the current item before calling the color dialog and then in the onAccepted method change the color of that item using the variable, but I don't know how to achieve anything of this in QML, because I am rather new to QML. Maybe you can offer even a cleaner way to change the color of the item's rectangle when the color dialog was closed (onAccepted). Thx for any help! :)
import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Controls.Styles 1.4
Rectangle {
id: listViewContainer
width: parent.width/10*9;
height: 50
Behavior on height {
NumberAnimation {
duration: 100;
}
}
gradient: Gradient {
GradientStop {position: 0.0; color: "white" }
GradientStop {position: 1.0; color: "silver" }
}
radius: 5
ColorDialog {
id: colorDialog
title: "Please choose a color"
onAccepted: {
console.log("You chose: " + colorDialog.color)
Qt.quit()
}
onRejected: {
console.log("Canceled")
Qt.quit()
}
}
Component {
id: playerDelegate
Item {
anchors.left: parent.left
anchors.right: parent.right
height: 50
Column {
Text { text: '<b>Name:</b> ' + name }
Row {
MouseArea {
width: 20
height: 20
onClicked: {
colorDialog.visible = true;
playerColor = colorDialog.color;
//open color dialog
}
Rectangle {
radius: 3
anchors.fill: parent
color: playerColor
}
}
}
}
}
}
ListView {
id: playerListView
anchors.fill: parent
model:
ListModel {
id: playerListViewModel;
ListElement {
name: "Bill Smith"
playerColor: "red"
}
}
delegate: playerDelegate
}
Button {
id: addPlayerButton
anchors.top: playerListView.bottom
anchors.left: playerListView.left
anchors.right: playerListView.right
style: ButtonStyle {
label: Text {
text: "Add new player"
horizontalAlignment: Text.Center
}
}
onClicked: {
root.addnewPlayer(playerListView); //dont worry about this method
playerListViewModel.append({name: "Billy", playerColor: "blue"});
listViewContainer.height += 50;
}
}
}
Here is a sure fire way to make a working colorDialog --
in playerDelegate
Component {
id: playerDelegate
Item {
anchors.left: parent.left
anchors.right: parent.right
height: 50
Column {
Text {
text: '<b>Name:</b> ' + name
}
/* Object to store value from color selector */
Item {
id: colorSelector
property color color: "#000000"
onColorChanged: { playerColor = color; }
}
/* box to display color */
Rectangle {
//Layout.fillWidth: true
height: 120
width: 120
anchors.left: button.right
//Layout.alignment: Qt.AlignHCenter
color: colorSelector.color
border.width: 1
border.color: "#000000"
}
/* button to open dialog -- can be mousearea or other clickable object */
Button {
id: button
text: "Browse..."
onClicked: {
colorDialog.color = colorSelector.color
colorDialog.open()
}
}
/* actual color dialog for this delegate */
ColorDialog {
id: colorDialog
modality: Qt.ApplicationModal
title: "Please choose a color"
onAccepted: colorSelector.color = currentColor
}
}
}
}
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
}
}
I have made an Item in QT QML which contains a MouseArea element.
Here is the code,
import QtQuick 1.0
Rectangle {
id: base
width: 240
height: 320
x:0; y:0
color: "#323138"
/////////////////////// MAIN FOCUSSCOPE //////////////////////
FocusScope {
id: mainfocus
height: base.height; width: base.width
focus: true
/////////////////////// MAIN GRID ///////////////////////////
GridView {
id: maingrid
width: base.width-10; height: base.height-titlebar.height-10
x: 5; y: titlebar.height+5;
cellHeight: maingrid.height/3; cellWidth: maingrid.width/3-1
Component {
id: myicon
Rectangle {
id: wrapper
height: maingrid.cellHeight-10; width: maingrid.cellWidth-10
radius: 8; smooth: true
color: GridView.isCurrentItem ? "#c0d0c0" : "transparent"
focus: true
MouseArea {
id: clickable
anchors.fill: wrapper
hoverEnabled: true
//onClicked: func()
}
Image {
id: iconpic
source: "./ui6.svg"
anchors.centerIn: wrapper
}
Text {
id: iconname
color: wrapper.GridView.isCurrentItem ? "black" : "#c8dbc8"
anchors.top: iconpic.bottom; anchors.horizontalCenter: iconpic.horizontalCenter
text: name
}
}
}
model: 4
delegate: myicon
focus: true
}
}
//////////////////////// TITLEBAR ///////////////////////
Rectangle {
id: titlebar
x:base.x
y:base.y
height: 25; width: base.width
color : "#356f47"
Text {
color: "#fdfdfd"
anchors.centerIn: titlebar
text: "title"
}
}
}
I want to make a grid of such Items so that it gives me a grid of custom made click-able Items that I created which I can use for different functions.
Using the GridView element, I was able to make such a grid which used number of my custom made Items as a template.
The problem is that when I click anyone of these Items it executes a single function since there was only one MouseArea element in my Item. I am able to detect a click on an Item, but not able to uniquely determine which Item was clicked. How do I achieve this ?
Of course, I might be doing it wrong, so other suggestions are also welcome.
Thanks
When the GridView item creates the instances they inherit the index variable. This identifies the unique item.
MouseArea {
id: clickable
anchors.fill: wrapper
hoverEnabled: true
onClicked: {
maingrid.currentIndex=index;
switch (index)
{
case 0:
//Function or method to call when clicked on first item
break;
case 1:
//Function or method to call when clicked on second item
break;
default:
//Function or method to call when clicked on another item
break;
}
}
}
I hope it helps you!