Throwing error on component creation



  • Writing a custom QML extension which is kind of a conditional loader, it should load different QML sources on different parent width conditions.

    Container {
    	id: cont
    	anchors.fill: parent
    	View {
    		max: 319
    		source: "ViewSmall.qml"
    	}
    	View {
    		min: 320
    		max: 639
    		source: "ViewMedium.qml"
    	}
    	View {
    		min: 640
    		source: "ViewBig.qml"
    	}
    }
    

    According to the above example there are three views, when the parent of cont is 0-319 load "SmallView.qml", when it's 320-639 then load "MediumView.qml", when it's bigger or equal 640 then load "ViewBig.qml".

    I implement the virtual QQmlParserStatus::componentComplete() in order to parse and verify the given view instructions:

    void QbContainer::componentComplete() {
    	//verify views
    	for(
    		QList<QbView*>::const_iterator itr(_views.constBegin()); 
    		itr != _views.constEnd();
    		++itr
    	) {
    		//verify min/max
    		if((**itr)._min < 0 && (**itr)._max < 0) {
    			//ERROR: neither min nor max are set on this view
    			throw std::runtime_error("No min/max");
    		}
    		//etc....
    	}
    }
    

    Unfortunately when the logical error is encountered the program just crashes with an uncaught exception which looks like this:

    Actual Result

    But I want it to look like a regular QML component loading error! For example if I tried to pass a wrong type value to a property it would trace the error down to the actual QML file and line number and tell me what's wrong:

    Actual Result

    I've already tried using a QException derived exception, thought it might catch it somehow, it didn't though.
    Any ideas how to make the logical error produce a useful, traced component loading error?

    P.S. Previously I simply used a Loader and gave it a condition on the source property like this:

    Loader {
    	id: container
    	anchors.fill: parent
    	source: {
    		if(width < 320) {
    			return "ViewSmall.qml"               
    		} else if(width >= 320 && width < 640) {
    			return "ViewMedium.qml"
    		} else if(width >= 640) {
    			return "ViewBig.qml"
    		}
    	}
    }
    

    ultimately I thought I needed a more elegant solution that's prettier and less error prone



  • It's been a while, yet I still have no idea how to make custom QML components produce meaningful QML errors tracing down to the actual QML file?

    Really no way to do that? no way to hook yourself in?

    P.S. Perhaps not the right forum section? Should probably go in the general section as it has not much to do with QML itself, rather C++ and the underlying engine if I'm not mistaking?


  • Moderators

    @romsharkov said in Throwing error on component creation:

    Really no way to do that? no way to hook yourself in?

    P.S. Perhaps not the right forum section? Should probably go in the general section as it has not much to do with QML itself, rather C++ and the underlying engine if I'm not mistaking?

    Hi,

    It's possible that nobody in this forum (including myself) know the answer to your question. I suggest you subscribe to the Interest mailing list and ask there. Qt engineers, who designed the internals of the QML engine, are active there.

    But anyway, I doubt that exceptions are the way to go. These are low-level, C++ constructs that terminate the whole program if uncaught. Qt itself does not throw or catch any exceptions, so your code is guaranteed to crash whenever it throws an exception. On the other hand, "official" QML errors don't terminate the program, which suggests to me that they're not implemented as exceptions.



  • Forgive me if this doesn't help, but it's what I'm thinking.

    I'm not sure if this will even work (unsure if you can swap sources) like this on width changed... but onCompleted should be ok?

    It may get you experimenting / thinking differently to get a solution.

    http://doc.qt.io/qt-5/qml-qtquick-loader.html#source-prop

    Loader {
    	id: container
    	anchors.fill: parent
    	// setSource on Loader Component complete
    	Component.onCompleted: { doSetSource(); }
    }
    Connection { target: container; onWidthChanged: { doSetSource(); } }
    function doSetSource(){
       if(container.width < 320) {
            container.setSource("ViewSmall.qml");
    ...