Can't fit font to window
-
I prepared simple app which display time and date. Generally everything is OK, except one case.
When I start app, then I can resize app and font is fit to window, but when I hide date, and later show date, then label with time can't be fit automatically.I am using context menu to hide and show label with date. Try to find MenuItem with text: "Usun Datę"
How to fix it?
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 1.4 //https://doc.qt.io/qt-5/qml-qtqml-date.html Window { id: mainWindow width: 640 height: 480 visible: true title: qsTr("QML Clock") property string czas_string: "Godzina" property string data_string: "Data" MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton onClicked: { if (mouse.button == Qt.RightButton) { menu.popup() // console.log("Prawy") } else if (mouse.button == Qt.LeftButton) { // console.log("Lewy") } else { // console.log("Inny") } } Menu { id: menu MenuItem { checkable: true text: qsTr("Usuń obramowanie") shortcut: "Ctrl+B" onTriggered: { if (checked == true) { flags = flags | Qt.FramelessWindowHint text = "Przywróć obramowanie" } else { flags = flags & ~Qt.FramelessWindowHint text = "Usuń obramowanie" } } } MenuItem { id: naWierzchu checkable: true text: "Zawsze na wierzchu" shortcut: "Ctrl+T" onTriggered: { if (checked == true) { flags = flags | Qt.WindowStaysOnTopHint text = "Zawsze na wierzchu" } else { flags = flags & ~Qt.WindowStaysOnTopHint text = "Zawsze na wierzchu" } } } MenuSeparator { } >>>>>>> MenuItem <<<<<<<< { checkable: true text: "Usun Datę" // shortcut: "Ctrl+D" onTriggered: { if (checked == true) { text = "Usun datę" dateLabel.visible = false timeLabel.width = mainWindow.width timeLabel.height = mainWindow.height } else { text = "Pokaż datę" dateLabel.visible = true timeLabel.width = mainWindow.width timeLabel.height = mainWindow.height/2 } } } MenuSeparator { } MenuItem { text: "Zamknij progrm" shortcut: "Ctrl+Q" onTriggered: Qt.quit() } } } function timeChanged() { var data = new Date; czas_string = data.toLocaleString(Qt.locale("pl_PL"), "h:mm:ss"); data_string = data.toLocaleString(Qt.locale("pl_PL"), "yyyy-MM-dd\ndddd"); } Timer { interval: 1000; running: true; repeat: true onTriggered: mainWindow.timeChanged() } Text { x: 0 y: 0 id: timeLabel text: qsTr(czas_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: mainWindow.width height: mainWindow.height/2 font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit } Text { x: 0 y: mainWindow.height/2 id: dateLabel text: qsTr(data_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: mainWindow.width height: mainWindow.height/2 font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit } }
-
Most of problems solved by adding functions onWidthChanged and onHeightChanged
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 1.4 //https://doc.qt.io/qt-5/qml-qtqml-date.html Window { id: mainWindow width: 640 height: 480 visible: true title: qsTr("QML Clock") property bool onlyTime: false onWidthChanged: { if (onlyTime == false) { //Pokazuje czas i date timeLabel.width = width dateLabel.width = timeLabel.width timeLabel.x = 0 dateLabel.x = 0 timeLabel.horizontalAlignment = Text.AlignHCenter timeLabel.verticalAlignment = Text.AlignVCenter dateLabel.horizontalAlignment = Text.AlignHCenter dateLabel.verticalAlignment = Text.AlignVCenter } else { //Pokazuje tylko czas timeLabel.width = width dateLabel.width = timeLabel.width timeLabel.x = 0 dateLabel.x = 0 timeLabel.horizontalAlignment = Text.AlignHCenter timeLabel.verticalAlignment = Text.AlignVCenter dateLabel.horizontalAlignment = Text.AlignHCenter dateLabel.verticalAlignment = Text.AlignVCenter } } onHeightChanged: { if (onlyTime == false) { //Pokazuje czas i date timeLabel.height = height/2 dateLabel.height = timeLabel.height timeLabel.y = 0 // dateLabel.y = y/2 timeLabel.horizontalAlignment = Text.AlignHCenter timeLabel.verticalAlignment = Text.AlignVCenter dateLabel.horizontalAlignment = Text.AlignHCenter dateLabel.verticalAlignment = Text.AlignVCenter } else { //Pokazuje tylko czas timeLabel.height = height // dateLabel.height = timeLabel.height timeLabel.y = 0 // dateLabel.y = y/2 timeLabel.horizontalAlignment = Text.AlignHCenter timeLabel.verticalAlignment = Text.AlignVCenter // dateLabel.horizontalAlignment = Text.AlignHCenter // dateLabel.verticalAlignment = Text.AlignVCenter } } property string czas_string: "Godzina" property string data_string: "Data" MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton onClicked: { if (mouse.button == Qt.RightButton) { menu.popup() // console.log("Prawy") } else if (mouse.button == Qt.LeftButton) { // console.log("Lewy") } else { // console.log("Inny") } } Menu { id: menu MenuItem { checkable: true checked: true text: qsTr("Obramowanie") shortcut: "Ctrl+B" onTriggered: { if (checked == true) { flags = flags & ~Qt.FramelessWindowHint text = "Obramowanie" } else { flags = flags | Qt.FramelessWindowHint text = "Obramowanie" } } } MenuItem { id: naWierzchu checkable: true checked: false text: "Zawsze na wierzchu" shortcut: "Ctrl+T" onTriggered: { if (checked == true) { flags = flags | Qt.WindowStaysOnTopHint text = "Zawsze na wierzchu" } else { flags = flags & ~Qt.WindowStaysOnTopHint text = "Zawsze na wierzchu" } } } MenuSeparator { } MenuItem { checkable: true checked: true text: "Data" // shortcut: "Ctrl+D" onTriggered: { if (checked == true) { text = "Data" dateLabel.visible = true timeLabel.width = mainWindow.width timeLabel.height = mainWindow.height/2 mainWindow.width = timeLabel.width mainWindow.height = timeLabel.height onlyTime = false } else { text = "Data" dateLabel.visible = false timeLabel.width = mainWindow.width timeLabel.height = mainWindow.height mainWindow.width = timeLabel.width mainWindow.height = timeLabel.height onlyTime = true } } } MenuSeparator { } MenuItem { text: "Zamknij progrm" shortcut: "Ctrl+Q" onTriggered: Qt.quit() } } } function timeChanged() { var data = new Date; czas_string = data.toLocaleString(Qt.locale("pl_PL"), "h:mm:ss"); data_string = data.toLocaleString(Qt.locale("pl_PL"), "yyyy-MM-dd\ndddd"); } Timer { interval: 1000; running: true; repeat: true onTriggered: mainWindow.timeChanged() } Text { x: 0 y: 0 id: timeLabel text: qsTr(czas_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: mainWindow.width height: mainWindow.height/2 font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit // anchors.centerIn: parent } Text { x: 0 y: mainWindow.height/2 id: dateLabel text: qsTr(data_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter width: mainWindow.width height: mainWindow.height/2 font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit // anchors.centerIn: parent } }
EDIT: After post from @GrecKo , I modified code and correct solution is to use Qt.bindings. Code from this post is working too, but better and shorter solution is to use Qt.bindings. Go to https://forum.qt.io/post/626248
-
That's the wrong solution.
Generally if you are doingon<Property>Changed
, you should consider if you really need it.What happened is that
Usun Datę
MenuItem you broke the width and height bindings of timeLabel.
That is the case when you assign imperatively to a property.
Here withtimeLabel.width = mainWindow.width
, thetimeLabel
width won't be update if themainWindow
width changes, you need to use theQt.binding()
function to create a binding imperatively:
timeLabel.width = Qt.binding(() => mainWindow.width);
Alternatively, you could write your code without having to position your items manually, by using a layout, and in a more declarative manner, here's how I would do it in less than 50% of your lines:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.12 Window { id: mainWindow width: 640 height: 480 visible: true title: qsTr("QML Clock") property string czas_string: "Godzina" property string data_string: "Data" flags: Qt.Window | (framelessMenuItem.checked && Qt.FramelessWindowHint) | (naWierzchu.checked && Qt.WindowStaysOnTopHint) MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton onClicked: { if (mouse.button == Qt.RightButton) { menu.popup() // console.log("Prawy") } } Menu { id: menu MenuItem { id: framelessMenuItem checkable: true text: checked ? qsTr("Przywróć obramowanie") : qsTr("Usuń obramowanie") shortcut: "Ctrl+B" } MenuItem { id: naWierzchu checkable: true text: checked ? "Zawsze na wierzchu" : "?Zawsze na wierzchu" shortcut: "Ctrl+T" } MenuSeparator { } MenuItem { id: hideDateMenuItem checkable: true text: checked ? "Pokaż datę" : "Usun Datę" // shortcut: "Ctrl+D" } MenuSeparator { } MenuItem { text: "Zamknij progrm" shortcut: "Ctrl+Q" onTriggered: Qt.quit() } } } function timeChanged() { var data = new Date; czas_string = data.toLocaleString(Qt.locale("pl_PL"), "h:mm:ss"); data_string = data.toLocaleString(Qt.locale("pl_PL"), "yyyy-MM-dd\ndddd"); } Timer { interval: 1000; running: true; repeat: true onTriggered: mainWindow.timeChanged() } ColumnLayout { anchors.fill: parent Text { id: timeLabel Layout.fillWidth: true Layout.fillHeight: true text: qsTr(czas_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit } Text { visible: !hideDateMenuItem.checked Layout.fillWidth: true Layout.fillHeight: true text: qsTr(data_string) horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pointSize: 400 minimumPointSize: 8 fontSizeMode: Text.Fit } } }
-
I removed functions onWidthChanged and onHeightChanged and next I used Qt.bindings and it works perfectly.
Thanks @GrecKoMenuItem { checkable: true checked: true text: "Data" shortcut: "Ctrl+D" onTriggered: { if (checked == true) { text = "Data" dateLabel.visible = true timeLabel.width = Qt.binding(() => mainWindow.width); timeLabel.height = Qt.binding(() => mainWindow.height/2); onlyTime = false } else { text = "Data" dateLabel.visible = false timeLabel.width = Qt.binding(() => mainWindow.width); timeLabel.height = Qt.binding(() => mainWindow.height); onlyTime = true } } }