I try to create a simple application where the user needs to enter a date. For this I want to connect a button with a calendar popup. This works fine as long as the popup is its own window and has a border. But the moment I make the window borderless it seems to be not drawn anymore. Actually if you move the underlaying window around you see that the area with the calendar widget stays undrawn.
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow {
width: 800
height: 600
property var pos : getOffset(dateField)
Button {
id: dateField
width: 100
height: 50
anchors.centerIn: parent
text: "show widget"
onClicked:{ toggleModal() }
}
function getOffset(item) {
var offset = {
"x": item.x,
"y": item.y + item.height
};
while(item.parent) {
item = item.parent;
offset.x += item.x;
offset.y += item.y;
}
console.debug("total", "x", offset.x, "y", offset.y)
return offset;
}
function toggleModal() {
if(modal.active) {
console.log("hide calendar")
loseFocus();
}
else {
console.log("show calendar")
modal.show()
modal.requestActivate()
}
}
function loseFocus(newDate) {
modal.close();
}
Window {
id: modal
flags: Qt.Window | Qt.FramelessWindowHint
//flags: Qt.Window
//modality: Qt.ApplicationModal
minimumHeight: calendar.height; minimumWidth: calendar.width
maximumHeight: calendar.height; maximumWidth: calendar.width
x: pos.x
y: pos.y
Calendar {
id: calendar
width: 200
height: 300
}
}
}
Related
When I press the button now it instantly goes to the next page. Is it possible to give this loading.gif a sleep of 5 seconds?
I have tried to give it a duration: 5000 but then it gives an error
---- FULL CODE UPDATED ----
Login.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
Component
{
Rectangle
{
Rectangle
{
anchors.fill: parent
// Timer for Creating delay
Timer
{
id: timer
}
function delay(delayTime,cb)
{
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
ColumnLayout
{
// Some other items.
Button
{
onClicked:
{
backend.inloggen(email.text, wachtwoord.text, dropdown.currentText)
delay(5000, function()
{
loading_container.visible = true
})
stack.push(btnHomepage)
}
}
Rectangle
{
id: loading_container
visible: false
AnimatedImage
{
source: "./images/loading.gif"
}
}
}
}
}
}
Error: Login.qml:170: ReferenceError: delay is not defined
Sadly updating the the QtQuick nad QtQuick.controls update wasn't the solution
you can create delays by using Timer here is your code, I add one function that creates delay it gets duration like 5000 means 5 seconds, and one function that will be connected to Timer.
This function acts like a singleshot.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
// Timer for Creating delay
Timer {
id: timer
}
function delay(delayTime,cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle
{
id: loading_container
anchors.fill: parent
color: "#d71616"
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 60
visible: false
}
Button {
id: button
x: 0
y: 0
width: 151
height: 62
text: qsTr("Click me ")
onClicked:
{
delay(5000, function() {
loading_container.visible = true
})
}
}
}
As you update the question, Try this :
Component encapsulated QML types with well-defined interfaces.
the way that you use it is wrong.
The way that you use Function in your program is also wrong.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Item {
width: 640
height: 480
Timer
{
id: timer
}
function delay(delayTime,cb)
{
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle
{
anchors.fill: parent
// Timer for Creating delay
// ColumnLayout
// {
// Some other items.
Button
{
onClicked:
{
// backend.inloggen(email.text, wachtwoord.text, dropdown.currentText)
delay(5000, function()
{
loading_container.visible = true
})
// stack.push(btnHomepage)
}
}
Rectangle
{
id: loading_container
visible: false
AnimatedImage
{
source: "what ever is your source path"
}
}
}
// }
}
In your code, the button doesn't have access to the Delay function, hence the reference error you get
Simply move the function to the button and the Timer in the root item
Let's say I have a QML Text or TextArea that contains a very long HTML page. I want to make it easier to read by splitting it into pages.
More specifically, every time I press the down key, I want it to scroll down until none of the current text on the screen is still there.
I already know how to make the entire TextArea scrollable; that's not what I'm looking for. What I'm looking for is more like the kind of behavior you'd expect in an ebook reader.
Is there any way to do something like that, preferably in pure QML (though C++ is also fine).
You can measure the TextArea height after loading, divide it to the container height and so get the count of pages. Then you just move the TextArea relative to its container according to the current page.
The simple illustration of my idea:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
id: main
visible: true
width: 640
height: 800
property int currentPage: 1
property int pageCount: 1
ColumnLayout
{
anchors.fill: parent
anchors.margins: 5
RowLayout {
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignHCenter
Button {
text: "<"
onClicked: {
if(main.currentPage > 1)
main.currentPage --;
}
}
Text {
text: main.currentPage + " / " + main.pageCount
}
Button {
text: ">"
onClicked: {
if(main.currentPage < main.pageCount)
main.currentPage ++;
}
}
}
Rectangle {
id: container
clip: true
Layout.fillHeight: true
Layout.fillWidth: true
TextArea {
id: msg
text: "Loading ..."
width: container.width
height: container.height
y: -(main.currentPage - 1) * container.height
textFormat: TextEdit.RichText
wrapMode: TextEdit.Wrap
Component.onCompleted: {
msg.makeRequest();
}
onContentHeightChanged: {
msg.height = msg.contentHeight;
if(msg.contentHeight >= container.height && container.height > 0)
{
main.pageCount = msg.contentHeight / container.height;
loader.running = false;
}
}
function makeRequest()
{
var doc = new XMLHttpRequest();
msg.text = "";
doc.onreadystatechange = function() {
if (doc.readyState === XMLHttpRequest.DONE) {
msg.text = doc.responseText;
}
}
doc.open("GET", "http://www.gutenberg.org/files/730/730-h/730-h.htm");
doc.send();
}
}
}
}
BusyIndicator {
id: loader
running: true
anchors.centerIn: parent
}
}
Of course you have to process margins, the last line on a page, recalculate the values on resizing etc.
QML Popup and derived controls are creating a PopupItem object which is a visual representation of it, but Popup itself is parented to the contentData of the application window. objectName specified for Popup is not applied to PopupItem. For example, the following application:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Popup Test")
Button {
text: "Open"
onClicked: dummyPopup.open()
}
Popup {
id: dummyPopup
objectName: "dummyPopup"
x: 100
y: 100
width: 200
height: 300
modal: true
focus: true
}
}
creates PopupItem with empty objectName
Is there a way to set objectName for PopupItem from QML?
Set the objectName of its contentItem upon completion:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Popup Test")
Button {
text: "Open"
onClicked: dummyPopup.open()
}
Popup {
id: dummyPopup
objectName: "dummyPopup"
x: 100
y: 100
width: 200
height: 300
modal: true
focus: true
Component.onCompleted: {
contentItem.objectName = "foo"
print(contentItem)
}
}
}
By the way, if this is for auto tests, I have a hack in C++ that avoids the need to give an objectName to the contentItem:
QObject *TestHelper::findPopupFromTypeName(const QString &typeName) const
{
QObject *popup = nullptr;
foreach (QQuickItem *child, overlay->childItems()) {
if (QString::fromLatin1(child->metaObject()->className()) == "QQuickPopupItem") {
if (QString::fromLatin1(child->parent()->metaObject()->className()).contains(typeName)) {
popup = child->parent();
break;
}
}
}
return popup;
}
You can then use that function like this in your test:
const QObject *newProjectPopup = findPopupFromTypeName("NewProjectPopup");
QVERIFY(newProjectPopup);
QTRY_VERIFY(newProjectPopup->property("opened").toBool());
I am trying to add a tabButton to TabBar dynamically on pressing a button but i have spent a lot of time searching but i am not getting how to add, below is the code which i am working on :
MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Item
{
property int BtnWidth:0
property int BtnHeight:0
property string BtnText: ""
property bool isChecked : false
TabButton
{
id:tabBtn
text:BtnText
width:BtnWidth
height:BtnHeight
}
}
MainForm.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Rectangle
{
Button
{
id:button
width:100
height:100
anchors.top:parent.top
text:qStr("Add")
onClicked{
//How to add logic here to add tab in below tabBar.
}
}
TabBar
{
id:tabBar
anchors.top:button.bottom
width:500
height:500
}
}
Example:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
width: 360
height: 630
visible: true
header: TabBar {
id: tabBar
}
Component {
id: tabButton
TabButton { }
}
Button {
text: "Add"
anchors.centerIn: parent
onClicked: {
var tab = tabButton.createObject(tabBar, {text: "Tab " + tabBar.count})
tabBar.addItem(tab)
}
}
}
You need to have something like a Component that is a TabButton. Your file MyTabButton.qml won't result in a TabButton, but instead an Item containing a TabButton, but with this, your TabBar does not know what to do.
So your file will need to have TabButton as root element
//MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
TabButton
{
id: tabBtn
// customize as you like
}
Then you create a Component of this in your file where you want to use it. (e.g. main.qml)
import QtQuick 2.4
import QtQuick.Controls 2.0
ApplicationWindow {
width: 800
height: 600
visible: true
TabBar {
id: tabBar
width: 800
height: 50
}
// The component is like a factory for MyTabButtons now.
// Use myTabButton.createObject(parent, jsobject-with-property-assignments) to create instances.
Component {
id: myTabButton
MyTabButton {
/// EDIT ACCORDING TO YOUR COMMENTS ***
Connections {
target: tabBar
onCurrentIndexChanged: doSomething()
}
/// EDIT OVER
}
}
Button {
anchors.centerIn: parent
// Create a object out of the component, and add it to the container
onClicked: tabBar.addItem(myTabButton.createObject(tabBar /*, { object to set properties }*/))
}
}
TabBar inherits Container, which has addItem().
Try it in Window
Row {
anchors.fill: parent
TabBar {
id: tabBar
currentIndex: 0
width: parent.width - addButton.width
TabButton { text: "TabButton" }
}
Component {
id: tabButton
TabButton { text: "TabButton" }
}
Button {
id: addButton
text: "+"
flat: true
onClicked: {
tabBar.addItem(tabButton.createObject(tabBar))
console.log("added:", tabBar.itemAt(tabBar.count - 1))
}
}
}
When I try to dynamically creates Popup with Qt.createQmlObject(...) or Qt.createComponent(...), I got exception:
QML Popup: cannot find any window to open popup in.
Here is my code:
var popup1 = Qt.createQmlObject('import QtQuick 2.8; import QtQuick.Controls 2.1; Popup { id: popup; x: 100; y: 100; width: 200; height: 300; modal: true; focus: true; closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent; visible: false }',
window,
"DynamicPopup");
popup1.open()
var popupComponent = Qt.createComponent("qrc:/TestPopup.qml")
var popup2 = popupComponent.createObject(window);
popup2.open()
TestPopup.qml:
import QtQuick.Window 2.2
import QtQuick.Controls 2.1
Popup {
x: 100
y: 100
width: 200
height: 300
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
visible: false
}
Popup is not inheriting QQuickItem, and by default it is parented by QML Window, which is not instantiated if you are using QQuickWidget. Thus passing parent should be done as follows:
var popupComponent = Qt.createComponent("qrc:/TestPopup.qml")
var popup2 = popupComponent.createObject(window, {"parent" : window});
popup2.open()
The parent must be an element that inherits from QQuickItem
Example:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.1
Window {
id: win
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Row{
Button{
id: item1
text: "btn1"
onClicked: {
var popup1 = Qt.createQmlObject('import QtQuick 2.8; import QtQuick.Controls 2.1; Popup { id: popup; x: 100; y: 100; width: 200; height: 300; modal: true; focus: true; closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent; visible: false }',
item1,
"DynamicPopup");
popup1.open()
}
}
Button{
id: item2
text: "btn2"
onClicked: {
var popupComponent = Qt.createComponent("qrc:/TestPopup.qml")
var popup2 = popupComponent.createObject(item2);
popup2.open()
}
}
}
}
method 1:
method 2:
A Popup needs to be be parented to an Item, window isn't one.
You should use window.contentItem instead.
A good approach to dynamically load a popup with a Loader:
Loader {
id: popupLoader
active: false
source: "qrc:/TestPopup.qml"
onLoaded: item.open()
}
function openMyPopup() {
if( popupLoader.active )
popupLoader.item.open()
else
popupLoader.active = true
}