How to create a square Button in Qt QML? - qt

I'm trying to create a simple square-shaped button in QML, but it is not working as expected. Here is the minimum amount of code:
import QtQuick 2.7
import QtQuick.Controls 2.1
Page {
id: app
width: 400
height: 640
Button {
width: 48
height: 48
}
}
Which produces this result:
Any idea what is going on? I've looked through the docs and tried to set the implicitWidth and implicitHeight through a defined background item, but that blocks the built in hover and shadow functionalities of the Button.
Button {
background: Rectangle {
implicitWidth: 48
implicitHeight: 48
color: "gray"
}
}
results in:
Are there any ways to set the desired size without explicitly defining a background item?
Edit:
I've also tried setting all padding to 0 to see if padding is an issue:
Button {
width: 48
height: 48
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
}
As well as following a colleague's advice to add a text element to see where it is placed:
Button {
width: 48
height: 48
Text {
text: "hello"
}
}
The text placement suggests to me that the button may extend past the top bounds of the visible gray rectangle. Could this be the case?
Another note: The emulator I am using is the AppStudio for ArcGIS emulator installed in Qt Creator. Qt 5.10.0, Windows 10.

Any idea what is going on? I've looked through the docs and tried to set the implicitWidth and implicitHeight through a defined background item, but that blocks the built in hover and shadow functionalities of the Button.
The Material style Button has some padding which is probably what's causing it to not be square. Setting each padding property to 0 (or equal values) should help:
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0

Mitch was on the right track that the Qml Material style Button has some padding but the background Rectangle also has this line:
height: parent.height - 12
which is a bit troublesome. You could make a hacky solution by setting your button height 12 more than the width (and also changing the padding) but I would not suggest it.
Instead like they suggest with Customizing Qt Quick Controls I would make MyButton.qml and copy the Material style Button.qml code there and just change the background height and the control padding. This makes it easier to do more style changes later since you do not need to change all the Buttons in your application.

Related

QML Tumbler looses vertical mouse focus

When I create a tumbler widget in QML, I can grab it, and change the contents. As soon as I leave the widget with my mouse in vertical direction, the tumbler stops changing its contents. It works fine if I leave the widget to the left or right. In that case, I can operate the tumbler even when the mouse leaves the QML window.
Is there anything I missed?
Example code:
import QtQuick 2.5
import QtQuick.Controls 2.5
Rectangle {
width: 1000
height: 600
Tumbler {
anchors.centerIn: parent
model: 24
width: 30
height: 100
}
}
I'm using QT 6.2.1 and tried it on Kubuntu 20.04 and Yocto Dunfell.
I tried the same thing with a QML Dial. Herewith I can leave the widget in all directions, and it still reacts to my mouse movement.

error with Layout.alignment vertical bar in vertical bar .qml file

Background: I have a side project that I'm working on that's gonna be a "rolling" project that I'll be updating as I learn and grow as a programmer. Since this project will be growing with me I wanted to learn how to create a GUI that can be simple but also gives me the ability to really customize the GUI once I really feel comfortable with it. After feeling overwhelmed with options I landed on PySide6 and QML but I'm running into an issue with the QML file.
The tutorial I'm following is Python-QML integration (https://doc.qt.io/qtforpython/tutorials/qmlintegration/qmlintegration.html) and I'm using the .py and .qml files linked at the bottom of the tutorial page. For an IDE if it matters I'm using Pycharm and have PySide6 package added to the project as well as the QML Editor plug-in.
Problem: The issue that I'm having is with the .qml file. For some reason, it's not recognizing the vertical bar used in the two-dimensional flag to center my RowLayout vertically and horizontally. When I hover my cursor over the vertical bar I get a tip saying that one of multiple different symbols like commas, parenthesis, or braces were expected but instead got '|'.
ColumnLayout {
id: rightcolumn
spacing: 2
Layout.columnSpan: 1
Layout.preferredWidth: 400
Layout.preferredHeight: 400
Layout.fillWidth: true
RowLayout {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Button {
id: red
text: "Red"
highlighted: true
Material.accent: Material.Red
onClicked: {
leftlabel.color = bridge.getColor(red.text)
}
}
}
I feel like I've checked everywhere Reddit, stack overflow, the documentation on the QT site, but can't find anyone else that's experienced this.
The main issue is that setting Qt.AlignVCenter in a child of a ColumnLayout doesn't make sense since Layouts only honor alignment orthogonal to the direction of their layout. So, setting a vertical alignment on a vertically oriented layout won't do anything.
In this case, since you've simplified the example (specifically, all of your layouts only have one child), you don't really need any layouts at all. Instead, I would convert the ColumnLayout to an Item and then anchor the Button in the center of it like this:
Item {
id: rightcolumn
Layout.columnSpan: 1
Layout.preferredWidth: 400
Layout.preferredHeight: 400
Layout.fillWidth: true
Button {
id: red
anchors.centerIn: parent
text: "Red"
highlighted: true
Material.accent: Material.Red
onClicked: {
leftlabel.color = bridge.getColor(red.text)
}
}
}

QML/Qt: Make displayed text as large as possible depending on the parent containing it

I am trying to make a very simple KDE-Plasma Widget where only a certain number is displayed. I want to make this displayed number have a font size as large as possible depending on the parent containing it.
Here is what it looks right now:
As you can see, the text inside has a lot of space around it. What I actually want it to be is something like the "Date And Time" Widget found in KDE Plasma (my widget is right next to it for comparison):
Here, the time displayed has much lesser space around it while also auto-resizing whenever the panel height is changed.
Here is what the current code looks like:
import QtQuick 2.6
import QtQuick.Layouts 1.0
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.plasmoid 2.0
Item {
id: main
anchors.fill: parent
Layout.minimumWidth: units.iconSizes.large
Layout.minimumHeight: units.iconSizes.large
Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
PlasmaComponents.Label {
id: display
anchors {
fill: parent
margins: Math.round(parent.width * 0.1)
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: foobar
font.pixelSize: 1000;
minimumPointSize: theme.smallestFont.pointSize
fontSizeMode: Text.Fit
font.bold: true
}
Timer {
some stuff
}
}
I tried looking into the code of the above Date and Time widget and wrote down the exact same layouts/controls (which is what you are seeing in the above code) with the same positioning/styling properties and yet I get a lot of space around my text/or the font size continues to remain small.
I tried your code and it resized the font correctly. For the spacing around the text, there are two points:
The spacing on the left and right is easily controlled by adjusting the margins value that you are using. For less space, try Math.round(parent.width * 0.05).
The spacing on the top and bottom is larger because the shape of your parent object is square, while the shape of the text is rectangular. In order to make the text fit the height of the square without exceeding the width of the square, the text would not just need to resize, it would need to be stretched vertically. But QML does not have an easy way to do that, and I doubt that's really what you want anyway.
EDIT:
And if you do want font stretching, I'll point you to this answer.
Thanks to #JarMan's input I was able to realize that my text was being rendered in small font because of lack of space due to the root (item) element being square in shape.
I have now figured that to change the layout sizes of the root element inside the KDE-Plasma panel, one needs to mess with Layout.preferredWidth and Layout.preferredHeight.
Here is what I did:
item {
.
.
Layout.preferredWidth: 150 * units.devicePixelRatio
Layout.preferredHeight: 50 * units.devicePixelRatio
.
.
}
Note: the 150 and 50 values aren't final. It basically gives an idea about the ratio at which the root element's width and height should be in (and I wanted a rectangle). It automatically resizes the inner content too as the Plasma Panel is resized.

SVG rasterization issue in a QML Canvas

I am experiencing issues when using the QML Canvas drawImage method to render SVG icons.
Basically the QML Canvas ignores the rasterization size and paint the image starting from its original size (in this case 48x48px), and scaling it up with an ugly aliasing effect.
Has anyone ever seen this and possibly figured out a solution ?
Please see QTBUG-59878 for a working self-contained example.
Here I'm gonna copy just the QML code and a screenshot of what I see.
From the left:
the original SVG icon as Image item (correct)
the same Image item rendered by drawImage (to be honest I expected this to be correct as well, since rasterized data should be provided by Image)
the SVG icon loaded with the procedure explained in the documentation, with loadImage and onImageLoaded
import QtQuick 2.0
Rectangle
{
width: 640
height: 480
Image
{
id: svgIcon
source: "qrc:/qt_logo.svg"
x: 10
y: 100
width: 180
height: 200
sourceSize: Qt.size(width, height)
}
Canvas
{
id: canvas
anchors.fill: parent
contextType: "2d"
property string imagefile: "qrc:/qt_logo.svg"
Component.onCompleted: context.loadImage(imagefile)
onImageLoaded: requestPaint()
onPaint:
{
context.drawImage(svgIcon, 200, 100, 180, 200)
context.drawImage(imagefile, 400, 100, 180, 200)
}
}
}
I have worked with SVG within QML, the performance is very poor and quality of upscaling and downscaling isn't good enough. if you're using SVG for showing icons, i will suggest you to use fonts instead of svg icons, its pretty fast and high quality. you can convert your svg icons to font characters, and pack them in single font and use it within QML as Text or label elements, seen Iconmoon.io

QML tab occasionally stretches off-screen

I have a QML-based GUI with a fixed width that uses the TabView type in several places.
On one page, I have something like this (leaving out most properties except for lateral anchors):
ColumnLayout {
MyTabsViewSubmenu { // defined below
Layout.fillWidth: true
Tab {
id: someId
title: someString
anchors.fill: parent
SomeCustomClass {
id: someId2
anchors.fill: parent
}
}
// three more tabs defined the same way, with the same anchors...
}
// another item below the tabs...
}
MyTabsViewSubmenu is something like this:
TabView {
Rectanble {
anchors.fill: parent
}
style: TabViewStyle {
// miscellaneous style stuff
}
}
One of my four tabs in the ColumnLayout above sometimes stretches off the screen when selected. As far as I can tell, there is nothing special about it compared to the other items used as tabs throughout the GUI. The layout of this tab is something like this:
Item {
MyTabsViewSubmenu {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: sibling.top
Tab {
// no anchors (see below)
SomeItem {
anchors.fill: parent
}
// ... other tabs....
}
Rectangle {
id: sibling
anchors.left: parent.left
anchors.right: parent.right
// ... stuff....
}
}
The entire page stretches off the screen: both the sub-tab content and the content in the Rectangle I've shown here as sibling.
I would suspect that possibly the missing anchors.fill: parent in the innermost Tabs might be the problem, except that sibling is not (as far as I can tell* missing any anchors, and I've never seen the tabs stretched offscreen without the sibling being stretched offscreen as well.
It seems entirely unpredictable whether the stretching occurs or the layout is done correctly. Once the layout has stretched off the screen, I can sometimes get it to correct itself by navigating away from that page and back.
I'm using Qt 5.6.1-1 on Debian 7.
EDIT: When I navigate to the "stretched" tab and the bug occurs causing the stretching, the tabs themselves at the top of the page also get "stretched" somewhat. Returning to a different tab un-stretches the tabs.
The fix
Setting Layout.maximumWidth (as per Velkan's comment) appears to resolve the issue. Additionally, it appears to make the page load faster.
Observations and testing
It's now about a week and a half since I introduced this change to the code, and the product has been heavily tested since then.
We have discovered a second component that needs Layout.maximumWidth set in order to keep from stretching off the screen, and indeed applying this fix to both the original problematic components has prevented the screen-stretching bug. So this is definitely a valid fix.
Possible root cause (i.e. groundless speculation)
I suspect that the QML engine attempts to size "Layout" objects by starting with the maximum width, then shrinking them to fit (or something like this). If the maximum width is unset, it's set to something like "infinity". Without a maximumWidth, it appears that the auto-shrinking operation sometimes fails, leaving the component stretched offscreen. I suspect that the automatic-resizing code may be impacted by some kind of nondeterminism in the order in which the sizes of different QML components are computed.

Resources