Skip to content
  • 0 Votes
    7 Posts
    464 Views
    Pl45m4P

    @sayan275

    It's also always better to post the relevant code as text and not as image, so others can reproduce it easier.

  • 0 Votes
    2 Posts
    127 Views
    jsulmJ

    @AROH I guess you need to declare/register QVector<int>, see https://doc.qt.io/qt-6/custom-types.html

  • 0 Votes
    6 Posts
    497 Views
    jsulmJ

    @CJha The problem is that you can't just replace something in a file if new value has different lenght than the old one. In this case you need to read the file into memory, replace the value and write it back. To read such an ini file and replace something there Qt needs to know how to interpret the data it reads.

  • 0 Votes
    4 Posts
    883 Views
    Pl45m4P

    @szmf

    It might work when on the same thread (also you should register it anyway) but as soon as you have QueuedConnections this will probably fail without registering the type globally.

    https://doc.qt.io/qt-6/custom-types.html#overview

    The part here even says, that declaring is necessary for direct signal and slot connections:

    The Message class only needs a suitable implementation in order to be usable. However, Qt's type system will not be able to understand how to store, retrieve and serialize instances of this class without some assistance. For example, we will be unable to store Message values in QVariant.

    The class in Qt responsible for custom types is QMetaType. To make the type known to this class, we invoke the Q_DECLARE_METATYPE() macro on the class in the header file where it is defined:
    Q_DECLARE_METATYPE(Message);

    This now makes it possible for Message values to be stored in QVariant objects and retrieved later. See the Custom Type Example for code that demonstrates this.

    The Q_DECLARE_METATYPE() macro also makes it possible for these values to be used as arguments to signals, but only in direct signal-slot connections. To make the custom type generally usable with the signals and slots mechanism, we need to perform some extra work.

    As stated reading further here:

    Although the declaration in the previous section makes the type available for use in direct signal-slot connections, it cannot be used for queued signal-slot connections, such as those that are made between objects in different threads. This is because the meta-object system does not know how to handle creation and destruction of objects of the custom type at run-time.

    To enable creation of objects at run-time, call the qRegisterMetaType() template function to register it with the meta-object system. This also makes the type available for queued signal-slot communication as long as you call it before you make the first connection that uses the type.

  • 0 Votes
    2 Posts
    272 Views
    JonBJ

    @johnco3
    I'm afraid I know nothing about std::variant, but a couple of observations.

    Your setData() is void. QStandardItemModel's is bool. Have you checked the return result when you call that, you never know if it might be barfing?

    Your setData() defaults to Qt::UserRole + 1. How does your item->data().value<PortVariant>() pass that role to fetch?

    setData() copies its argument. I assume the equivalent code to test would be something like:

    PortVariant portVariant = port; QVariant v = QVariant::fromStdVariant(portVariant); QVariant v2 = v1; const auto& portVariant = v2.value<PortVariant>();

    How does that come out? You might also call QVariant::canConvert<>() to check, including on your item->data().

    I assume all the various component types in your structs are serializable to QVariant without further registration.

  • 0 Votes
    9 Posts
    835 Views
    crueeggC

    @kshegunov I have ~80 classes, each with 5-10 different properties (enums, POD, custom types, containers). The problem are all implicit (in a loop) conversions of these properties.

  • 0 Votes
    1 Posts
    305 Views
    No one has replied
  • 0 Votes
    6 Posts
    592 Views
    SGaistS

    When you use custom types, it's pretty usual to register them all before building any of the widgets that will use them as part of your application startup sequence after you created your QApplication object.

  • 0 Votes
    6 Posts
    1k Views
    L

    @oblivioncth same here. Neither Macro nor register function needed. no related documents.

  • 0 Votes
    3 Posts
    1k Views
    R

    @JKSH Thanks for the reply. I was actually hoping to list the QMetaObject's properties on QML, in a dynamic way. Is it possible?

  • 1 Votes
    4 Posts
    836 Views
    M

    @Dariusz Did you ever figure out the problem? I'm seeing something similar having moved to Qt6.2

  • 0 Votes
    5 Posts
    472 Views
    B

    Maybe @Moia want a method to get that QVariant without a QJsonValue?
    By looking into the source code of QJsonValue, you can see that value comes from

    QVariant::fromValue(nullptr)
  • 0 Votes
    3 Posts
    874 Views
    Christian EhrlicherC

    From a short look at the code without understanding the whole stuff I would guess that internally there is only a QObject pointer is stored. So it must be a QObject to track the lifetime.

  • 0 Votes
    6 Posts
    1k Views
    JKSHJ

    @Max13 said in Store custom QVariant type in database:

    I will write a toJson() instead, as I'm loading the data from Json already.

    Sounds good.

    Thanks for your advice. Indeed, it would be the correct way to implement this, in my situation I didn't think it would be necessary to implement it that way.

    I'm updating some models from an API, and save them as a read-only cache in an sqlite because the desktop may be disconnected. So in my opinion, adding another table would make me write more queries and deal with relations when I can do that in a nasty way 😅

    That's fair enough. Simplicity is often a good thing in code.

    Thanks for your complete answer.

    You're most welcome. Happy coding!

  • 0 Votes
    6 Posts
    1k Views
    F

    This question is a bit old now, but I ran into the same problem without finding a solution elsewhere, so maybe this will be useful for others to know.

    I tried exactly the same code as you, and found the the same issue of the signal not connecting properly. What worked for me was to add the following somewhere in the code (e.g. the class constructor) to get executed before the connect() call.

    #include <QDBusMetaType> // Add to code (e.g. constructor) to be run before the connect() call qDBusRegisterMetaType<InterfaceList>();

    The connect() call then returned true, the signal fired, and I was able to extract the object properties straight from the InterfaceList object passed with the signal.

  • 0 Votes
    1 Posts
    873 Views
    No one has replied
  • 0 Votes
    2 Posts
    1k Views
    B

    I've solved it.

    To handle long I did not have to send immediately reply (even though tutorial said that we have to). And delayed reply will be send.

    Also in extension, QDBusPendingReply<QString, QByteArray> reply = *call; setting expecting signature to \"say\" and not looking to xml interface.

  • 0 Votes
    13 Posts
    3k Views
    Matthew11M

    OK as @J.Hilk said:

    @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

    are you by any chance exposing those thread-shared custom types directly to qml?

    And:

    @J.Hilk said in Passing custom type pointers between QML and threads via signals and slots cause app to crash:

    I can only tell you that I always ran into trouble when I tried to access/manipulate c++ threaded stuff (directly)via QML.

    Indeed that was causing the crashes. The solution is to create a copy of the resource that is sent from QML and then send a copy of that resource to thread.

    As @J.Hilk suggested Manager object should do the job which is:

    @Matthew11 said in [Passing custom type pointers between QML and threads via signals and slots cause app to crash

    Manager <-> Threads : communicate via signal/slots with QueuedConnection synchronization/locking on the shared resource Manager <-> QML signals and slots or directly from the manager's memory

    Below you can find my working example. This is very similar to the code which I provided in the first post. You send a dispatch from QML to specific Contractor, Contractor then is doing his job and return the result back to QML (sends task with input data scenario). Or you send a dispatch to Contractor to retrieve some data (send task with no input data scenario). ContractorTask is no longer exposed to QML. But pointers are no longer send however it is possible in the C++ domain (across main (Manager) and workers threads with proper locking/synchronization).

    If you want to feel how it is when app is crashing uncomment the line _taskCopy.setData(_data); from pushTaskToContractor() in Controller.h which disabling the step of making the copy of the resource.

    Thank you all for your help in solving the problem!

    Code:

    //.pro QT += quick CONFIG += c++11 SOURCES += \ Contractor.cpp \ main.cpp RESOURCES += qml.qrc HEADERS += \ Contractor.h \ ContractorTask.h \ Controller.h // Contractor.h #ifndef CONTRACTOR_H #define CONTRACTOR_H #include <QObject> #include <ContractorTask.h> class Contractor : public QObject { Q_OBJECT public: Contractor(int _ID, QObject* parent = nullptr); int getID() { return ID; } public slots: void executeTask(ContractorTask _task); signals: void finished(); void taskStarted(ContractorTask _task); void taskFinished(ContractorTask _task); private: int ID; }; #endif // CONTRACTOR_H // Contractor.cpp #include "Contractor.h" #include <QDebug> #include <QThread> Contractor::Contractor(int _ID, QObject *parent) : QObject(parent), ID(_ID) {} void Contractor::executeTask(ContractorTask _task) { emit(taskStarted(_task)); if(getID() != _task.getConctractorID()) { qDebug() << "Not mine ID, discarding"; return; } QVariant localData = _task.getData(); switch(_task.getTaskID()) { case 0: // PASS TASK TO C++ TO RETRIEVE DATA { QList<QVariant> _params; _params.append(12.5F); _params.append(14.36F); QVariant _data = _params; _task.setData(_data); qDebug() << "PASS TASK TO C++ TO RETRIEVE DATA"; } break; case 1: // PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML { QList<QVariant> _params; _params = localData.value<QList<QVariant>>(); QList<float> _floats; int counter = 0; for(auto item : _params) { _floats << item.toFloat(); qDebug() << "Getting data in C++ from QML (QList<float>): item =" << counter++ << "value =" << item; } qDebug() << "PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML"; } break; default: { qDebug() << "Oh... I don't have these one :("; } } emit(taskFinished(_task)); } // ContractorTask.h #ifndef CONTRACTORTASK_H #define CONTRACTORTASK_H #include <QVariant> class ContractorTask { public: ContractorTask() : taskID(-1), contractorID(-1), data("") {} int getTaskID() { return taskID; } void setTaskID(int _ID) {taskID = _ID; } int getConctractorID() { return contractorID; } void setContractorID(int _ID) { contractorID = _ID; } QVariant getData() { return data; } void setData(QVariant _data) { data = _data; } private: int taskID; int contractorID; QVariant data; }; Q_DECLARE_METATYPE(ContractorTask) #endif // CONTRACTORTASK_H // Controller.h #ifndef CONTROLLER #define CONTROLLER #include <QObject> #include <QThread> #include <QDebug> #include <Contractor.h> #include <ContractorTask.h> class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Contractor *worker = new Contractor(0); worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &Controller::startTask, worker, &Contractor::executeTask); connect(worker, &Contractor::taskStarted, this, &Controller::contractorStartedTask); connect(worker, &Contractor::taskFinished, this, &Controller::contractorFinishedTask); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } signals: void startTask(ContractorTask); void taskStarted(int id, int contractor, QVariant data); void taskEnded(int id, int contractor, QVariant data); public slots: void pushTaskToContractor(int _id, int _contractor, QVariant _data) { // QVariant depends to QML, so make COPY of QVariant CONTENT, before passing it to thread: QList<QVariant> _params; _params = _data.value<QList<QVariant>>(); QVariant _dataToSend = _params; ContractorTask _taskCopy; _taskCopy.setTaskID(_id); _taskCopy.setContractorID(_contractor); _taskCopy.setData(_dataToSend); // Sending local data copy is OK // _taskCopy.setData(_data); // Sending _data (has source in QML) = PROGRAM CRASH!!! emit(startTask(_taskCopy)); } void contractorFinishedTask(ContractorTask _task) { // Passing COPY of ContractorTask to QML: emit(taskEnded(_task.getTaskID(), _task.getConctractorID(), _task.getData())); } void contractorStartedTask(ContractorTask _task) { // Passing COPY of ContractorTask to QML: emit(taskStarted(_task.getTaskID(), _task.getConctractorID(), _task.getData())); } }; #endif // CONTROLLER // main.cpp #include <QGuiApplication> #include <QQmlApplicationEngine> #include <Controller.h> #include <QQmlContext> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); Controller TaskController; qRegisterMetaType<ContractorTask>(); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("TaskController", &TaskController); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); // Get item from QML, and connect it's signal (startTaskFromQML) to Controller QObject *item = engine.rootObjects().first(); QObject::connect(item, SIGNAL(startTaskFromQML(int, int, QVariant)), &TaskController, SLOT(pushTaskToContractor(int, int, QVariant))); return app.exec(); } // main.qml import QtQuick 2.12 import QtQuick.Controls 2.5 ApplicationWindow { id: root visible: true width: 640 height: 480 title: qsTr("Test") signal startTaskFromQML(int id, int contractor, variant data) property variant _data: 0 Connections { target: TaskController onTaskEnded: console.log("Contractor with ID =", contractor, "finished task with ID = ", id, "and returned result:", data); onTaskStarted: console.log("Contractor with ID =", contractor, "started task with ID = ", id); } Column { id: column anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter Button { id: passAndGet text: qsTr("PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML") anchors.horizontalCenter: parent.horizontalCenter onClicked: { _data= [1.2, 3.4, 5.6, 7.8] for(var i = 0; i < 50; i++) { root.startTaskFromQML(1, 0, _data) } } } Button { id: getData text: qsTr("PASS TASK TO C++ TO RETRIEVE DATA") anchors.horizontalCenter: parent.horizontalCenter onClicked: { _data = 0 root.startTaskFromQML(0, 0, _data) } } } } // qtquickcontrols2.conf [Controls] Style=Material // qml.qrc <RCC> <qresource prefix="/"> <file>main.qml</file> <file>qtquickcontrols2.conf</file> </qresource> </RCC>
  • Qt ActiveX i AutoCAD

    Unsolved Polish
    2
    0 Votes
    2 Posts
    1k Views
    N

    Uzupełniając moje pytanie. Próba dodania obiektu takiego jak punkt czy koło kończy się takim komunikatem.:

    QAxBase: Error calling IDispatch member AddCircle: Exception thrown by server
    Code : -2147024809
    Source :
    Description:
    Help :
    Connect to the exception(int,QString,QString,QString) signal to catch this exception

    Ktoś może wie gdzie sprawdzić ten kod?
    Dzięki za pomoc
    Adam

  • 0 Votes
    31 Posts
    7k Views
    E

    Sorry mate but I see no point in continuing this conversation.

    Some software developers agreed that they need the class “variant” for working with type-safe unions. They chose another useful programming interface. These software design decisions might influence other class libraries, don't they?

    The Qt software library is using also a variant class for the support of the meta-object protocol, isn't it?