QML does not update when C++ Abstract Model Updates
-
Hello,
I am working on a control application for an eight channel preamplifier and am having some troubles integrating QML and C++. I have an object representing the unit with eight child objects that represent the individual channels. I am displaying the the channels as a list view, but cannot get the display to update when the channel objects are modified. For example, I have bound a few boolean variables to button checked properties. When I toggle the values in the C++ model (reimplemented QAbstractListModel), the button states do not change until I force the ListView to redraw itself by shrinking the window and re-maximizing it. I originally attempted to use the built-in functionality of the QAbstractListModel to handle the updates, but had not success. To get to the point I am at, I have implemented a series of signals moving up the object tree until a call can be made to the C++ class to change the fields. To make the changes go the other way, I have manually sent signals to the QML and have been able to get the preamp status pane to update real time. Unfortunately I have been unable to do the same for the Channel List View. Below is some of the source for the project. Thanks in advance for any help you can provide!
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <qqmlcontext.h> #include <qqml.h> #include <iostream> #include <QDebug> #include <QQuickView> #include <QQmlComponent> #include <QTimer> #include "preampmodel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QTextStream cin(stdin); QQmlApplicationEngine engine; QQmlContext* context = engine.rootContext(); PreampModel * preamps = new PreampModel(); context->setContextProperty("preampModel", preamps); engine.load(QUrl(QStringLiteral("qrc:/MainForm.qml"))); return app.exec(); }
preampmodel.cpp
/* Class: PreampModel * Author: JLimbocker * Description: This class inherits QAbstractListModel to present data to the QML user interface. * It contains eight channels and seven configuration fields. Each of the eight channels has * eleven roles which are accessed through role names. The seven configuration fields are accessed * through role names regardless of which index is selected. This class will be updated when changes * are made in QML and when changes are made in C++. All changes should be reflected both in QML and * in C++. */ #include "preampmodel.h" #include "channel.h" #include <QAbstractListModel> #include <string> #include <QDebug> PreampModel::PreampModel(QObject * parent) : QAbstractListModel(parent) { preampID = 1; online = true; clkStatus = false; sampleRate = 2; clkSource = 1; outFormat = 0; clkOutSource = 0; for(int i = 0; i < 8; i++) channelList.append(new Channel((preampID-1)*8+(1+i), QString("Channel_" + (preampID-1)*8+1), true, false, true, true, 1, 23)); } PreampModel::~PreampModel() { } /* void PreampModel::print() * This function prints debug information for the object * Returns: void * Parameters: none */ void PreampModel::print() { qDebug() << "PreampID : "; qDebug() << preampID; qDebug() << "\nonline : "; qDebug() << online; qDebug() << "\nclkStatus : "; qDebug() << clkStatus; qDebug() << "\nsampleRate : "; qDebug() << sampleRate; qDebug() << "\nclkSource : "; qDebug() << clkSource; qDebug() << "\noutFormat : "; qDebug() << outFormat; qDebug() << "\nclkOutSrc : "; qDebug() << clkOutSource; qDebug() << "\n"; } /* roleNames() * This function is reimplemented from QAbstractItemModel. * It provides role names to the QML engine. * Returns: roles - a Hash relating the role to the role name * Parameters: none */ QHash<int, QByteArray> PreampModel::roleNames() const { QHash<int, QByteArray> roles; roles[idRole] = "preampID"; roles[onlineRole] = "online"; roles[clkStatusRole] = "clkStatus"; roles[sampleRateRole] = "sampleRate"; roles[clkSourceRole] = "clkSource"; roles[outFormatRole] = "outFormat"; roles[clkOutSourceRole] = "clkOutSource"; roles[phantomRole] = "phantom"; roles[phaseRole] = "phase"; roles[ribbonRole] = "ribbon"; roles[groupRole] = "group"; roles[groupNameRole] = "groupName"; roles[gainRole] = "gain"; roles[nameRole] = "name"; roles[numberRole] = "number"; roles[meterLevelRole] = "meterLevel"; roles[peakValueRole] = "peakValue"; roles[scribbleStripRole] = "scribbleStrip"; return roles; } /* data(index, role) * This function is reimplemented from QAbstractItemModel. * It provides access to the model data for the QML Engine. * If Index is out of range or the chosen role is not supported, * it returns an empty QVariant. * Returns: A QVariant containing the desired data, if available. * Parameters: index - the index of the data to be accessed * role - the role of the data to be accessed */ QVariant PreampModel::data(const QModelIndex &index, int role) const { if(index.row() < channelList.size() && index.row() >= 0) switch (role){ case idRole : return preampID; case onlineRole : return online; case clkStatusRole : return clkStatus; case sampleRateRole : return sampleRate; case clkSourceRole : return clkSource; case outFormatRole : return outFormat; case clkOutSourceRole : return clkOutSource; case phantomRole : return channelList[index.row()]->getPhantom(); case phaseRole : return channelList[index.row()]->getPhase(); case ribbonRole : return channelList[index.row()]->getRibbon(); case groupRole : return channelList[index.row()]->getGroup(); case groupNameRole : return channelList[index.row()]->getGroupName(); case gainRole : return channelList[index.row()]->getGain(); case nameRole : return channelList[index.row()]->getName(); case numberRole : return channelList[index.row()]->getNumber(); case meterLevelRole : return channelList[index.row()]->getMeterLevel(); case peakValueRole : return channelList[index.row()]->getPeakValue(); case scribbleStripRole : return channelList[index.row()]->getScribbleStrip(); default: return QVariant(); } else return QVariant(); } /* rowCount(index) * This function is reimplemented from QAbstractItemModel. * It provides a count of the number of rows in the model. * In the case of this implementation, there are only eight * different indices - one per preamp channel. * Returns: 8 - the number of channels in the preamp. * Parameters: index - unused */ int PreampModel::rowCount(const QModelIndex & index) const { return 8; } /* setData(index, value, role) * This function is reimplemented from QAbstractItemModel. * It provides an interface for the QML engine to set data * fields in the object. * Returns: True if data has been set, False otherwise. * Parameters: index - the index of the data to be set * value - the value to which the data should be set * role - the role of the data to be set */ bool PreampModel::setData(const QModelIndex & index, const QVariant & value, int role) { if(index.row() < channelList.size() && index.row() >= 0) { switch (role){ case idRole : preampID = value.toInt(); break; case onlineRole : online = value.toBool();break; case clkStatusRole : clkStatus = value.toBool();break; case sampleRateRole : sampleRate = value.toInt();break; case clkSourceRole : clkSource = value.toInt();break; case outFormatRole : outFormat = value.toInt();break; case clkOutSourceRole : clkOutSource = value.toInt();break; case phantomRole : channelList[index.row()]->setPhantom(value.toBool());break; case phaseRole : channelList[index.row()]->setPhase(value.toBool());break; case ribbonRole : channelList[index.row()]->setRibbon(value.toBool());break; case groupRole : channelList[index.row()]->setGroup(value.toBool());break; case groupNameRole : channelList[index.row()]->setGroupName(value.toInt());break; case gainRole : channelList[index.row()]->setGain(value.toInt());break; case nameRole : channelList[index.row()]->setName(value.toString());break; case numberRole : channelList[index.row()]->setNumber(value.toInt());break; case meterLevelRole : channelList[index.row()]->setMeterLevel(value.toInt());break; case peakValueRole : channelList[index.row()]->setPeakValue(value.toInt());break; case scribbleStripRole : channelList[index.row()]->setScribbleStrip(value.toString()); break; default: return false; } qDebug() << "emitting datachanged"; //If data has been changed, send signal to notify QML Engine emit dataChanged(index, index); return true; } else return false; } /* index(row, column, parent) * This function is reimplemented from QAbstractItemModel. * It created an index for the given row and column. * Returns: the index corresponding to the row and column * Parameters: row - the row at whic the item is located. * column - the column at which the item is located. */ QModelIndex PreampModel::index(int row, int column, const QModelIndex &parent) const { return QAbstractItemModel::createIndex(row, column); } /* setProperty(_index, name, value) * This function provides manual property setting from QML. * Returns: True if successful, false if unsuccessful. * Parameters: _index - the row to be accessed * name - the role name to be accessed * value - the value to write */ bool PreampModel::setProperty( const QVariant _index, const QString name, const QVariant value) { QModelIndex index = PreampModel::index(_index.toInt(), 0, QModelIndex()); qDebug() << index.row() << " " << name << " " << value << channelList.size(); if(index.row() < channelList.size() && index.row() >= 0) { if(name == QString::fromUtf8("idRole")) { preampID = value.toInt(); } else if(name == QString::fromUtf8("onlineRole")) { online = value.toBool(); } else if(name == QString::fromUtf8("clkStatusRole")) { clkStatus = value.toBool(); } else if(name == QString::fromUtf8("sampleRateRole")) { sampleRate = value.toInt(); } else if(name == QString::fromUtf8("clkSourceRole")) { clkSource = value.toInt(); } else if(name == QString::fromUtf8("outFormatRole")) { outFormat = value.toInt(); } else if(name == QString::fromUtf8("clkOutSourceRole")) { clkOutSource = value.toInt(); } else if(name == QString::fromUtf8("phantomRole")) { channelList[index.row()]->setPhantom(value.toBool()); } else if(name == QString::fromUtf8("phaseRole")) { channelList[index.row()]->setPhase(value.toBool()); } else if(name == QString::fromUtf8("groupRole")) { channelList[index.row()]->setGroup(value.toBool()); } else if(name == QString::fromUtf8("ribbonRole")) { channelList[index.row()]->setRibbon(value.toBool()); } else if(name == QString::fromUtf8("groupNameRole")) { channelList[index.row()]->setGroupName(value.toInt()); } else if(name == QString::fromUtf8("gainRole")) { channelList[index.row()]->setGain(value.toInt()); } else if(name == QString::fromUtf8("nameRole")) { channelList[index.row()]->setName(value.toString()); } else if(name == QString::fromUtf8("scribbleStripRole")) { channelList[index.row()]->setScribbleStrip(value.toString()); } else { qDebug() << "Property Set Failed: Unknown Role"; return false; } emit dataChanged(index, index); qDebug() << name << " changed"; return true; } else { qDebug() << "Property Set Failed: Index out of Bounds"; return false; } } /* flags(index) * This function is reimplemented from QAbstractItemModel. * It tells the qml that all items are editable and selectable. * Returns: An OR combination of the necessary flags. * Parameters: index - unused. */ Qt::ItemFlags PreampModel::flags(const QModelIndex &index) const { return Qt::ItemIsEditable | Qt::ItemIsSelectable; }
channel.cpp
Channel::Channel(QObject *parent) : QObject(parent) { phantom = false; phase = true; ribbon = false; group = false; groupName = 0; gain = 49; name = "Channel"; number = 0; meterLevel = 0; peakValue = 0; scribbleStrip = ""; } Channel::Channel(int chNum, QString chName, QObject *parent) : QObject(parent) { number = chNum; name = chName; meterLevel = 0; peakValue = 0; scribbleStrip = ""; phantom = false; phase = true; ribbon = false; group = false; groupName = 0; gain = 49; } Channel::Channel(int chNum, QString chName, bool phant, bool pha, bool rib, bool grp, int grpNam, int gn, QObject *parent) : QObject(parent) { number = chNum; name = chName; meterLevel = 0; peakValue = 0; scribbleStrip = ""; phantom = phant; phase = pha; ribbon = rib; group = grp; groupName = grpNam; gain = gn; } //Setters void Channel::setPhantom(bool newPhantom) { phantom = newPhantom; emit phantomChanged(); } void Channel::setPhase(bool newPhase) { phase = newPhase; qDebug() << "Phase changed at channel level"; emit phaseChanged(); } void Channel::setRibbon(bool newRibbon) { ribbon = newRibbon; emit ribbonChanged(); } void Channel::setGroup(bool newGroup) { group = newGroup; emit groupChanged(); } void Channel::setGroupName(int newGroupName) { groupName = newGroupName; emit groupNameChanged(); } void Channel::setGain(int newGain) { gain = newGain; emit gainChanged(); } void Channel::incrementGain() { gain++; emit gainChanged(); } void Channel::decrementGain() { gain--; emit gainChanged(); } void Channel::setName(QString newName) { name = newName; emit nameChanged(); } void Channel::setNumber(int newNumber) { number = newNumber; emit numberChanged(); } void Channel::setMeterLevel(int newLevel) { meterLevel = newLevel; emit meterLevelChanged(); } void Channel::setPeakValue(int newValue) { peakValue = newValue; emit peakValueChanged(); } void Channel::setScribbleStrip(QString newString) { scribbleStrip = newString; emit scribbleStripChanged(); } void Channel::setAll() { } //Getters bool Channel::getPhantom() { return phantom; } bool Channel::getPhase() { return phase; } bool Channel::getRibbon() { return ribbon; } bool Channel::getGroup() { return group; } int Channel::getGroupName() { return groupName; } int Channel::getGain() { return gain; } QString Channel::getName() { return name; } int Channel::getNumber() { return number; } int Channel::getMeterLevel() { return meterLevel; } int Channel::getPeakValue() { return peakValue; } QString Channel::getScribbleStrip() { return scribbleStrip; }
QML in follow-up post
JL
-
Preamp.qml
import QtQuick 2.7 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.0 Rectangle { id: pre property var devName: "preamp"; property int devID: 0; property int clkSource property int clkOutSource property int outFormat property int sampleRate property bool online property bool clkStatus property variant channelModel property int startChNum: (devID-1)*8 + 1; signal channelChange(var index, var prop, var value) height: 410 width: parent.width color: "#00000000" ListView { Component.onCompleted: { currentIndex = 0; } id: channelView anchors.left: parent.left anchors.right: status.left anchors.rightMargin: 12 contentWidth: 1488 contentHeight: 400 boundsBehavior: Flickable.StopAtBounds flickableDirection: Flickable.AutoFlickIfNeeded orientation: ListView.Horizontal interactive: true spacing: 12 delegate: Channel { id: ch channelID: model.number; channelName: model.name; gainVal: model.gain; phantom: model.phantom; phase: model.phase; ribbon: model.ribbon; group: model.group; groupName: model.groupName; meterLevel: model.meterLevel; scribbleStrip: model.scribbleStrip; onPhantomChanged: { pre.channelChange(model.modelIndex, "phantomRole", phantom) channelView.currentIndex = index; } onPhaseChanged: { pre.channelChange(index, "phaseRole", phase) channelView.currentIndex = index; } onGroupChanged: { pre.channelChange(index, "groupRole", group) channelView.currentIndex = index; } onRibbonChanged: { pre.channelChange(index, "ribbonRole", ribbon) channelView.currentIndex = index; } onGroupNameChanged: { pre.channelChange(index, "groupNameRole", groupName) channelView.currentIndex = index; } onGainValChanged: { pre.channelChange(index, "gainRole", gainVal) channelView.currentIndex = index; } onChannelNameChanged: { pre.channelChange(index, "nameRole", channelName) channelView.currentIndex = index; } onScribbleStripChanged: { pre.channelChange(index, "scribbleStripRole", scribbleStrip) channelView.currentIndex = index; } } model: channelModel ScrollBar.horizontal: ScrollBar { } } Preamp_status { id: status anchors.top: parent.top anchors.right: parent.right anchors.rightMargin: 6 anchors.leftMargin: 12 online: parent.online clkStatus: parent.clkStatus clkSource: parent.clkSource clkOutSource: parent.clkOutSource sampleRate: parent.sampleRate outFormat: parent.outFormat devID: parent.devID onSampleRateChanged: { pre.channelChange(channelView.CurrentIndex, "sampleRateRole", sampleRate) } onOnlineChanged: { pre.channelChange(channelView.currentIndex, "onlineRole", online) } onClkStatusChanged: { pre.channelChange(channelView.currentIndex, "clkStatusRole", clkStatus) } onClkSourceChanged: { pre.channelChange(channelView.currentIndex, "clkSourceRole", clkSource) } onClkOutSourceChanged: { pre.channelChange(channelView.currentIndex, "clkOutSourceRole", clkOutSource) } onOutFormatChanged: { pre.channelChange(channelView.currentIndex, "outFormatRole", outFormat) } } }
MainForm.qml
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Window 2.2 Window { id:top visible: true Connections { target: preampModel onDataChanged:{ preamp1.devID = preampModel.preampID; preamp1.devName = ""; preamp1.clkSource = preampModel.clkSource preamp1.clkOutSource = preampModel.clkOutSource preamp1.outFormat =preampModel.outFormat preamp1.sampleRate = preampModel.sampleRate preamp1.online = preampModel.online preamp1.clkStatus = preampModel.clkStatus preamp1.channelModel = preampModel preamp1.updated(); } } Rectangle { id: main objectName: "mainRect" anchors.fill: parent color: "#505050" Rectangle { id: navBar anchors.top: parent.top width: parent.width*(7/12) height: 60 z: 10 color: "#000000" Row { id: row1 x: parent.x y: parent.y width: parent.width height: parent.height Rectangle { id: preampsBtn width: parent.width/3 height: parent.height color: parent.parent.color Text { id: preampTxt x: 40 y: 9 width: 240 height: 43 color: "#ffffff" text: qsTr("Preamp") font.pixelSize: 26 anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } MouseArea { id: mouseArea_preamps width: 100 height: 100 anchors.fill: parent } } Rectangle { id: mixerBtn width: parent.width/3 height: parent.height color: parent.parent.color Text { id: mixerTxt x: 40 y: 9 width: 240 height: 43 color: "#ffffff" text: "Mixer" font.pixelSize: 26 anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } MouseArea { id: mouseArea_mixer width: 100 height: 100 anchors.fill: parent } } Rectangle { id: setupBtn width: parent.width/3 height: parent.height color: parent.parent.color Text { id: setupTxt x: 40 y: 9 width: 240 height: 43 color: "#ffffff" text: qsTr("Setup") font.pixelSize: 26 anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } MouseArea { id: mouseArea_setup width: 100 height: 100 anchors.fill: parent } } } } Rectangle { id: presetBar x: parent.width - width y: 0 width: parent.width *(5/12)-20 height: 60 z:10 color: "#000000" Row { id: row2 x: 268 y: 24 width: 200 height: 400 anchors.fill: parent Rectangle { id: rectangle1 width: parent.width*(3/14) height: parent.height color: parent.parent.color Text { id: text4 color: "#ffffff" text: qsTr("Preset") font.pixelSize: 26 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter anchors.fill: parent } } Rectangle { id: rectangle2 width: parent.width*(5/14) height: parent.height color: parent.parent.color ComboBox { id: presetBox y: 3 model: presetList anchors.fill:parent anchors.margins: 3 Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { presetBox.focus = false } } contentItem: Text { color : "#496c89" text: presetBox.displayText font.family: "Arial"; font.pixelSize: 26; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter; } background: Rectangle{ color: "#16161d" } indicator: Rectangle { } delegate: ItemDelegate { width: presetBox.width contentItem: Text { text: modelData; horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 26; color: "#7a9cb8" } onClicked: { presetBox.currentIndex = index preamplistview.currentIndex = index presetBox.focus = false } } popup: Popup { id: preampPopup width: parent.width height: preamplistview.contentHeight margins: 0 background: Rectangle { color: "#16161d" } contentItem: ListView { id: preamplistview anchors.fill: parent model: presetBox.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex: presetBox.highlightedIndex delegate: presetBox.delegate } enter: Transition { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to: preampPopup.parent.height*preampPopup.parent.count } } exit: Transition { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: preampPopup.parent.height*preampPopup.parent.count; to: 0 } } } textRole: "key" ListModel { id: presetList ListElement { key: "Defaults"; } ListElement { key: "Preset 1"; } ListElement { key: "Preset 2"; } } } } Rectangle { id: rectangle3 width: parent.width*(3/14) height: parent.height color: parent.parent.color Text { id: text5 x: 277 y: 23 color: "#ffffff" text: qsTr("store") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter anchors.fill: parent font.pixelSize: 26 } } Rectangle { id: rectangle4 width: parent.width*(3/14) height: parent.height color: parent.parent.color Text { id: text6 color: "#ffffff" text: qsTr("recall") anchors.fill: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pixelSize: 26 } } } } function updateModel(index, role, value) { preampModel.setProperty(index, role, value) //console.log("Model Updated") } Preamp { id: preamp1 devID: preampModel.preampID; devName: ""; clkSource: preampModel.clkSource clkOutSource: preampModel.clkOutSource outFormat:preampModel.outFormat sampleRate: preampModel.sampleRate online: preampModel.online clkStatus: preampModel.clkStatus channelModel: preampModel anchors.right: parent.right anchors.rightMargin: 0 anchors.left: parent.left anchors.leftMargin: 6 anchors.top: navBar.bottom anchors.topMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 onChannelChange: { main.updateModel(index, prop, value) } } } }
-
Channel.qml
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtGraphicalEffects 1.0 Rectangle { id: channel property var gainVal: 49 property var gainDisp: valToDisp(gainVal) property var channelID: "#" property var channelName: "ChannelName" property var peakValue: false property var groupName property var group property var ribbon property var phantom property var phase property var meterLevel property var scribbleStrip onPhantomChanged: console.log("Delegate Phantom Changed") onPhaseChanged: console.log("Delegate Phase Changed") onGroupChanged: console.log("Group Changed") onRibbonChanged: console.log("Ribbon Changed") onGroupNameChanged: console.log("Group Name Changed") onGainValChanged: console.log("Gain Changed") function valToDisp(val) { return (val*1 <= 0) ? -6: val*1+1 } function updateGain(change) { gainVal = gainVal + change; if(gainVal > 68) gainVal = 68; if(gainVal < 0) gainVal = 0; gainSlider.value = gainVal; } function updateGainValue(value) { if(value*1 > 68) gainVal = 68; else if(value*1 < 0) gainVal = 0; else gainVal = value; gainSlider.value = gainVal; } DropShadow { id : channelShadow color: qsTr("#df000000") source: channel horizontalOffset: 2 verticalOffset: 4 samples: 6 radius: 3 cached: true anchors.fill: channel visible: channel.visible } width: 174 height: 399 color: "#00000000" Rectangle { id: rectangle1 x: 212 y: 133 width: 174 height: 344 color: "#496c89" anchors.rightMargin: 0 anchors.fill: parent GridView { id: gridView1 anchors.right: parent.right anchors.rightMargin: 0 anchors.left: parent.left anchors.leftMargin: 0 anchors.bottom: parent.bottom anchors.bottomMargin: 0 anchors.top: parent.top anchors.topMargin: 0 cellHeight: 70 cellWidth: 70 Rectangle { id: channelRect width: 120 height: 74 color: "#333240" anchors.top: parent.top anchors.topMargin: 6 anchors.right: meterRect.left anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 Text { id: channelIDField height: 31 color: "#ffffff" text: channelID anchors.right: parent.right anchors.rightMargin: 6 anchors.left: channelNameField.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 6 font.pixelSize: 30 font.bold: true horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } TextField { id: channelNameField text: channelName font.bold: false anchors.right: parent.right anchors.rightMargin: 3 anchors.left: parent.left anchors.leftMargin: 3 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: channelIDField.bottom anchors.topMargin: 0 font.pixelSize: 15 selectByMouse: true verticalAlignment: TextInput.AlignVCenter horizontalAlignment: TextInput.AlignLeft validator: RegExpValidator { regExp: /([A-Za-z0-9-_]{1,11})/; } background: channelNameBackgroundLoader.item color: focus ? "#26c9ff" : "#ffffff" selectionColor: "#26c9ff" selectedTextColor: "#ffffff" Component { id: nameFieldNormal Rectangle { color: "#333240" } } Component { id: nameFieldSelected Rectangle { color: "#636378" } } Loader { id: channelNameBackgroundLoader sourceComponent: nameFieldNormal } onFocusChanged: { if(focus) { selectAll(); channelNameBackgroundLoader.sourceComponent = nameFieldSelected } else { channelNameBackgroundLoader.sourceComponent = nameFieldNormal } } onEditingFinished: { channelName = text; text: channelName; focus = false; channelNameBackgroundLoader.sourceComponent = nameFieldNormal } } } Rectangle { id: gainRect x: 7 height: 153 color: "#333240" anchors.top: channelRect.bottom anchors.topMargin: 6 anchors.rightMargin: 0 anchors.leftMargin: 0 anchors.right: channelRect.right anchors.left: channelRect.left Text { id: gainLabel width: 40 color: "#ffffff" text: "Gain" anchors.bottom: gainUp.top anchors.bottomMargin: 6 font.pixelSize: 20 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 6 } TextField { id: gainDisplay text: gainDisp echoMode: TextInput.Normal anchors.left: gainLabel.right anchors.leftMargin: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.bottom: gainUp.top anchors.bottomMargin: 6 anchors.top: parent.top anchors.topMargin: 6 horizontalAlignment: Text.AlignHCenter verticalAlignment: TextInput.AlignVCenter font.pixelSize: 28 selectByMouse:true validator: IntValidator { bottom: -6; top: 69} //TODO Change behavior on entered fields background: gainDisplayBackgroundLoader.item color: focus ? "#26c9ff" : "#ffffff"; selectionColor: "#26c9ff" selectedTextColor: "#ffffff" Loader { id: gainDisplayBackgroundLoader sourceComponent: gainDisplayNormal } Component { id: gainDisplayNormal Rectangle { color: "#333240"; } } Component { id: gainDisplaySelected Rectangle { color: "#636378"; } } onFocusChanged: { if(focus) { selectAll(); gainDisplayBackgroundLoader.sourceComponent = gainDisplaySelected gainSlider.visible = true; } else { gainDisplayBackgroundLoader.sourceComponent = gainDisplayNormal; } } onEditingFinished: { gainSlider.visible = false; if(gainDisplay.text*1 < 0) { updateGainValue(0); } else if (gainDisplay.text*1 < 2) { updateGainValue(1); } else updateGainValue(gainDisplay.text*1 - 1); focus = false; gainDisplayBackgroundLoader.sourceComponent = gainDisplayNormal } } Button { id: gainUp y: 57 width: 90 height: 40 anchors.left: parent.left anchors.leftMargin: 6 anchors.horizontalCenterOffset: 0 anchors.horizontalCenter: parent.horizontalCenter background: gainUpBackgroundLoader.item contentItem: gainUpContentLoader.item Loader { id: gainUpBackgroundLoader sourceComponent: gainUpNormal } Loader { id: gainUpContentLoader sourceComponent: upArrow } Component { id: gainUpNormal Rectangle { gradient: Gradient { GradientStop { position: 0.0; color: "#69697C" } GradientStop { position: 1.0; color: "#424251" } } } } Component { id: gainUpClicked Rectangle { gradient: Gradient { GradientStop { position: 0.0; color: "#3e3e46" } GradientStop { position: 1.0; color: "#1f1f24" } } } } Component { id: upArrow Image { source: "Images/upArrow.png" width: 27 height: 20 fillMode: Image.Pad } } Component { id: upArrowClicked Image { source: "Images/upArrowClicked.png" fillMode: Image.Pad } } Timer { id: gainUpLongpress repeat: false running: false interval: 500 onTriggered: { gainUpRepeat.restart() } } Timer { id: gainUpRepeat repeat: true running: false interval: 250 onTriggered: { updateGain(1); } } MouseArea { id: mouseArea1 x: 18 y: 16 anchors.fill: parent hoverEnabled: true onPressed: { updateGain(1); gainUpLongpress.restart(); gainUpBackgroundLoader.sourceComponent = gainUpClicked gainUpContentLoader.sourceComponent = upArrowClicked } onReleased: { gainUpLongpress.stop(); gainUpRepeat.stop(); gainUpBackgroundLoader.sourceComponent = gainUpNormal gainUpContentLoader.sourceComponent = upArrow } onExited: { gainUpLongpress.stop(); gainUpRepeat.stop(); gainUpBackgroundLoader.sourceComponent = gainUpNormal gainUpContentLoader.sourceComponent = upArrow } onCanceled: { gainUpLongpress.stop(); gainUpRepeat.stop(); gainUpBackgroundLoader.sourceComponent = gainUpNormal gainUpContentLoader.sourceComponent = upArrow } } } Button { id: gainDown width: 90 height: 40 anchors.top: gainUp.bottom anchors.topMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.horizontalCenterOffset: 0 anchors.horizontalCenter: parent.horizontalCenter contentItem: gainDownContentLoader.item background: gainDownBackgroundLoader.item Loader { id: gainDownBackgroundLoader sourceComponent: gainDownNormal } Loader { id: gainDownContentLoader sourceComponent: downArrow } Component { id: gainDownNormal Rectangle { gradient: Gradient { GradientStop { position: 0.0; color: "#69697C" } GradientStop { position: 1.0; color: "#424251" } } } } Component { id: gainDownClicked Rectangle { gradient: Gradient { GradientStop { position: 0.00; color: "#3e3e46"; } GradientStop { position: 1.00; color: "#1f1e24"; } } } } Component { id: downArrow Image { source: "Images/downArrow.png" width: 27 height: 20 fillMode: Image.Pad } } Component { id: downArrowClicked Image { source: "Images/downArrowClicked.png" fillMode: Image.Pad } } Timer { id: gainDownLongpress repeat: false running: false interval: 500 onTriggered: { gainDownRepeat.restart() } } Timer { id: gainDownRepeat repeat: true running: false interval: 250 onTriggered: { updateGain(-1) } } MouseArea { id: mouseArea2 anchors.rightMargin: 0 anchors.bottomMargin: -1 anchors.leftMargin: 0 anchors.topMargin: 1 anchors.fill: parent hoverEnabled: true onPressed: { updateGain(-1); gainDownLongpress.restart(); gainDownBackgroundLoader.sourceComponent = gainDownClicked gainDownContentLoader.sourceComponent = downArrowClicked } onReleased: { gainDownLongpress.stop(); gainDownRepeat.stop(); gainDownBackgroundLoader.sourceComponent = gainDownNormal gainDownContentLoader.sourceComponent = downArrow } onExited: { gainDownLongpress.stop(); gainDownRepeat.stop(); gainDownBackgroundLoader.sourceComponent = gainDownNormal gainDownContentLoader.sourceComponent = downArrow } onCanceled: { gainDownLongpress.stop(); gainDownRepeat.stop(); gainDownBackgroundLoader.sourceComponent = gainDownNormal gainDownContentLoader.sourceComponent = downArrow } } } } Rectangle { id: groupRect y: 293 height: 43 color: "#333240" anchors.right: parent.right anchors.rightMargin: 6 anchors.left: channelRect.left anchors.leftMargin: 0 Button { id: btnGroup y: 3 width: 55 height: 33 text: qsTr("") checkable: true checked: group anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 6 background: groupLoader.item contentItem: Text { color: "#ffffff" text: "group" font.pixelSize: 16 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } onCheckedChanged: { if(checked) groupLoader.sourceComponent = grpStyleON else groupLoader.sourceComponent = grpStyleOFF } onClicked: { group = !group; } Loader { id: groupLoader sourceComponent: grpStyleOFF } Component { id: grpStyleON Rectangle { gradient: Gradient { GradientStop { position: 1; color: "#2db201" } GradientStop { position: 0; color: "#238c01" } } } } Component { id: grpStyleOFF Rectangle { gradient: Gradient { GradientStop { position: 0; color: "#69697C" } GradientStop { position: 1; color: "#424251" } } } } } ComboBox { id: groupSelect y: 3 width: 85 height: 33 model: groupList currentIndex: groupName anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 6 anchors.left: btnGroup.right anchors.leftMargin: 6 Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { groupSelect.focus = false } } contentItem: Text { color : "#ffffff" text: parent.displayText font.family: "Arial"; font.pixelSize: 16; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignLeft; } background: Rectangle{ color: "#424251" } indicator: Rectangle { } delegate: ItemDelegate { width: groupSelect.width contentItem: Text { text:modelData; horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 16; color: "#ffffff" } onClicked: { groupName = index groupSelect.focus = false } } popup: Popup { id: groupPopup width: groupSelect.width height:listview.contentHeight margins: 0 background: Rectangle { color: "#424251" } contentItem: ListView { id: listview anchors.fill: parent model: groupSelect.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex: groupSelect.highlightedIndex delegate: groupSelect.delegate } enter: Transition { SequentialAnimation { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to: listview.contentHeight } PropertyAction { properties: "contentItem.visible"; value: true } } } exit: Transition { SequentialAnimation{ PropertyAction { properties: "contentItem.visible"; value: false } PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: listview.contentHeight; to: 0 } } } } textRole: "key" ListModel { id: groupList ListElement { key: "Group 1"; } ListElement { key: "Group 2"; } ListElement { key: "Group 3"; } } } } Rectangle { id: configRect height: 44 color: "#333240" anchors.bottom: groupRect.top anchors.bottomMargin: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 Row { id: configRow spacing: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 Button { id: btnPhantom width: (parent.width-parent.spacing*2)/3 text: qsTr("") checkable: true checked: phantom anchors.bottom: parent.bottom anchors.bottomMargin: 0 anchors.top: parent.top anchors.topMargin: 0 background: phantomLoader.item contentItem: Text { color: "#ffffff" text: "48V" font.pixelSize: 16 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Loader { id: phantomLoader sourceComponent: phantomStyleOFF } onCheckedChanged: { if(checked) phantomLoader.sourceComponent = phantomStyleON else phantomLoader.sourceComponent = phantomStyleOFF } onClicked: { phantom = !phantom; checked = phantom; } Component { id: phantomStyleON Rectangle { gradient: Gradient { GradientStop { position: 1; color: "#d93600" } GradientStop { position: 0; color: "#8c2300" } } } } Component { id: phantomStyleOFF Rectangle { gradient: Gradient { GradientStop { position: 0; color: "#69697C" } GradientStop { position: 1; color: "#424251" } } } } } Button { id: btnPhase width: (parent.width-parent.spacing*2)/3 text: qsTr("") state: "OFF" checkable: true checked: phase anchors.bottom: parent.bottom anchors.top: parent.top anchors.bottomMargin: 0 anchors.topMargin: 0 contentItem: Text { color: "#ffffff" text: "Ø" font.pixelSize: 16 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } background: phaseLoader.item Loader{ id: phaseLoader sourceComponent: phaseStyleOFF } onCheckedChanged: { if(checked) phaseLoader.sourceComponent = phaseStyleON else phaseLoader.sourceComponent = phaseStyleOFF } onClicked: { phase = !phase; checked: phase; } Component { id: phaseStyleON Rectangle { gradient: Gradient { GradientStop { position: 1; color: "#d9a300" } GradientStop { position: 0; color: "#8c6900" } } } } Component { id: phaseStyleOFF Rectangle { gradient: Gradient { GradientStop { position: 0; color: "#69697C" } GradientStop { position: 1; color: "#424251" } } } } } Button { id: btnRibbon width: (parent.width-parent.spacing*2)/3 text: qsTr("") checkable: true checked: ribbon anchors.bottom: parent.bottom anchors.top: parent.top anchors.bottomMargin: 0 anchors.topMargin: 0 background: ribbonLoader.item contentItem: Text { color: "#ffffff" text: "RBN" font.pixelSize: 16 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Loader { id: ribbonLoader sourceComponent: ribbonStyleOFF } onCheckedChanged: { if(checked) ribbonLoader.sourceComponent = ribbonStyleON else ribbonLoader.sourceComponent = ribbonStyleOFF } onClicked: { ribbon = !ribbon; checked: ribbon; } Component { id: ribbonStyleON Rectangle { gradient: Gradient { GradientStop { position: 1; color: "#006dd9" } GradientStop { position: 0; color: "#00468c" } } } } Component { id: ribbonStyleOFF Rectangle { gradient: Gradient { GradientStop { position: 0; color: "#69697C" } GradientStop { position: 1; color: "#424251" } } } } } } } Rectangle { id: meterRect width: 46 color: "#333240" anchors.topMargin: 6 anchors.rightMargin: 6 anchors.left: gainRect.right anchors.leftMargin: 6 anchors.bottom: gainRect.bottom anchors.top: parent.top anchors.right: parent.right Meter { id: meter color: "#333240" anchors.topMargin: 0 anchors.fill: parent } } DropShadow { id : sliderShadow color: qsTr("#df000000") source: gainSlider horizontalOffset: 3 verticalOffset: 6 samples: 16 radius: 8 cached: true anchors.fill: gainSlider visible: gainSlider.visible } Slider { id: gainSlider visible: false focusPolicy: Qt.NoFocus width: 55 height: 300 anchors.top: channelRect.bottom anchors.topMargin: 0 anchors.leftMargin: 6 anchors.bottomMargin: 10 snapMode: Slider.SnapAlways stepSize: 1 from: 0 to: 68 orientation: Qt.Vertical background: Rectangle { x: gainSlider.leftPadding y: gainSlider.topPadding implicitWidth: 50 implicitHeight: 300 width: gainSlider.availableWidth height: gainSlider.availableHeight color: "#333240"; border.width: 3; border.color: "#898989"; Rectangle{ color: "#898989" //height: parent.height width: 6 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.bottom: parent.bottom anchors.topMargin: 12 anchors.bottomMargin: 12 } } handle: Image { x: gainSlider.leftPadding + gainSlider.availableWidth/2 - width/2 y: gainSlider.topPadding + gainSlider.visualPosition * (gainSlider.availableHeight - height) source: "/Images/fader_vert_png.png"; height: 26; width: 33 } Component.onCompleted: { value = gainVal } onPositionChanged: { value = Math.floor(value) updateGainValue(Math.floor(gainSlider.position*69)); } } Rectangle { id: rectangle2 color: "#333240" z: -1 anchors.left: parent.left anchors.leftMargin: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.top: groupRect.bottom anchors.topMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 TextArea { id: scribbleBox x: 41 y: 32 width: 80 height: 20 color: focus ? "#26c9ff" : "#ffffff"; bottomPadding: 3 rightPadding: 3 topPadding: 3 leftPadding: 3 wrapMode: Text.NoWrap clip: false selectionColor: "#26c9ff" selectedTextColor: "#ffffff" placeholderText: qsTr("notes...") anchors.rightMargin: 3 anchors.leftMargin: 3 anchors.bottomMargin: 3 anchors.topMargin: 3 anchors.fill: parent background: scribbleBackgroundLoader.item selectByMouse:true font.pixelSize: 14 text: scribbleStrip Loader { id: scribbleBackgroundLoader sourceComponent: scribbleNormal } onFocusChanged: { if(focus) { selectAll(); scribbleBackgroundLoader.sourceComponent = scribbleSelected } else { color: "#ffffff"; scribbleBackgroundLoader.sourceComponent = scribbleNormal } } Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { console.log("Enter") if(lineCount == 2) { console.log("Line count = 2") event.accepted = true } } } onEditingFinished: { focus = false; scribbleBackgroundLoader.sourceComponent = scribbleNormal; scribbleStrip = text; } Component { id: scribbleNormal Rectangle { anchors.fill: parent; color: "#333240"; } } Component { id: scribbleSelected Rectangle { anchors.fill: parent; color: "#636378"; } } } } } } }
-
Last one. I imagine there is a better way to share the contents of a project, but I am not sure what that would be in this case.
Preamp_status.qml
import QtQuick 2.7 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.0 import QtGraphicalEffects 1.0 Rectangle { id: rectangle2 width: 174 height: 399 color: "#00000000" property bool clkStatus: false; property bool online: false; property int clkSource property int clkOutSource: 0; property int outFormat: 0; property int sampleRate property int devID: 0; DropShadow { id : adcShadow color: qsTr("#df000000") source: adc horizontalOffset: 2 verticalOffset: 4 samples: 6 radius: 3 cached: true anchors.fill: adc visible: adc.visible } Rectangle { id: adc color: "#496c88" anchors.left: parent.left anchors.bottom: parent.bottom anchors.right: parent.right anchors.top: status.bottom anchors.leftMargin: 0 anchors.bottomMargin: 0 anchors.rightMargin: 0 anchors.topMargin: 12 width: parent.width Text { id: adcLabel height: 22 color: "#ffffff" text: qsTr("ADC") verticalAlignment: Text.AlignVCenter font.bold: true anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 6 font.pixelSize: 24 } Rectangle { id: srRect height: 55 color: "#333240" anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.top: adcLabel.bottom anchors.topMargin: 6 Text { id: srLabel color: "#ffffff" text: qsTr("Sample Rate") anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 3 font.pixelSize: 14 } ComboBox { id: srCombo anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: srLabel.bottom anchors.topMargin: 3 model: srModel currentIndex: sampleRate Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { srCombo.focus = false } } contentItem: Text { color : "#ffffff" text: srCombo.displayText font.family: "Arial"; font.pixelSize: 14; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignLeft; } background: Rectangle{ color: "#424251" } indicator: Rectangle { } delegate: ItemDelegate { x: 0 y: 0 width:srCombo.width contentItem: Text { text:modelData; horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 14; color: "#ffffff" } onClicked: { sampleRate = index srCombo.focus = false } } popup: Popup { id: srPopup width: srCombo.width height:srView.contentHeight margins: 0 background: Rectangle { color: "#424251" } contentItem: ListView { id: srView anchors.fill: parent model:srCombo.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex:sampleRate delegate:srCombo.delegate } enter: Transition { SequentialAnimation { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to: srView.contentHeight } PropertyAction { properties: "contentItem.visible"; value: true } } } exit: Transition { SequentialAnimation{ PropertyAction { properties: "contentItem.visible"; value: false } PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: srView.contentHeight; to: 0 } } } } textRole: "key" ListModel { id: srModel ListElement { key: "44.1 kHz"; } ListElement { key: "48 kHz"; } ListElement { key: "88.2 kHz"; } ListElement { key: "96 kHz"; } ListElement { key: "176.4 kHz"; } ListElement { key: "196 kHz"; } } } } Rectangle { id: clkSrcRect height: 55 color: "#333240" anchors.top: srRect.bottom anchors.topMargin: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 Text { id: clkSrcLabel color: "#ffffff" text: qsTr("Clock Source") anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 3 font.pixelSize: 14 } ComboBox { id: clkSrcCombo anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: clkSrcLabel.bottom anchors.topMargin: 3 model:clkSrcModel currentIndex: clkSource Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { clkSrcCombo.focus = false } } contentItem: Text { color : "#ffffff" text: clkSrcCombo.displayText font.family: "Arial"; font.pixelSize: 14; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignLeft; } background: Rectangle{ color: "#424251" } indicator: Rectangle { } delegate: ItemDelegate { width:clkSrcCombo.width contentItem: Text { text:modelData; horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 14; color: "#ffffff" } onClicked: { clkSource = index; clkSrcCombo.focus = false } } popup: Popup { id:clkSrcPopup width: clkSrcCombo.width height: clkSrcView.contentHeight margins: 0 background: Rectangle { color: "#424251" } contentItem: ListView { id: clkSrcView anchors.fill: parent model:clkSrcCombo.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex:clkSource delegate:clkSrcCombo.delegate } enter: Transition { SequentialAnimation { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to: clkSrcView.contentHeight } PropertyAction { properties: "contentItem.visible"; value: true } } } exit: Transition { SequentialAnimation{ PropertyAction { properties: "contentItem.visible"; value: false } PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: clkSrcView.contentHeight; to: 0 } } } } textRole: "key" ListModel { id:clkSrcModel ListElement { key: "Internal"; } ListElement { key: "Word"; } ListElement { key: "Word - 75Ω"; } ListElement { key: "Dante"; } } } } Rectangle { id: outRect height: 55 color: "#333240" anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.top: clkSrcRect.bottom anchors.topMargin: 6 Text { id: outLabel color: "#ffffff" text: qsTr("Output Format") anchors.left: parent.left anchors.leftMargin: 6 anchors.top: parent.top anchors.topMargin: 3 font.pixelSize: 14 } ComboBox { id: outCombo anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: outLabel.bottom anchors.topMargin: 3 model:outModel currentIndex: outFormat Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { outCombo.focus = false } } contentItem: Text { color : "#ffffff" text: outCombo.displayText font.family: "Arial"; font.pixelSize: 14; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignLeft; } background: Rectangle{ color: "#424251" } indicator: Rectangle { } delegate: ItemDelegate { width:outCombo.width contentItem: Text { text:modelData; horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 14; color: "#ffffff" } onClicked: { outFormat = index outCombo.focus = false } } popup: Popup { id:outPopup width: outCombo.width height : outView.contentHeight /*parent.height*parent.count*/ margins: 0 background: Rectangle { color: "#424251" } contentItem: ListView { id: outView anchors.fill: parent model:outCombo.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex:outFormat delegate:outCombo.delegate } enter: Transition { SequentialAnimation { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to:outView.contentHeight } PropertyAction { properties: "contentItem.visible"; value: true } } } exit: Transition { SequentialAnimation{ PropertyAction { properties: "contentItem.visible"; value: false } PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from:outView.contentHeight; to: 0 } } } } textRole: "key" ListModel { id:outModel ListElement { key: "Professional"; } ListElement { key: "Consumer"; } } } } Rectangle { id: clkOutRect height: 55 color: "#333240" anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.top: outRect.bottom anchors.topMargin: 6 Text { id: clkOutLabel color: "#ffffff" text: qsTr("Clock Out Source") anchors.top: parent.top anchors.topMargin: 3 anchors.left: parent.left anchors.leftMargin: 6 font.pixelSize: 14 } ComboBox { id: clkOutCombo anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: clkOutLabel.bottom anchors.topMargin: 3 model:clkOutModel currentIndex: clkOutSource Keys.onPressed: { if(event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { clkOutCombo.focus = false; } } contentItem: Text { color : "#ffffff" text: clkOutCombo.displayText font.family: "Arial"; font.pixelSize: 14; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignLeft; } background: Rectangle{ color: "#424251" } indicator: Rectangle { } delegate: ItemDelegate { width:clkOutCombo.width contentItem: Text { text:modelData; horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter font.family: "Arial"; font.pixelSize: 14; color: "#ffffff" } onClicked: { clkOutSource = index clkOutCombo.focus = false } } popup: Popup { id: clkOutPopup width: clkOutCombo.width height: clkOutView.contentHeight /*parent.height*parent.count*/ //implicitHeight:clkOutView.contentHeight margins: 0 background: Rectangle { color: "#424251" } contentItem: ListView { id:clkOutView anchors.fill: parent model:clkOutCombo.model boundsBehavior: Flickable.StopAtBounds highlight: Rectangle { color: "#69697C" } spacing: 0 highlightFollowsCurrentItem: true currentIndex:clkOutSource delegate:clkOutCombo.delegate } enter: Transition { SequentialAnimation { PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: 0; to: clkOutView.contentHeight } PropertyAction { properties: "contentItem.visible"; value: true } } } exit: Transition { SequentialAnimation{ PropertyAction { properties: "contentItem.visible"; value: false } PropertyAnimation { properties: "height"; easing.type: Easing.OutSine; duration: 250; from: clkOutView.contentHeight; to: 0 } } } } textRole: "key" ListModel { id:clkOutModel ListElement { key: "Internal"; } ListElement { key: "External"; } } } } Rectangle { id: clkStatusRect height: 30 color: "#333240" anchors.top: clkOutRect.bottom anchors.topMargin: 6 anchors.right: parent.right anchors.rightMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 Text { id: clkStatusLabel color: "#ffffff" text: qsTr("Clock Status") anchors.left: parent.left anchors.leftMargin: 6 anchors.verticalCenter: parent.verticalCenter font.pixelSize: 14 } Rectangle { id: clkStatusIndicator x: 86 y: 8 width: 16 height: 16 color: clkStatus ? "#00ff00" : "#767676" radius: 8 anchors.right: parent.right anchors.rightMargin: 16 anchors.verticalCenter: parent.verticalCenter } } } DropShadow { id : statusShadow color: qsTr("#df000000") source: status horizontalOffset: 2 verticalOffset: 4 samples: 6 radius: 3 anchors.rightMargin: 0 anchors.bottomMargin: 0 anchors.leftMargin: 0 anchors.topMargin: 0 cached: true anchors.fill: status visible: status.visible } Rectangle { id: status height: 73 color: "#496c88" anchors.top: parent.top anchors.topMargin: 0 anchors.right: parent.right anchors.rightMargin: 0 anchors.left: parent.left anchors.leftMargin: 0 Rectangle { id: statusRect y: 39 color: "#333240" anchors.left: statusLabel.right anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.top: parent.top anchors.right: parent.right anchors.topMargin: 6 anchors.rightMargin: 6 Rectangle { id: onlineIndicator x: 138 y: 16 width: 16 height: 16 color: online ? "#00ff00" : "#767676" radius: 8 anchors.verticalCenter: onlineLabel.verticalCenter anchors.right: parent.right anchors.rightMargin: 6 Layout.maximumHeight: 16 Layout.maximumWidth: 16 Layout.minimumHeight: 16 Layout.minimumWidth: 16 Layout.preferredHeight: 16 Layout.preferredWidth: 16 } Text { id: onlineLabel y: 0 color: "#ffffff" text: qsTr("Online") anchors.left: parent.left anchors.leftMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.right: onlineIndicator.left anchors.rightMargin: 6 verticalAlignment: Text.AlignVCenter Layout.columnSpan: 6 Layout.rowSpan: 1 Layout.fillHeight: true font.pixelSize: 18 } Text { id: preampID y: 0 color: "#ffffff" text: devID anchors.verticalCenterOffset: -15 anchors.verticalCenter: parent.verticalCenter anchors.left: idLabel.right anchors.leftMargin: 6 verticalAlignment: Text.AlignVCenter Layout.columnSpan: 3 Layout.rowSpan: 1 Layout.fillHeight: true font.pixelSize: 18 } Text { id: idLabel color: "#ffffff" text: qsTr("ID:") anchors.top: parent.top anchors.topMargin: 6 anchors.verticalCenterOffset: -15 anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 5 verticalAlignment: Text.AlignVCenter Layout.columnSpan: 3 Layout.fillHeight: true font.pixelSize: 18 } } Text { id: statusLabel width: 72 height: 25 color: "#ffffff" text: "Status" anchors.top: parent.top anchors.topMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 font.bold: true verticalAlignment: Text.AlignVCenter font.pixelSize: 22 } Button { id: pkClearButton anchors.right: statusRect.left anchors.rightMargin: 6 anchors.top: statusLabel.bottom anchors.topMargin: 6 anchors.bottom: parent.bottom anchors.bottomMargin: 6 anchors.left: parent.left anchors.leftMargin: 6 background: pkClearBackgroundLoader.item contentItem: Text { color: "#ffffff" text: "Peak Clear" font.pixelSize: 12 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Loader { id: pkClearBackgroundLoader sourceComponent: pkClearButton.pressed ? pkClearClicked : pkClearNormal } Component { id: pkClearNormal Rectangle { gradient: Gradient { GradientStop { position: 0.0; color: "#69697C" } GradientStop { position: 1.0; color: "#424251" } } } } Component { id: pkClearClicked Rectangle { gradient: Gradient { GradientStop { position: 0.0; color: "#3e3e46" } GradientStop { position: 1.0; color: "#1f1f24" } } } } } } }
-
@cjmdaixi
It was my understanding that this operation only needs to occur when the size of the model is being changed, i.e. when rows are being added to the structure. In this case, I simply want to access data members in the model. I will implement the begin/endInsertRows and see if it makes a difference.
It is also worth mentioning that I am able to confirm that changes are being made to the C++ model. The problem seems to be that the QML is not seeing the updates. I believe a solution would be to find a way to manually update the delegates in the ListView, but there doesn't seem to be a straightforward way to do this.