qt quick material style controls - qt

I'm trying to design a qt quick application using qml. From what I gather in the documentation of qt is that these controls have support for styling automatically (e.g. there's a material light/material dark themes.
However, when I tried to apply it to the tabview control I can't get the styling to be applied. I can make a propery binding ala Rectangle { color: Material.color(Material.Red)} This works well for looking up any of the predefined colors, however I don't seem to be able to access attached (inherited) properties like Material.background
How can I best apply theming to controls that don't support it? It doesn't look like it's possible to property binding to an attached property- or at least qt/qml seems to get confused because Material. is also considered the namespace.
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.2
import QtQuick.Controls.Material 2.1
ApplicationWindow {
id: mainWindow;
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Material.theme: Material.Dark
Material.accent: Material.Purple
TabView {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
tabPosition: Qt.BottomEdge
Material.theme: Material.Dark
Material.accent: Material.Purple
Tab {
title: "Red"
Material.theme: Material.Dark
Material.accent: Material.Purple
}
Tab {
title: "Blue"
Rectangle { color: "blue" }
}
Tab {
title: "Green"
Material.theme: Material.Dark
Material.accent: Material.Purple
}
style: TabViewStyle {
frameOverlap: 1
tab: Rectangle {
color: styleData.selected ? "steelblue" :"lightsteelblue"
border.color: "steelblue"
implicitWidth: Math.max(text.width + 4, 80)
implicitHeight: 20
radius: 2
Text {
id: text
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "white" : "black"
}
}
frame: Item {
}
}
}
}

TabView is from Controls 1. You should use TabBar and TabButton, as the Material style is only available with Qt Quick Controls 2:
https://doc.qt.io/qt-5/qtquickcontrols2-differences.html#type-comparison-table

Related

Material Style In Qml Does Not Load Colors

i used methods here to use material design in my QtQuick project and used Accent and Themes from here controls loading in material style correctly in normal qml files , but in qml files loaded by loader result is like this:
this loader is in main.qml :
Loader{
id:myLoader
anchors.fill: parent
source: "LoginPage.qml"
}
and here is my dynamic qml file
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.3
import QtGraphicalEffects 1.0
Rectangle{
Material.theme: Material.Dark
Material.accent: Material.Teal
property string error_msg: ""
id: loginPage
Button {
id: button
width: 80
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 0
font.family: "B Nazanin"
enabled: webView.loadProgress == 100 ? true:false
KeyNavigation.tab: button1
Material.accent: Material.Orange
onClicked: {
login()
}
}
}
The dark there is presumed to have a dark background. It will not set your window background for you, it only affects GUI controls. And the button in particular doesn't use use the accent color, just the foreground color, unless toggle is enabled, in which case it will use the accent color to signify that.
Material.theme: Material.Dark
Material.accent: Material.Teal
Rectangle {
anchors.fill: r2
color: "#262626"
}
Row {
id: r1
Button {
text: "test"
checkable: true
Material.accent: Material.Orange
}
Button {
text: "test"
checkable: true
}
}
Rectangle {
anchors.fill: r2
}
Row {
id: r2
anchors.top: r1.bottom
Button {
text: "test"
checkable: true
Material.accent: Material.Orange
}
Button {
text: "test"
checkable: true
}
}
As you see, on a white background, the dark theme button looks blurry and washed out. If you want to set the button color, that would be the Material.background whereas the text would be Material.foreground.
I had a similar problem.
Just use ApplicationWindow as your root element and it will work.
And additionally you have to load Material before instantiating QML.
QGuiApplication application(argc, argv);
QQmlApplicationEngine engine;
QQuickStyle::setStyle("Material");

QML: Buttons become transparet over images using Material Style

I want my application to use an image as a Background. So I use this code:
In my ApplicationWindow:
Image {
id: bkgImage
source: "qrc:/images/bkg.jpg"
anchors.centerIn: parent
}
To add a button
Button {
id: btnAsistencia
text: qsTr("ASISTENCIA")
font.pixelSize: fhButttonTextSize
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: btnInscripcion.bottom
anchors.topMargin: parent.height*0.1
}
The code above is for the second button, but I added one before in the exact same way. This is the result:
The second button becomes transparent over the image. How can I prevent this?
You can set the background colour of the button with the Material.background attached property:
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
ApplicationWindow {
id: window
width: 400
height: 440
visible: true
color: "red"
Button {
text: qsTr("ASISTENCIA")
Material.background: "#666"
}
}
The default colour has some transparency:
http://code.qt.io/cgit/qt/qtquickcontrols2.git/tree/src/imports/controls/material/qquickmaterialstyle.cpp#n862

QML: QtQuick.Controls Tabs with Icons

I have been learning how to use QT Creator Tool so that I can build UI's quickly and easily. For my current project, I have to use QML to build my UI. I want to have tabs in my display. I would like to use an image in place of text in my tab. My code is below. I have tried to add a source but that did not help me add an icon. Does anyone know how to do this? All help would be greatly appreciated.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.2
Window {
visible: true
width: 640
height: 400
opacity: 1
TabView {
height: 300
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 0
anchors.fill: parent
Tab {
title: "Robot"
component: Qt.createComponent("RobotControls.qml")
}
Tab{
title: "Tab #2"
}
}
}
Elaborating on the answer from Simon Warta in Extending TabViewStyle styleData, here is what you could do :
Define a custom IconTab
You want to extend the Tab item so that you can specify an icon to display.
So add a new file to your project, called IconTab.qml:
IconTab.qml
import QtQuick.Controls 1.4
Tab{
property string icon
}
Define a custom TabViewStyle.
In order to use this new property, you must create your own TabViewStyle. You may have to redefine background and text size and colors so that it fits your app theme, but something like this could work:
MyStyle.qml
import QtQuick 2.5
import QtQuick.Controls.Styles 1.2
TabViewStyle {
tab: Item {
implicitWidth: Math.round(textitem.implicitWidth + image.width + 20)
implicitHeight: Math.round(textitem.implicitHeight + 10)
Rectangle
{
anchors.fill: parent
anchors.bottomMargin: 2
radius: 1
border.width: 1
border.color: "#AAA"
color:"transparent"
}
Rectangle
{
anchors.fill: parent
anchors.margins: 1
anchors.bottomMargin: styleData.selected ? 0 : 2
radius: 1
gradient: Gradient{
GradientStop{position:0; color:styleData.selected?"#EDEDED":"#E3E3E3"}
GradientStop{position:1; color:styleData.selected?"#DCDCDC":"#D3D3D3"}
}
}
Text {
id: textitem
anchors.fill: parent
anchors.leftMargin: 4 + image.width
anchors.rightMargin: 4
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: styleData.title
elide: Text.ElideMiddle
}
Image
{
id: image
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 2
anchors.leftMargin: 4
fillMode: Image.PreserveAspectFit
source: control.getTab(styleData.index).icon
}
}
}
Note how you can make use of the control property and the styleData.index to get your icon's url: control.getTab(styleData.index).icon
Put the pieces together
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
Window {
visible: true
width: 640
height: 400
TabView {
id: tabView
anchors.fill: parent
style: MyStyle{}
IconTab {
title: "Tab #1"
icon: "icon.png"
}
IconTab{
title: "Tab #2"
}
IconTab{
title: "Tab #3"
icon: "icon.png"
}
}
}
Result

How to ensure Button has focus when QML tab is activated, rather than TextField?

In QML, I have a Tab containing a TextField and a Button. How do I ensure the Button has focus when the tab is selected, instead of the TextField? Setting "focus:" to true and false, respectively, does not do it. In the code below, the goal is for btnRefresh to have focus when a tab is selected, instead of txtName.
main.qml:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.2 // For TabViewStyle
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TabView {
id: tabView
anchors.fill: parent
anchors.margins: 20
tabPosition: Qt.BottomEdge
Tab {title: "Tab 1"; source: "mytab.qml"}
Tab {title: "Tab 2"; source: "mytab.qml"}
style: TabViewStyle {
frameOverlap: 1
tab: Rectangle {
color: styleData.selected ? "steelblue" :"lightsteelblue"
border.color: "steelblue"
implicitWidth: Math.max(text.width + 4, 80)
implicitHeight: 20
radius: 2
Text {
id: text
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "white" : "black"
}
}
frame: Rectangle { color: "steelblue" }
}
}
}
mytab.qml:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
Rectangle {
anchors.fill: parent
GridLayout {
columns: 2
anchors.fill: parent
rowSpacing: 10
RowLayout {
Layout.columnSpan: 2
Label {
id: lblName
text: "Name:"
}
TextField {
id: txtName;
text: "a name"
Layout.preferredWidth: lblName.implicitWidth * 1.5;
focus: false
}
}
TextArea {
id: textSetup
text: "Text Area"
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.fillHeight: true
}
Button {
id: btnRefresh
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
text: qsTr("Refresh")
focus: true
}
}
}
Whenever you switch tabs in a TabView, a signal handler onVisibleChanged is called on the two tabs (one that disappeared and the one that appeared) since the visibility of these tabs has changed. You can try adding following code to your Tabs:
Tab {
id: tab1
title: "Tab 1"; source: "mytab.qml"
onVisibleChanged: {
if (visible) tab1.item.funcSetFocusOnButton();
}
}
Please note the way a function is called on a tab using item.
Now in "mytab.qml", you create a javascript function funcSetFocusOnButton which sets focus on your button. So your mytab.qml will have this additional code:
Rectangle {
//Your GridLayout{}
funcSetFocusOnButton() {
btnRefresh.forceActiveFocus();
}
}
Note here that the function funcSetFocusOnButton should be a direct child of your base item (rectangle here). Hope this helps!

How do I show a message box with Qt Quick Controls?

What is the equivalent of QMessageBox::information() when one wishes to write a QML application using Qt Quick Controls?
In Qt 6.3 and later you can use MessageDialog from QtQuick.Dialogs:
MessageDialog {
text: "The document has been modified."
informativeText: "Do you want to save your changes?"
buttons: MessageDialog.Ok | MessageDialog.Cancel
onAccepted: Qt.quit()
}
In Qt 6.2 and earlier you can use MessageDialog from Qt.labs.platform (using the same example code as above).
In Qt 5 you can use MessageDialog from QtQuick.Dialogs 1.x:
import QtQuick 2.2
import QtQuick.Dialogs 1.1
MessageDialog {
id: messageDialog
title: "May I have your attention please"
text: "It's so cool that you are using Qt Quick."
onAccepted: {
console.log("And of course you could only agree.")
Qt.quit()
}
Component.onCompleted: visible = true
}
You Can use Popup In QtQuick Controls 2 :
import QtQuick.Window 2.2
import QtQuick.Controls 2.0 // or import Qt.labs.controls 1.0
Window {
id: window
width: 400
height: 400
visible: true
Button {
text: "Open"
onClicked: popup.open()
}
Popup {
id: popup
x: 100
y: 100
width: 200
height: 300
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
}
}
Ok this does the job (badly). Import the Window object:
import QtQuick.Window 2.1
Then add this to your main window (or you could put it in another file I guess):
function showMessage(text, title)
{
messageBox.text = text;
messageBox.title = title;
messageBox.visible = true;
}
Window {
id: messageBox
modality: Qt.ApplicationModal
title: ""
visible: false
property alias text: messageBoxLabel.text
color: parent.color
minimumHeight: 100
minimumWidth: 300
Label {
anchors.margins: 10
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: messageBoxButton.top
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
id: messageBoxLabel
text: ""
}
Button {
anchors.margins: 10
id: messageBoxButton
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: "Ok"
onClicked: messageBox.visible = false
}
}
Problems with it:
The window can be shrunk so that the text and button overlap.
The minimum window size is hard-coded rather than calculated from the text size.
You can't select the text.
Looks a bit shit.
Unfortunately, there isn't one, at least not in the shipping Qt Quick Controls as of Qt 5.1.1 :(
You need to add it to your project via a QObject wrapper.
// CenteredDialog.qml
import QtQml 2.2
import QtQuick 2.9
import QtQuick.Controls 2.2
Dialog {
parent: ApplicationWindow.overlay
x: (parent.width - width) / 2
y: (parent.height - height) / 2
focus: true
modal: true
property alias text: messageText.text
Label {
id: messageText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
}
standardButtons: Dialog.Ok
}
You can declare CenteredDialog { id: centeredDialog } somewhere, then in some event handler you may call:
centeredDialog.title = qsTr("Error!")
centeredDialog.text = qsTr("Access violation")
centeredDialog.visible = true

Resources