JuliaGraphics / QML.jl

Build Qt6 QML interfaces for Julia programs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Array as Observable

jheinen opened this issue · comments

How would I use an array as Observable (within a Repeater)? I both tried using it as a model parameter or as a value parameter in the delegate. In the first case the window is empty, in the second case an error occurs ("Unable to assign qmlwrap::qvariant_any_t to double").

ENV["QT_QUICK_CONTROLS_STYLE"] = "Fusion"

using QML
using Observables

mktempdir() do folder
  path = joinpath(folder, "test.qml")
  write(path, """
import QtQuick 2.12
import QtQuick.Controls 2.4
import org.julialang 1.1

ApplicationWindow {
  title: "Test"
  visible: true
  Grid {
    rows: 5
    columns: 1
    Repeater {
      model: 5
      delegate: Row {
        Slider {
          value: slider
        }
      }
    }
  }
}
  """)

  slider = Observable(zeros(5))

  loadqml(path; slider=slider)
  exec_async()

  while true
    sleep(1)
    slider[][5] = rand()
  end

end

Hi Josef,

This probably isn't exactly what you are looking for, but with a Repeater you need to use a ListModel:

ENV["QT_QUICK_CONTROLS_STYLE"] = "Fusion"

using QML
using Qt5QuickControls2_jll

mktempdir() do folder
  path = joinpath(folder, "test.qml")
  write(path, """
import QtQuick 2.12
import QtQuick.Controls 2.4
import org.julialang 1.1

ApplicationWindow {
  title: "Test"
  visible: true
  Grid {
    rows: 5
    columns: 1
    Repeater {
      model: slider
      delegate: Row {
        Slider {
          onValueChanged: {
            sliderval = value;
          }

          Component.onCompleted: {
            value = sliderval;
          }
        }
      }
    }
  }
}
  """)

  slidervalues = (collect(0.2:0.2:1.0))
  slider = ListModel(slidervalues)
  addrole(slider, "sliderval", identity, setindex!)

  loadqml(path; slider=slider)
  exec()

  println("slider values: $slidervalues")
end

At this time, Observables doesn't really fit into that, I'm assuming you want to update the ListModel from Julia here?

Hi Bart, thanks for you help. This works fine, but how would I now inform the Qt5 run-time to update the slider widget(s) (from an asynchronously triggered function)?

OK, this appears to do the trick:

ENV["QT_QUICK_CONTROLS_STYLE"] = "Fusion"

using QML
using Qt5QuickControls2_jll

qml_data = QByteArray("""
import QtQuick 2.12
import QtQuick.Controls 2.4
import org.julialang 1.1

ApplicationWindow {
  title: "Test"
  visible: true
  Grid {
    rows: 5
    columns: 1
    Repeater {
      model: slider
      delegate: Row {
        Slider {
          id: sliderControl
          onValueChanged: {
            sliderval = value;
          }

          Component.onCompleted: {
            value = sliderval;
          }
          Connections {
            target: slider
            function onDataChanged() { sliderControl.value = sliderval; }
          }
        }
      }
    }
  }
}
  """)

slidervalues = (collect(0.2:0.2:1.0))
slider = ListModel(slidervalues)
addrole(slider, "sliderval", identity, setindex!)

qengine = init_qmlengine()
ctx = root_context(qengine)
set_context_property(ctx, "slider", slider)

qcomp = QQmlComponent(qengine)
set_data(qcomp, qml_data, QML.QUrl())
create(qcomp, qmlcontext());

exec_async()

After the exec_async, you can use the REPL to modify the sliders like this:

slider[1] = 1

Thanks a lot. That works fine ...