I have the following simple QML:
Button
{
id: aButton
text: "a button"
anchors.left: parent.left
anchors.bottom: aRectangle.bottom
onClicked: {
console.log( aButton.height )
console.log( aButton.implicitHeight )
}
}
Rectangle {
id: aRectangle
width: 200
height: 25
color: "red"
border.color: "red"
border.width: 1
anchors.right: parent.right
anchors.top: parent.top
}
The QML produces the following output.
what surprised me is that button is visually offset from the bottom of the rectangle by 6 pixels. What I was expecting is for them to be aligned.
What is the correct way to make this happen?
This is because of Material theme (you should have mentioned ;-) ). They have put a offset inside the thing that is technically the button, but outside of what is visually the button. This is done to have some room for the shadow. It is indeed 6 pixels.
If you wish to overcome this, you can use the 'bottomInset' property:
Button
{
id: aButton
text: "a button"
anchors.left: parent.left
anchors.bottom: aRectangle.bottom
anchors.bottomInset: 0
}
Related
I am getting some weird behaviour from the Qt Virtual Keyboard on QML. I have a TextInput which has focus, but it will not receive the keystrokes until I do an actual click (using a real mouse, not touch) somewhere on the screen. I am also getting "input method not set" in the log. The system is running Ubuntu 20.04. Anybody came across something like this. Any hints/help would be appreciated.
Would also like to mention that the touch screen works for all the other screen navigation
Please see my code below:
Rectangle {
id: passwordFieldId
anchors.top: passwordPromptId.bottom
anchors.topMargin: 30
anchors.horizontalCenter: userPasswordBackgroundId.horizontalCenter
color: HLGStyles.white
border.color: HLGStyles.black
border.width: 1
width: 350
height: 40
TextInput {
id: passwordInputFieldId
echoMode: TextInput.Password
anchors.fill: parent
font {family: liberationSansRegular.name; pointSize: HLGStyles.mediumFont}
color: HLGStyles.black
visible: passwordVirtualKeyboardId.visible
onVisibleChanged: if(visible) passwordInputFieldId.forceActiveFocus()
onActiveFocusChanged: {
if(activeFocus) {
Qt.inputMethod.update(Qt.ImQueryInput)
}
}
focus: passwordVirtualKeyboardId.visible
padding: 2
verticalAlignment: TextInput.AlignVCenter
anchors.centerIn: parent
Keys.onReturnPressed: viewModel.onEnterPressed(passwordInputFieldId.text)
}
}
InputPanel {
id: passwordVirtualKeyboardId
visible: (guiManager.currentScreenDisplayed === Screens.SoftwareUpdate) && (viewModel.currentScreen === viewModel.userPasswordScreenName) ? true : false
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width * 0.95
height: parent.height * 0.5
anchors.bottom: parent.bottom
anchors.bottomMargin: 140
}
The problem is that after I build the app on low-resolution Android devices the screen doesn't look compatible. There is not enough spaces for some pages of application. For instance text inputs overflow the screen, some pages have half view images. I would like the application must keep its form even though I resize it to the minimal screen. There are examples in Qt Software like Gallery sample which can be scalable. But I couldn't find what I missed.
Here is part of my application:
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import QtQuick.Controls.Universal 2.0
import Fluid.Controls 1.0
Flickable {
id:optionsPage
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
margins: 5
}
width: parent.width
clip: true
contentHeight: Math.max(optionsColumn.implicitHeight, height)
ScrollBar.vertical: ScrollBar {}
z: 2
Material.background: "white"
Material.elevation: 1
Universal.background: Universal.accent
Column{
anchors.horizontalCenter: parent.horizontalCenter
id:optionsColumn
spacing: 40
anchors.fill : parent
anchors.topMargin : 15
anchors.bottomMargin : 15
anchors.leftMargin :15
anchors.rightMargin : 15
TextField {
anchors.horizontalCenter: parent.horizontalCenter
id:abg_to3
anchors.margins: 1
Text {
color: "#002aff"
anchors.right: abg_to3.left
text: "(AB): "
font.pointSize: 15
}
}
TextField {
anchors.horizontalCenter: parent.horizontalCenter
id:beta_to3
anchors.margins: 1
Text {
color: "#002aff"
anchors.right: beta_to3.left
text: "Beta: "
font.pointSize: 15
}
}
Row{
anchors.horizontalCenter: parent.horizontalCenter
spacing:50
Button {
id:hesapla_to3
text: "Calculate"
}
Button {
id:sil_to3
text: "Delete"
}
}
Column{
anchors.horizontalCenter: parent.horizontalCenter
spacing: 50
TextField {
anchors.horizontalCenter: parent.horizontalCenter
id:bcg_to3
anchors.margins: 1
Text {
color: "#002aff"
anchors.right: bcg_to3.left
text: "(BC): "
font.pointSize: 15
}
}
Rectangle{
id:reco
height:geri.height
width:geri.width
anchors.horizontalCenter: parent.horizontalCenter
Image {
id:geri
source:"../images/third.png"
}
}
}
}
}
This is normal app.
This is after resizing the window.
For the image you should specify a width and a height proportional to the size of the parent or the device and use Image.PreserveAspectFit as fillMode.
For the font, I think you should use a factor ratio which depends on the resolution of the screen, there is an example here: http://doc.qt.io/qt-5/scalability.html#calculating-scaling-ratio
There might be problems with the margins too and once again the use of a ratio might be the solution.
More generally If you want a full scalable application, there are a few rules that can help you, you can find them here : http://doc.qt.io/qt-5/scalability.html
Hope it helped.
I have a simple component which is designed to show an image with some text under it as follows:
Rectangle{
id: functionView
RowLayout {
spacing: 350
anchors.centerIn: parent
Item {
Image {
id: upload_pic
source: "http://icons.iconarchive.com/icons/custom-icon-design/mono-general-4/128/upload-icon.png"
Text {
text: "Upload Images"
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: -20
}
}
Layout.fillWidth: true
}
Item {
Image {
id: workflow_pic
source: "http://icons.iconarchive.com/icons/icons8/windows-8/128/Data-Workflow-icon.png"
Text {
text: "Upload Workflow"
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: -20
}
}
Layout.fillWidth: true
}
}
}
However, this is not aligned (either vertically or horizontally) on the component window. This can be verified using qmlscene. The images are directly linked in the component source.
You are trying to center your RowLayout in its parent, which is a Rectangle that doesn't have its width property set.
Set the rectangle's width to some value or to its parent width for example by width: parent.width or by setting its anchors like for example:
anchors.left: parent.left
anchors.right: parent.right
I've created a new project and added a scrollview with a rectangle. When I start the project the rectangle is not displayed but if I add an other control it appears. I'm not sure what I'm doing wrong, I want to see the rectangle always.
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: mainWindow
ScrollView{
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.topMargin: 0
anchors.bottomMargin: 0
width: 289
Rectangle{
anchors.fill: parent
color: "blue"
MouseArea
{
anchors.fill: parent
onClicked: console.log("Click")
}
}
}
}
With this code I get the following window (rectangle is not visible):
However if I add a button to this ScrollView...
ScrollView{
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.topMargin: 0
anchors.bottomMargin: 0
width: 289
Rectangle{
anchors.fill: parent
color: "blue"
MouseArea
{
anchors.fill: parent
onClicked: console.log("Click")
}
}
Button{
text:"Test"
}
}
The rectangle appears:
What's wrong with my first code (without the button)?
The ScrollView has two sizes, the size of the control view in the UI, and the size of the content of the ScrollView.
When you add the Rectangle without the Button, you instruct the Rectangle to fill its parent. The parent in this case is the content of the ScrollView. By default that content is empty, and you've instructed the Rectangle to fill this empty space. Therefore there is nothing displayed.
When you add the Button which has an explicit size, it forces the content of the ScrollView to be non-empty, so now the Rectangle has something to fill, thus you see it.
I'm using Qt 5.2.1 for windows (Qt creator 3.0.1)
I have a custom QML component, it works fine when I'm loading in into rectangle:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: mainRectangle
anchors.fill: parent
Loader {
anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld01;
onLoaded: {
ld01.visible = true;
anchors.top = parent.top;
}
}
Loader {
anchors.top: ld01.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld02;
onLoaded: {
anchors.top = ld01.bottom;
ld02.visible = true;
}
}
Component.onCompleted: {
ld01.setSource("View_item2.qml");
ld02.setSource("View_item2.qml");
}
}
But when I'm trying to put it all inside a ScrollView, elements of my component are moved somewhere. What kind of trick I should implement for correct use of ScrollView?
ScrollView {
id: mainTabLayout
anchors.fill: parent
anchors.margins: 4
//here I put a code from above (except imports, of course)
}
Component code is below:
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0
Rectangle {
id: slv_layout
objectName: "itemColumnLayout"
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 1
property int minimal_height: 200
height: 400
color: "green"
MouseArea {
property bool is_pressed: false
property int initial_y: 0
property int proposed_y: 0
id: resizeStick
enabled: true
anchors.bottom: parent.bottom
height: 10
width: parent.width
hoverEnabled: true
onEntered: {
cursorShape = Qt.SizeVerCursor;
}
onPressed: {
is_pressed = true;
initial_y = mouseY;
}
onReleased: {
is_pressed = false;
}
onMouseYChanged: {
if (is_pressed) {
proposed_y = slv_layout.height + mouseY - initial_y;
if (proposed_y >= slv_layout.minimal_height) {
slv_layout.height += (mouseY - initial_y);
initial_y = mouseY;
}
}
}
}
Text {
id: slvTitle
text: "device name"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Rectangle {
anchors.top: slvTitle.bottom
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.topMargin: 2
color: "blue"
Button {
id: slv_butt_run;
objectName: "slv_butt_run"
width: 60
height: width
text: "Run"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_settings;
objectName: "slv_butt_settings"
width: 60
height: width
text: "Settings"
anchors.top: parent.top
anchors.left: slv_butt_run.right
anchors.margins: 2
}
Button {
id: slv_butt_stop;
objectName: "slv_butt_stop"
width: 60
height: width
text: "Stop"
anchors.top: slv_butt_run.bottom
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_expand;
objectName: "slv_butt_expand"
width: 60
height: width
text: "Expand"
anchors.top: slv_butt_settings.bottom
anchors.left: slv_butt_stop.right
anchors.margins: 2
}
TextArea {
id: slv_log_area
anchors.left: slv_butt_expand.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 3
}
}
}
How it looks when all is ok:
How it looks when not ok:
Actually, I still don't know, why code works as described above. But I have found acceptable method to solve task other way.
Looks like "put a needle into egg, egg into duck, duck into rabbit":
ScrollView must contain a ListView component which has a corresponding ListModel and a custom component should act as delegate. Only with ListModel I've got correct automatic scrolling and relative emplacement support.
ScrollView {
id: id_scrollView
anchors.fill: parent
objectName: "ScrollView"
frameVisible: true
highlightOnFocus: true
style: ScrollViewStyle {
transientScrollBars: true
handle: Item {
implicitWidth: 14
implicitHeight: 26
Rectangle {
color: "#424246"
anchors.fill: parent
anchors.topMargin: 6
anchors.leftMargin: 4
anchors.rightMargin: 4
anchors.bottomMargin: 6
}
}
scrollBarBackground: Item {
implicitWidth: 14
implicitHeight: 26
}
}
ListView {
id: id_listView
objectName: "ListView"
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 11
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
delegate: view_component
model: id_listModel
ListModel {
id :id_listModel
objectName: "ListModel"
}
//delegate: View_item2.Item
Component {
id: view_component
View_item2 {
objectName: name
}
}
}
According to the ScrollView documentation,
A ScrollView can be used either to replace a Flickable or decorate an existing Flickable. ... The width and height of the child item will be used to define the size of the content area.
A ScrollView needs to know two width-height pairs: the first one is the width and height used to display the region, and the second one is the width and height of the content. If the area of the content is larger than the display area, the display area will add a scroll bar on it.
In your example:
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
anchors.fill: parent
//...
}
}
The width and height of the content is bound to the display area, making the two areas be in the same size. The width and height of display area is the one in mainTabLayout, which is bound to it's parent; and the width and height of the content is the one in mainRectangle, which is bound to it's parent, mainTabLayout. Therefore the ScrollView cannot work correctly since ScrollView expects the two values are different, not bound together.
To solve your problem, you can explicitly assign width and height to mainRectangle. Do not bind the width and height of mainRectangle to it's parent using anchors.fill:parent.
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
width: 800; height: 800 //not binding to parent.width & height
//...
}
}
And this can work correctly.