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
}
}
}
}
Related
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
}
}
}
}
}
}
}
I need to call a C++ class method with parameters from UI after animation of SwipeView ends.
main.ui
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
SwipeView {
id: swipeView
anchors.fill: parent
Page1 {
id: page1
}
Page2{
id: page2
}
}
XOR {
id: xor
onXorEnded: {
//swipeView.setCurrentIndex(0)
}
onQChanged: {
page2.bar.value = xor.getq()
}
}
}
Page1Form.ui.qml
Page1Form {
kpButton.onClicked: {
kpDialog.visible = true
}
xorButton.onClicked: {
swipeView.setCurrentIndex(1)
xor.crypt(file_path.text, key_path.text, out_path.text)
}
fpButton.onClicked:{
fpDialog.visible = true
}
FileDialog {
id: fpDialog
onAccepted: {
file_path.text = fpDialog.fileUrl
}
}
FileDialog {
id: kpDialog
onAccepted: {
key_path.text = kpDialog.fileUrl
}
}
}
It seems like in xorButton.onClicked xoring starting before animation of swipe view ends. How it works now: Imgur
As a workaround you can bind your action to index changing:
xorButton.onClicked: {
swipeView.setCurrentIndex(1)
}
SwipeView {
id: swipeView
onCurrentItemChanged: {
if(currentIndex == 1)
xor.crypt(file_path.text, key_path.text, out_path.text)
}
}
But anyway, that fires not at end of animation.
As another workaround you can use StackView. It has more properties to control the animation. Another advantage of this control is that user cannot swipe it when you don't expect it. In your case an user just can swipe that. One more advantage is that page doesn't take memory when you don't need it.
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
visible: true
width: 800
height: 800
StackView {
id: view
anchors.fill: parent
initialItem: page1
onBusyChanged: {
if(!busy && currentItem.objectName == "page2")
currentItem.run();
}
}
Component {
id: page1
Rectangle {
color: "green"
objectName: "page1"
Button {
anchors.centerIn: parent
text: "swipe me"
onClicked:
view.push(page2)
}
}
}
Component {
id: page2
Rectangle {
color: "yellow"
objectName: "page2"
function run() { sign.visible = true; }
Rectangle {
id: sign
anchors.centerIn: parent
width: 100
height: 100
radius: 50
color: "red"
visible: false
}
}
}
}
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 get my board to flash green when a button is clicked.
I have added the following color animation code to help create the flashing effect, so that the board can go from its original colors, to green, and back to it's original colors.
I have seen in some code examples where ColorAnimation can also be used like this ColorAnimation on color{...}. I tried using this to reference the rectangle color property but it complains about color being an invalid property, which is why i don't have it in the code below.
SequentialAnimation
{
running: true
loops: Animation.Infinite
ColorAnimation
{
to: "green"
duration: 500
}
ColorAnimation
{
to: "transparent"
duration: 500
}
}
The code fragment above has gone into the repeater code below. The code below handles displaying my board with the black and white colors I am starting off with.
Repeater
{
id: board
model: 64
Rectangle
{
color: getWhiteOrBlack(index)
opacity: 0.45
width: getSquareSize()
height: getSquareSize()
x: getX(index)
y: getY(index)
MouseArea
{
anchors.fill: parent
onClicked:
{
pawn.x = parent.x
pawn.y = parent.y
if (starting_position == false)
{
starting.x = parent.x
starting.y = parent.y
starting_position = true
starting_index = index
ending.visible = false
}
else
{
ending.visible = true
ending.x = parent.x
ending.y = parent.y
ending_index = index
Board.move(getRow(starting_index), getColumn(starting_index), getRow(ending_index), getColumn(ending_index))
starting_position = false
}
}
}
SequentialAnimation
{
running: true
loops: Animation.Infinite
ColorAnimation
{
to: "green"
duration: 500
}
ColorAnimation
{
to: "transparent"
duration: 500
}
}
}
}
However, whenever I click on the button that is supposed to trigger the green flash, it doesn't flash.
I don't know how to get the flashing to work when a button is clicked and would greatly appreciate any help on how to accomplish this, thanks.
You need to declare the animated property since color property can be not only color but, for example background etc.
So usual it have to be :
Rectangle {
color: "green"
ColorAnimation on color {
to: "red"
duration: 1000
}
}
But when you use it in inside SequentialAnimation you lose link to property and in this case you can just use PropertyAnimation since ColorAnimation is particular case of it:
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
id: screen
width: 400
height: 300
visible: true
Rectangle {
id: light
width: 50
height: 50
radius: 25
color: "green"
anchors.centerIn: parent
SequentialAnimation {
id: anim
PropertyAnimation {
target: light
property: "color"
to: "red"
duration: 1000
}
PropertyAnimation {
target: light
property: "color"
to: "green"
duration: 1000
}
}
MouseArea {
anchors.fill: parent
onClicked: {
anim.running = true;
}
}
}
}
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!