How to show/hide KDE plasmoid's tooltip programatically? - qml

Is there a way to make a plasmoid tooltip to show/hide programatically?
I tried by setting a ToolTipArea over the compact representation, and trying to trigger it with a Timer - it does not work (the regular tooltip keeps showing but only when hovering the plasmoid icon (aka compactRepresentation):
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
Layout.preferredWidth: 200
Layout.preferredHeight: 300
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
Plasmoid.compactRepresentation: Item
{
anchors.fill: parent
MouseArea
{
onClicked:
{
plasmoid.expanded = !plasmoid.expanded
}
}
PlasmaCore.ToolTipArea
{
id: toolTip
width: parent.width
height: parent.height
anchors.fill: parent
mainItem: tooltipContentItem
active: false
interactive: true
}
Timer
{
interval: 3000
running: true
repeat: true
onTriggered:
{
if (tooltipContentItem.active == false)
{
toolTip.showToolTip()
toolTip.active == true
}
else
{
toolTip.hideToolTip()
toolTip.active == false
}
}
}
}
Item
{
id: tooltipContentItem
implicitWidth: 300
implicitHeight: 200
ColumnLayout
{
id: mainLayout
anchors
{
left: parent.left
top: parent.top
margins: PlasmaCore.Units.gridUnit / 2
}
PlasmaExtras.Heading
{
id: tooltipMaintext
level: 3
Layout.minimumWidth: Math.min(implicitWidth, preferredTextWidth)
Layout.maximumWidth: preferredTextWidth
elide: Text.ElideRight
text: "Test"
}
PlasmaComponents.Label
{
id: tooltipSubtext
Layout.minimumWidth: Math.min(implicitWidth, preferredTextWidth)
Layout.maximumWidth: preferredTextWidth
text: "Testing text"
opacity: 0.6
}
}
}
}
There's the toolTipItem QQuickItem too, but I cannot figure out if it is possible to make it show or hide on command (this bit was borrowed from KDE's digitalclock plasmoid:
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
Layout.preferredWidth: 200
Layout.preferredHeight: 300
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
Plasmoid.compactRepresentation: Item
{
anchors.fill: parent
MouseArea
{
onClicked:
{
plasmoid.expanded = !plasmoid.expanded
}
}
}
plasmoid.toolTipItem: Loader
{
id: toolTipLoader
source: "Tooltip.qml" // Just holds the tooltip contents
}
}

Related

Storing a user's code in a combo box that calls out for its name when selected

I want to make two input text fields (let's call them X and Y) that are in page A,
X: code of the person, Y: name of the person,
Page A contains two text fields for input, and a combo box for selection (for delete purpose), an adding button, and a delete button,
Once the X and Y are filled in the text fields they are inputed using an 'add' button, I want them to be stored when the button is pressed so I can call them back in the page B, or in the combo box in page A,
Page B contains a combo box and a casual text output next to it, the X goes to the combo box, and the Y goes to the text that both are in page B
When I select in page B one X of the many X that already have been inputed, I want the text to change with what have been selected accordingly,
if I want to delete one of the X, I do so by selecting the combobox that exists in Page A and proceed pressing the delete button,
how to store both the X and Y in variables and insert them in comboboxes and the texts, and make a bond between them, connecting each name with its own code ?
PageA
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.VirtualKeyboard 2.14
Item {
id:pageA
width: 1920
height: 1080
property alias codeIn: code.text
property alias nameIn: name.text
TextField{
id:code
y: 0
width: 200
height: 50
placeholderText: qsTr("Type the code here")
}
TextField{
id:name
x: 0
y: 65
width: 200
height: 50
placeholderText: qsTr("Type the name here")
}
ComboBox{
id:selectionForDelete
x: 320
y: 65
width: 200
height: 50
}
Button{
id:adding
x: 29
y:155
text: "add"
onClicked: {
code.clear()
name.clear()
}
}
Button{
id:deleting
x: 355
y: 155
text: "delete"
}
}
PageB
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.VirtualKeyboard 2.14
Item {
id:pageB
width: 1920
height: 1080
ComboBox{
id:codeList
}
Text {
id: relatedName
y:70
text: qsTr("")
}
}
One very simple solution is to declare a ListModel in your main app and when you instantiate either PageA or PageB they will have read/write access to the ListModel.
//MainApp.qml
Page {
ListModel { id: listModel }
PageA { }
PageB { }
}
//PageA.qml
Page {
}
//PageB.qml
Page {
}
As an example, PageA gives the ability to add new users as well as delete existing users, whereas PageB gives the ability to search for existing users:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
RowLayout {
anchors.fill: parent
PageA {
Layout.fillWidth: true
Layout.preferredWidth: 200
Layout.fillHeight: true
}
PageB {
Layout.fillWidth: true
Layout.preferredWidth: 200
Layout.fillHeight: true
}
}
ListModel {
id: listModel
function appendUser(code, name) { append( { code, name } ); }
}
}
//PageA.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
ColumnLayout {
anchors.fill: parent
Frame {
Layout.fillWidth: true
Text { text: qsTr("PageA") }
}
Label { text: qsTr("Users") }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: listModel
delegate: Frame {
width: ListView.view.width
RowLayout {
width: parent.width
Text {
Layout.fillWidth: true
text: model.code + " " + model.name
}
Button {
text: qsTr("Delete")
onClicked: listModel.remove(model.index)
}
}
}
}
Label { text: qsTr("Create new user") }
TextField {
id: code
Layout.fillWidth: true
placeholderText: qsTr("Code")
}
TextField {
id: name
Layout.fillWidth: true
placeholderText: qsTr("Text")
}
Button {
enabled: code.text && name.text
text: qsTr("Add")
onClicked: listModel.appendUser(code.text, name.text)
}
}
}
//PageB.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
ColumnLayout {
anchors.fill: parent
Frame {
Layout.fillWidth: true
Text { text: qsTr("PageB") }
}
Label { text: qsTr("Select Code") }
ComboBox {
id: comboBox
model: listModel
textRole: "code"
valueRole: "name"
}
Label { text: qsTr("Selected Name") }
Text {
text: comboBox.currentValue ?? ""
}
Item {
Layout.fillHeight: true
}
}
}
You can Try it Online!

How can I make a custom delegate for my ListView?

I'm trying to make a custom ListView (AppDataListView) that can be used for data manipulation (essentially having a bunch of inputs). The problem I'm having is finding a way to tell AppDataListView what input types to use in the delegate of the ListView.
I currently try and do this by creating a loader in the ListView delegate, setting its source to a property of type Component, and then when I create an instance of AppDataListView, I specify the Component... However, I don't have any access to the model data, so it's kind of pointless.
Does anyone know how I can accomplish this?
Main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick .Controls 2.12
import QtQuick.Layouts 1.12
Window {
width: 640
height: 480
visible: true
ListModel {
id: sampleData
ListElement {
itemId: 1
name: "Name1"
}
ListElement {
itemId: 2
name: "Name2"
}
ListElement {
itemId: 3
name: "Name3"
}
ListElement {
itemId: 4
name: "Name4"
}
}
AppDataListView {
anchors.fill: parent
headers: ["ID", "Name"]
model: sampleData
delegate: Component {
RowLayout {
anchors.fill: parent
TextArea {
// I can't access itemId from here even though this is loaded into the delegate.
text: itemId
}
TextArea {
// I can't access name from here even though this is loaded into the delegate.
text: name
}
}
}
}
}
AppDataListView.qml
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Rectangle {
property var headers: []
property alias model: listView.model
property alias listView: listView
required property Component delegate;
id: root
color: "#bdbdbd"
ColumnLayout {
anchors.fill: parent
anchors.margins: 1
spacing:0
RowLayout {
spacing: 1
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Item {
Layout.minimumWidth: 30
Layout.maximumWidth: 30
}
Repeater {
id: headerRepeater
model: headers
delegate: Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
gradient: Gradient {
GradientStop { position: 0.0; color: "#FFFFFF" }
GradientStop { position: 0.5; color: "#F1F1F1" }
GradientStop { position: 1.0; color: "#FFFFFF" }
}
Label {
text: modelData
padding: 5
anchors.centerIn: parent
}
}
}
}
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
interactive: true
clip: true
boundsBehavior: Flickable.StopAtBounds
spacing: 1
ScrollBar.vertical: ScrollBar {
active: true
policy: ScrollBar.AlwaysOn
}
delegate: RowLayout {
width: parent.width
spacing: 1
Button {
id: rowBtn
Layout.minimumWidth: 30
Layout.maximumWidth: 30
background: Rectangle {
gradient: Gradient {
GradientStop { position: 0.0; color: (rowBtn.down ? "#56aff5" : rowBtn.hovered ? "#d9ebf9" : "#FFFFFF") }
GradientStop { position: 0.5; color: (rowBtn.down ? "#1b93f1" : rowBtn.hovered ? "#a4b2bd" : "#F1F1F1") }
GradientStop { position: 1.0; color: (rowBtn.down ? "#56aff5" : rowBtn.hovered ? "#d9ebf9" : "#FFFFFF") }
}
}
}
Loader {
sourceComponent: root.delegate
}
}
}
}
}
Capturing #Amfasis excellent comments to the question and adding some more detail....
Change your Loader reference to this:
Loader {
sourceComponent: root.delegate
property int itemId: model.itemId
property string name: model.name
}
fixes it. Here's why....
A Component declaration is put into the QML namespace hierarchy where it is declared not where it is instantiated at runtime. In other words, by declaring the delegate within main.qml, it can only see that namespace regardless of where it is instantiated at (in this case in AppDataListView).
More info here:
https://doc.qt.io/qt-5/qml-qtqml-component.html#creation-context
As #Amfasis pointed out, the workaround in this case is to declare properties on the Loader to pass in the model references you need. In this case the Loader acts as a bridge of sorts from the ListView namespace over to the delegate Component's namespace in main.qml.
More info on that here:
https://doc.qt.io/qt-5/qml-qtquick-loader.html#using-a-loader-within-a-view-delegate

QML ListView delegate with Component Row does't render correctly

And now I have a problem with my qml script. here's the simple code:
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: root
anchors.fill: parent
color: "green"
SystemPalette { id: activePalette }
ColumnLayout {
id: rightPanel
Layout.fillHeight: true
Layout.fillWidth: true
Layout.rightMargin: 10
anchors.fill: parent
Component.onCompleted: {
console.log(this, width, parent, parent.width)
}
ListView {
spacing: 2
Layout.fillHeight: true
Layout.fillWidth: true
model: ListModel {
ListElement {
name: "nihao"
value: "1"
}
ListElement {
name: "fds"
value: "2"
}
ListElement {
name: "fdssd"
value: "4"
}
}
delegate: Component {
// Rectangle {
// color: "yellow"
// height: 40
// width: parent.width
Row {
anchors.fill: parent
spacing: 2
height: 40
width: 200
Rectangle {
color: activePalette.window
height: 25
width: 100
border.color: "white"
border.width: 3
Text {
anchors.centerIn: parent
text: name
}
}
Rectangle {
color: activePalette.window
height: 25
width: 100
border.color: "white"
border.width: 3
Text {
anchors.centerIn: parent
text: value
}
}
}
//}
}
}
}
}
}
The code does't display correctly when I use qmlscene to render it, it even render nothing if the ListModel is too long.
But, if I uncomment out the "Rectangle" code in delegate component, it works well. So I'm comfused with the difference between Reactangle and Row for that they are all inherited from Item. And what should be placed into the delegate component as its direct child?

display text in tableviewcolumn in treeView QtQuick controls 1.4

Im trying to create a simple treeView appeared in Qt 5.5 , the problem is that the text in items of the tree doesn't display, despite the model is full.
There is my code :
TreeViewPM.qml
Qt Code:
Switch view
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQml.Models 2.2
import KMTreeModelPM 1.0
Item {
KMTreeModelPM {
id: treeModel
}
ItemSelectionModel {
id: sel
model: treeModel
}
Text {
id:txt
text: " "
}
TreeView {
id: view
anchors.fill: parent
anchors.margins: 12
selection: sel
headerVisible : false
itemDelegate: Rectangle {
color: ( styleData.row % 2 == 0 ) ? "white" : "lightblue"
height: 20
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left // by default x is set to 0 so this had no effect
text: styleData.value
}
}
TableViewColumn {
id : title
title: "Title"
role: "title"
resizable: true
horizontalAlignment : Text.AlignLeft
}
model: treeModel
onDoubleClicked: txt.text = treeModel.data(index,0)
}
}
To copy to clipboard, switch view to plain text mode
main.qml
Qt Code:
Switch view
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQml.Models 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
Rectangle {
width: 785
TabView {
x: 17
y: 8
width: 970
height: 800
currentIndex: 2
visible: true
Tab {
id: tabAddProfile
title: qsTr("Add Profile")
AddProfilePage{}
}
Tab {
id: tabAddTypeSubType
title: qsTr("Add Type/SubType")
AddTypeSubTypePage{}
}
Tab {
id: tabAddDetail
height: 413
visible: true
title: qsTr("Add Detail")
TreeViewPM {}
}
}
}
It's probably your model. It's hard to know when we don't have access to it.
The following works:
#include <QGuiApplication>
#include <QtQml>
#include <QDebug>
#include <QtGui>
static void initStandardTreeModel(QStandardItemModel *model)
{
QStandardItem *item;
item = new QStandardItem(QLatin1String("Row 1 Item"));
model->insertRow(0, item);
item = new QStandardItem(QLatin1String("Row 2 Item"));
item->setCheckable(true);
model->insertRow(1, item);
QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
item->setChild(0, childItem);
item = new QStandardItem(QLatin1String("Row 3 Item"));
item->setIcon(QIcon());
model->insertRow(2, item);
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QStandardItemModel* model = new QStandardItemModel();
initStandardTreeModel(model);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("theModel", model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml:
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
width: 800
height: 400
visible: true
TreeView {
id: view
anchors.fill: parent
anchors.margins: 12
TableViewColumn {
id : title
title: "Title"
role: "display"
}
model: theModel
}
}

How to highlight the clicked (by mouse) element of a delegate w.r.t FolderListModel?

import QtQuick 2.0
import Qt.labs.folderlistmodel 2.0
Item
{
Component {
id: highlight
Rectangle {
id: rooot
width: 180; height: 20
color: ListView.isCurrentItem ? "black" : "red"; radius: 5
y: list.currentItem.y
Behavior on y {
SpringAnimation {
spring: 3
damping: 0.2
}
}
}
}
ListView {
id: list
width: 480; height: 400
model: folderModel
delegate: Text { id: h; text: fileName }
highlight: highlight
highlightFollowsCurrentItem: false
focus: true
}
FolderListModel
{
id: folderModel
folder: "/home/anisha/"
nameFilters: ["*"]
}
}
This works only when I use keyboard. How to make it work on mouse clicks?
To react on mouse events you need to place MouseArea item.
In the sample below (being an expanded version of the code you provided) I have added a MouseArea to the delegate item that upon being clicked sets the ListView's currentIndex to the delegate's index (a special property visible in the ListView's delegate).
import QtQuick 2.0
import Qt.labs.folderlistmodel 2.0
Item
{
Component {
id: highlight
Rectangle {
id: rooot
width: 180; height: 20
color: ListView.isCurrentItem ? "black" : "red"; radius: 5
y: list.currentItem.y
Behavior on y {
SpringAnimation {
spring: 3
damping: 0.2
}
}
}
}
ListView {
id: list
width: 480; height: 400
model: folderModel
delegate:
Text {
id: h;
text: fileName
MouseArea {
anchors.fill: parent
onClicked: list.currentIndex = index
}
}
highlight: highlight
highlightFollowsCurrentItem: false
focus: true
}
FolderListModel
{
id: folderModel
folder: "/home/anisha/"
nameFilters: ["*"]
}
}
As an alternative approach you might try placing a single MouseArea filling the whole ListView and use ListView's indexAt(int x, int y) method to check which delegate was clicked. However, you would need to care about more edge-conditions in such case.