Event filter in QML - c++

I have to send 48 Bytes of Data to controller via Qtcpsocket. I have represented each Bit in a Byte as a Button in QML. So whenever the user clicks the button, I have to set the Corresponding Bit to true/false and immediately send the entire 48 Bytes of data.
I have so many buttons(Bits) in so many QML files. How to detect which button has been pressed and immediately set the corresponding Bit? How to get the Object in qml ?
What i have done is emitting a signal in the Bit when button is pressed. Now confused how to pass it to the backend c++ on to the sockets because then i would have so many signals. I feel like it’s not a proper way to do. Any smart / better solution or similar example would be really helpful.Thanks

I don't exactly understand from you code what are you trying to do but may be this example can help:
Byte.qml
import QtQuick 2.4
import QtQuick.Controls 1.2
Row {
id: block
property int number: 0
signal dataChanged()
Repeater {
model: 8
Button {
width: 20
height: 20
property int buttonIndex: index
text: buttonIndex
checkable: true
checked: false
onClicked: {
block.number = block.number ^ (1 << buttonIndex);
dataChanged();
}
}
}
}
main.qml
import QtQuick 2.4
import QtQuick.Window 2.0
Window {
id: win
width: 800
height: 600
Column {
id: numbers
property var bytes: []
anchors.centerIn: parent
Repeater {
model: 6
Byte {
property int byteIndex: index
Component.onCompleted: numbers.bytes[byteIndex] = 0;
onDataChanged: {
numbers.bytes[byteIndex] = number;
console.log(numbers.bytes);
}
}
}
}
}
I use here 6 bytes to just bring up the idea. All you need is just to send it to C++ instead of printing it out to console. Intergrating QML and c++ is widely described in the Internet. You can start from here

Related

Changing the model does not redraw objects in QML sometimes

Repeater {
model: myModel.buttonParameters
delegate: Button
{
width: 47
height: 47
contentItem: Text {
id: content
text: modelData.name
font.family: MyStyle.fontFamily
fontSizeMode: Text.Fit
font.pixelSize: 30
font.styleName: "Bold"
topPadding: height / 6
color: modelData.visibility ? MyStyle.colorFromSeriesName(this.text) : MyStyle.dividerColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle
{
anchors.fill: parent
radius: 4
color: MyStyle.backgroundColor
border.color:MyStyle.dividerColor
border.width: 2
}
onClicked: {
cntModel.visibilityOfChartChanged(modelData.name, "plot");
}
}
}
On the C++ side.
myModel.buttonParameters is a QList<MyModel*> , where MyModel is a class inherited from QObject.
Q_PROPERTY(QVariant buttonParameters READ buttonParametersList NOTIFY buttonParametersChanged)
QVariant buttonParametersList()
{
return QVariant::fromValue(m_buttonParametersList );
}
The problem is that with a certain change in the model
(the signal buttonParametersChanged is sent), namely,
if the number of objects was equal to one and after the update there
is also one object, but with different characteristics, no redrawing
takes place, the old button remains. Moreover, it somehow depends on
the runtime. Also, if I remove the line with color, the model will update.
The issue is that buttonParametersChanged is a signal that triggers on the assignment of a new container (QList<>) to buttonParameters. It doesn't trigger on changes to the contents of an existing QList<> assigned to that property.
However, you can always manually trigger buttonParametersChanged when you know you've modified the contents of the QList<> which should give you the effect you want.
Note, a QML ListModel or C++ equivalent would likely be more appropriate for this use case. Many QML components are designed to specifically integrate with them and handle the cases of container contents changing.

Passing QList <QObject *> from C ++ to QML

Good evening,
We are programming a DaVinci DM8168 board with Qt5.7.1 and QtQuick2.7
we would like to pass a list of type:
QList from C ++ to QML
to be able to draw it asynchronously and above all efficiently. The list is modified by a thread on C ++.
We cannot state the update frequence of this list at all: it can be just one time per second or dozens! It depends by the target enviroment.
our solution (partially working) is the following:
On the C++ side we are using QPROPERTIES:
an extract of our code:
MyClass.h
class MyClass: public Observer
{
Q_OBJECT
Q_PROPERTY(QList<QObject*> getFailuresHistory READ getFailuresHistory NOTIFY failuresHistoryListChanged)
QList<QObject*>getFailuresHistory(){return failuresHistory_;}
signals:
void failuresHistoryListChanged();
}
then my .cpp we emit the signal every time the list changes ( not true at all: if more elements of the list changes at the same time we emit the signal only once in order to optimize the application)
emit failuresHistoryListChanged();
Then on QML "side" we do the following:
Item
{
// ... other code
//DELAGATE
Component
{
id: failuresDelegateHistory
Item
{
id: listHistoryItem
width: listHistory.width
height: 10
anchors.leftMargin: 5
Row
{
Text{
id: failureIdHistory
width: 30
text: qsTr(modelData.codeFailure) + mainSettingsHandler.emptyString
color: mainWindow.currentStyleColor.colorRed
font.pixelSize: 16
horizontalAlignment: Text.AlignHCenter
}
Text {
id: descriptionFailIdHistory
width: (listHistoryItem.width-failureIdHistory.width)*0.5
color:mainWindow.currentStyleColor.colorWhite
maximumLineCount: 1
text: qsTr(modelData.descriptionFail) + mainSettingsHandler.emptyString
wrapMode: Text.WrapAnywhere
horizontalAlignment: Text.AlignJustify
font.pixelSize: 12//16
}
Text
{
id: columnTimeStampFailureHistory
width: (listHistoryItem.width-descriptionFailIdHistory.width-failureIdHistory.width- 2)
maximumLineCount: 1
text: modelData.dateFail + mainSettingsHandler.emptyString
wrapMode: Text.WrapAnywhere
color:mainWindow.currentStyleColor.colorWhite
font.pixelSize: 12
horizontalAlignment: Text.AlignJustify
}
}
}
}
//LIST
ListView
{
id: list1
y: labelHistory.y + labelHistory.height+5
width: (FileConfiguration.widthMenuArea - space - 5)*0.5-1-space
height: (270 - space) *itemsPerPage
model: myClass.getFailuresHistory//failuresHistoryTable.getFailuresHisory
delegate: failuresDelegateHistory
spacing: 10
enabled: false
}
// ... other code
}
OK;
as I said before this solution is partially working because is very, very slow!
When the:
emit failuresHistoryListChanged();
on c++ side is called, the list is drawn but the software is "slow". We have keepalive message that shall be set every 300 ms and that is not sent anymore for a couple of seconds.
We need a more efficent way to pass the list to the QML.
if we comment the emit the software works fine within its deadlines.
So our purpose is: we would like to pass in a very efficent way this list to QML. Do you have solutions that involve a modification of the code that we have shown you or new architectures? do you have any examples? we are not experts in qml.
If you need more information ask us.
We thank you in advance, we have been trying to solve the problem for a long time.
thanks

How to access certain element in a QObjectList-based model in QML

Suppose on C++ side I've created a QList<QObject *> myObjects which contains several custom objects derived from QObject.
And then expose it to QML by setContextProperty( "myModel", QVariant::fromValue( myObjects ) );
The question is, in my QML code, how can I get and use a specific element (by index) in myModel (which is a QList). For instance, I would like to take a random element from the list and show it?
The example is here: http://doc.qt.io/qt-5/qtquick-models-objectlistmodel-example.html, where all elements of the model are shown in a ListView`, while I just want to show one (or several) of them.
its pretty easy...
to get item number i from the model:
myModel[i]
and to access its properties/roles:
myModel[i].propertyName
To get an item from the list you can use the [] operator:
myModel[index]
The elements of a QList are similar to arrays in javascript since QML is based on the latter.
The following example shows getting the names in random form (it only replaces the code in the example).
view.qml
import QtQuick 2.0
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4
//![0]
ColumnLayout{
ListView {
width: 100; height: 100
model: myModel
delegate: Rectangle {
height: 25
width: 100
color: model.modelData.color
Text {
text: name
}
}
}
Button {
text: "random"
onClicked: {
t.text = myModel[ Math.floor(Math.random()*myModel.length)].name;
}
}
Text{
id: t
text: ""
}
}

Propagating onPositionChanged events to background items in QtQuick 1.1

Background.qml
import QtQuick 1.1
Item {
MouseArea {
id: backgroundMouseArea
anchors.fill: parent
hoverEnabled: true
onPositionChanged: {
console.log("Background")
}
}
}
Foreground.qml
import QtQuick 1.1
Item {
Background {
width: 1920
height: 1080
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPositionChanged: {
console.log("Foreground")
[mouse.accepted = false] - Not working (as the docs say)
[backgroundMouseArea.onPositionChanged(mouse)] - Not working
}
}
}
I need to execute onPositionChanged event on both background and foreground items.
F.ex. for onPressed I would do it by setting mouse.accepted = false in the foreground item.
Can I call onPositionChanged of the background item manually? If yes, how do I do it?
I am not completely sure what you are trying to achieve here.
A MouseArea is meant to grab mouse events from hardware. If you really want to propagate mouse events to background from a different MouseArea, maybe what you actually want to do is give Background a simple property mousePosition instead of the MouseArea, and then set that position from the Foreground onPositionChanged handler.
Also, your Foreground code relies on an internal id parameter inside of Background. This smells really bad. It is often more useful to think about the "Public API" of the Background and Foreground "classes". If what I described above is really what you want to do, this is what it should look like IMHO:
// Background.qml
import QtQuick 1.1
Rectangle {
// an object with just x and y properties
// or the complete mouseevent, whatever you want
// Use variant for QtQuick 1/Qt4, var for QtQuick 2.0 / Qt5
property variant mousePosition
onMousePositionChanged: console.log(
"Background " + mousePosition.x + " " + mousePosition.y
)
}
//Foreground.qml
import QtQuick 1.1
Item {
// use only ids defined in the same file
// else, someone might change it and not know you use it
Background { id: background }
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPositionChanged: {
console.log("Foreground")
background.mousePosition = {x: mouse.x, y: mouse.y}
}
}
}
...........

qml + master-detail

I want to use qml with master-detail interface, but i don't know how to pass current item to detail view right way. The ListView in master view uses C++ model (add-on of QSQLTableModel, it's work fine) and I see two ways to pass item:
Create C++ classes with fields with static name like QSqlRecord field names and pass it to qml with w->rootContext()->setContextProperty() (w is QDeclarativeView *), but now i don't use any classes like this and can change my database and qml views without changing c++ code, I would like to save it
Create a lot of properties in any detail qml like
Rectangle {
id: mainRect
property alias myFieldName: txt_nominal.text
Column {
width: parent.width
Text {
id: txt_nominal
font.bold: true
}
}
}
and set this properties from c++ code by setting w->rootContext()->setContextProperty(record.fieldName(i),record.field(i).value()); (record - QSqlRecort at current row)
Is there any easier way to solve my problem?
PS The code I wrote above is not checked for accuracy, and is written to make it more clear what I mean
UPD
Maybe it will be useful for somebody, I discovered 3-rd way, rather, the modification of second - you can wrap fields into QVariantMap and pass only one object to qml. This is exactly what I wanted
in cpp:
QVariantMap testObject;
testObject["testField"]="first string from cpp";
testObject["testField2"]="second string from cpp";
rootContext()->setContextProperty("testObject",testObject);
in qml:
Text {
id: simpleTextt
text: testObject.testField
anchors.centerIn: parent
}
You could use the isCurrentItem property of the delegate to pass the data from ListView delegate to your details qml. That way you could get away without have to add additional c++ code. This is basically your second approach but without c++. You also do not need to add many properties as long as each of your QML elements that you want to change have an id.
If you have a number of different QML for different details views you would also have to use the Loader to load the appropriate details QML.
Just a toy example assuming that you have only one details template for all of your elements in the list (as mentioned above if that is not the case than you can use loader instead of detailsRect):
Rectangle {
width: 300; height: 400
Rectangle {
id: detailsRect
anchors.right: parent.right
width: 100
height: 500
color: "blue"
Text {
id: detailsText
text: ""
}
}
ListView {
id: list
anchors.fill: parent
model: 20
delegate: Rectangle {
color: ListView.isCurrentItem ? "red" : "green"
width: 40
height: 40
Text {
text: index
}
ListView.onIsCurrentItemChanged: {
if(ListView.isCurrentItem)
{
detailsRect.color = "yellow"
detailsText.text = index
}
}
MouseArea {
anchors.fill: parent
onClicked: {
list.currentIndex = index
}
}
}
}
}