[QGIS-Developer] How to access QgisApp::instance() from a core class
Schmetzer, Tobias
Tobias.Schmetzer at zae-bayern.de
Thu Mar 31 12:27:02 PDT 2022
> Offhand, there's a couple of ways to approach something like this:
> 1. You add appropriate signals in the core classes which are emitted
> at useful stages, e.g. "aboutToCalculateExtent",
> "extentCalculationProgressChanged", "extentCalculationComplete". And
> then the app/gui classes can listen out for these signals and respond
> to them appropriately, i.e. by showing a progress bar somewhere.
That sounds reasonable.
I am experimenting to implement the signals and the connect() call into the concerning
provider class. As I am not familiar with the QGIS architecture I am unsure
what class to put the slot function into that raises the QProgressDialog().
I was thinking if QgsProject:: would be a good place?
> 2. You could add a QgsFeedback* argument to the costly method, and use
> that to report progress and support early cancellation.
I couldn't manage to fully understand the concept of QgsFeedback, especially
how it causes QProgressDialog to be invoked. Sudden enlightenment or supportive
explanation provided I will update the docs.
> (2 is a more flexible, "better" approach, but depending on the method
> you may not be able to add this to an existing method without breaking
> stable API.
Tobias
________________________________
Von: Nyall Dawson <nyall.dawson at gmail.com>
Gesendet: Montag, 7. März 2022 23:52
An: Schmetzer, Tobias
Cc: qgis-developer at lists.osgeo.org
Betreff: Re: [QGIS-Developer] How to access QgisApp::instance() from a core class
On Tue, 8 Mar 2022 at 07:23, Schmetzer, Tobias
<Tobias.Schmetzer at zae-bayern.de> wrote:
>
> > Again, none of the core classes are allowed any GUI component, and the correct approach to handle this particular situation is to move that code from the provider level up to app level, specifically via the QgsDataItemGuiProvider class.
>
>
> I had a look into it. If I understood it correctly the class provides a framework for functions to be registered and called by other functions placed in the gui.
>
> But what to do when a progress dialog needs to be raised or an application state needs to be read? (see description below)
>
>
> > So my question would be: why do you need to raise a user-facing message from QgsOgrProvider::extent?
>
>
> - One idea was is to inform the user via a simple progress dialog in cases of very time-consuming extent calculations for large layers (I observed calc time ranges from 10 min to hours) of what's going on and that QGIS hasn't crashed yet. The design would practically allow this to be implemented in the provider . If that's also not how it is intended to be then I'd appreciate a quick hint of how it is intended to be.
Offhand, there's a couple of ways to approach something like this:
1. You add appropriate signals in the core classes which are emitted
at useful stages, e.g. "aboutToCalculateExtent",
"extentCalculationProgressChanged", "extentCalculationComplete". And
then the app/gui classes can listen out for these signals and respond
to them appropriately, i.e. by showing a progress bar somewhere.
2. You could add a QgsFeedback* argument to the costly method, and use
that to report progress and support early cancellation.
(2 is a more flexible, "better" approach, but depending on the method
you may not be able to add this to an existing method without breaking
stable API.
> and I also saw the use of QProgressDialog in other parts of the core components code
That's likely just outdated code which hasn't been removed yet.
>
>
> - The second idea was to display an additional message dependant on the current QGIS instance's project state (whether it's loading/loaded/saving/closed) for which I had planned to introduce an enum QgisApp::ProjectState alongside with a private variable mProjectState and a public function QgisApp::getProjectState(). So would I make this accessible to the provider?
That property sounds potentially useful! (Just a note that QGIS code
convention is to name a getter "projectState()", not
"getProjectState(). We follow Qt conventions for naming as much as
possible).
But... (there's always a catch!) You can't (well, shouldn't) access
QgsProject from a data provider*. So you'd need to change the
behaviour at a higher level based on the project state instead. (e.g.
by not calling some expensive method which can be deferred from the
app level code)
Nyall
* the virtual data provider does this, but it's special, and really
shouldn't anyway.
>
>
> Best regards
>
> Tobias
>
> --
>
> ZAE Bayern
> Dipl.-Ing. Tobias Schmetzer
> Systementwicklung | Systems Engineering
> Bereich Energiespeicherung | Division Energy Storage
> Walther-Meißner-Straße 6
> 85748 Garching
>
> Tel.: +49 89 329442-65
> Fax: +49 89 329442-12
> Mobil | Cell: +49 151 56964756
> tobias.schmetzer at zae-bayern.de
> https://www.zae-bayern.de
>
> ZAE Bayern
> Bayerisches Zentrum für Angewandte Energieforschung e. V. | Bavarian Center for Applied Energy Research
> Vorstand | Board: Dr. Andreas Hauer (Vorsitzender | Chairman), Dr. Hans-Peter Ebert
> Sitz | Registered Office: Würzburg
> Registergericht | Register Court: Amtsgericht Würzburg
> Registernummer | Register Number: VR 1386
>
> Hinweise zum Datenschutz unter https://www.zae-bayern.de/datenschutz
>
>
>
> ________________________________
> Von: Nyall Dawson <nyall.dawson at gmail.com>
> Gesendet: Montag, 7. März 2022 00:03
> An: Schmetzer, Tobias
> Cc: qgis-developer at lists.osgeo.org
> Betreff: Re: [QGIS-Developer] How to access QgisApp::instance() from a core class
>
> On Sun, 6 Mar 2022 at 00:16, Schmetzer, Tobias via QGIS-Developer
> <qgis-developer at lists.osgeo.org> wrote:
> >
> > Hello everyone,
> >
> >
> > I would like to access QgisApp::instance() (src/app/qgisapp.cpp) from a provider like QgsOgrProvider::extent() (src/core/providers/ogr/qgsogrprovider.cpp.
>
> You can't, by design.
>
> CORE classes must be completely non-gui, so that they work without
> issue on non-gui platforms like QGIS server (also for clients which
> have their own GUI, such as QFIeld/Input).
>
> Just to be super-blunt: There is 100% no way this will EVER change! ;)
>
>
> > When looking for this information I found some inactivating preprocessor code block comments like this one (qgswfsdataitems.cpp):
> >
> > #if 0
> >
> > // TODO: how to emit message from provider (which does not know about QgisApp)
> > QgisApp::instance()->messageBar()->pushMessage( tr( "Cannot copy style" ),
> > errorMsg,
> > Qgis::MessageLevel::Critical, messageTimeout() );
> > #endif
>
> This is very old code (hence why it's disabled). Again, none of the
> core classes are allowed any GUI component, and the correct approach
> to handle this particular situation is to move that code from the
> provider level up to app level, specifically via the
> QgsDataItemGuiProvider class.
>
> So my question would be: why do you need to raise a user-facing
> message from QgsOgrProvider::extent?
>
> Nyall
More information about the QGIS-Developer
mailing list