I have custom listviews with corresponding custom models. I use QML for the frontend and load the main file with Python and use python for the backend. The model data of the different models depends heavily on each other. Everything works as expected with the different listviews, test-models and delegates.
Since the models depend on each other I introduced a "PythonDataManager"-Class that should get the data from the three models, work with it and hand output back to the the corresponding model instances. I thought to do it with the Signal/Slot technology Qt provides. I connected the signals and slots of the instances of the different classes. I declared a slot I call from a button press in QML. This slot gets executed and should emit one signal, that therefore should call a different slot in a different class/instance. When I call the .emit() function on the signal nothing happens.
My Question is, how can I connect different instances of the different classes with signals and slots with PySide6?
The goal of the following example code is to read out the self.db attribute of the TimeseriesesModel class and send it off to the PythonDataManager that prints it out. The expected result is: [{"name": "hello", "selected": True},{"name": "zwei", "selected": False}] but I get a empty list: [].
The shorted code of one of the custom models:
QML_IMPORT_NAME = "library.measure"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class TimeseriesesModel(QAbstractListModel):
SelectedRole = Qt.UserRole + 1
NameRole = Qt.UserRole + 2
# The signal that later gets emitted
send_ts_model_data = Signal(list)
def __init__(self, parent=None):
super().__init__(parent=parent)
self.db = [
{"name": "hello", "selected": True},
{"name": "zwei", "selected": False},
]
# --- In this place I left out a lot of code that shouldn't be relevant
#----------------------------------------------------------------------
# The slot, that should get called by the "askModelsForData" signal
@Slot()
def request_handling(self):
self.send_ts_model_data.emit(self.db)
The relevant code of the PythonDataManager-Class:
@QmlElement
class PythonDataManager(QObject):
askModelsForData = Signal()
def __init__(self, parent=None):
super(PythonDataManager, self).__init__(parent=parent)
self.ts_model_db = []
@Slot(list)
def get_ts_model_data(self, data):
self.ts_model_db = data
# The slot that get's called successfully from QML
@Slot()
def print_something(self):
self.askModelsForData.emit()
print(self.ts_model_db)
The relevant code of the main.py:
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
data_manager = PythonDataManager()
ts_model = TimeseriesesModel()
# Connect the signals and the slots
data_manager.askModelsForData.connect(ts_model.request_handling)
ts_model.send_ts_model_data.connect(data_manager.get_ts_model_data)
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("TimeseriesesModel", ts_model)
engine.rootContext().setContextProperty("PythonDataManager", data_manager)
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
The code of the qml file that calls the pythonDataManager.print_something() slot:
import QtQuick 2.0
import QtQuick.Window
import library.measure // The library that gets invoked in the python part
import QtQuick.Controls
Item {
id: root
PythonDataManager {
id:pythonDataManager
}
// Lists the Different Window/ScreenQMLs--------------------------
// (In the reprex only one)
Window {
id: accessGrantedWindow
visible: true
minimumWidth: 955
minimumHeight: 730
Button {
id: resetButton
x: 0
y: 0
width: 88
height: 25
text: qsTr("Reset All")
onClicked: {
// The print_something() slot gets called successfully
console.log(pythonDataManager.print_something())
}
}
}
}
Thanks for helping
I solved the issue by now by myself.
Defining QML components in Python, importing them afterwards in QML and connecting the signals and slots in the QML with the "Connections{}" QML Type (see: https://doc.qt.io/qt-6/qml-qtqml-connections.html) works.
For example add in the QML File:
TimeseriesesModel {
id:ts_model
}
Connections {
target: pythonDataManager
function onAskModelsForData() {
console.log("received onAskModelsForData-signal")
// Call your slot here like id.slot()
ts_model.request_handling()
}
}
and remove from the main.py:
# Connect the signals and the slots
data_manager.askModelsForData.connect(ts_model.request_handling)
ts_model.send_ts_model_data.connect(data_manager.get_ts_model_data)