Reputation: 1806
I have a qt quick 2 application,I have base class for my c++ classes
class ManagerEngine : public QObject
{
Q_OBJECT
public:
explicit ManagerEngine(QObject *parent = nullptr);
bool isProcessing();
void setIsProcssing(bool isProcessing);
signals:
void isProcessingChanged(bool isProcessing);
private:
bool m_IsProccessing;
};
I have many class that has inherited from above class
class BookManager : public ManagerEngine
{
};
void BookManager::getList(bool refreshList){
setIsProcssing(true);
//get data from server
setIsProcssing(false);
}
Now in thease classes I want to show BusyIndicator
when the method is getting some data from server.
BookPage.qml
BookManager{
id: bm
onIsProcessingChanged: {
busyIndicator.visible=isProcessing; // busyIndicator is in main.qml
}
}
CategoryPage.qml
CategoryManager{
id: cm
onIsProcessingChanged: {
busyIndicator.visible=isProcessing;
}
}
QuestionPage.qml
QuestionManager{
id: qm
onIsProcessingChanged: {
busyIndicator.visible=isProcessing;
}
}
//I have many class like : login signup and ... inherited from base class
main.qml
BusyIndicator{
id:busyIndicator
}
All works ok in BookPage.qml
and ... (above) and in thease page busyIndicator will display.But I want do this on time.
I tryed this: I use base classManagerEngine
for display BusyIndicator
I want to display busyIndicator Like below.(i Declared Base class in main page.Now if i open BookPage.qml for display book list,now the busyIndicator must be visible
main.qml
ManagerEngine{
id: me
onIsProcessingChanged: {
progressIndicator.visible=isProcessing;
}
}
BusyIndicator{
id:busyIndicator
}
But It don't work.Is there another way for doing this work(for example can i use static keyword)
Upvotes: 0
Views: 854
Reputation: 98425
This won't ever work, because those classes seem to work in the main thread, and when the processing is being done, no user interface updates are taking place, and your application is frozen.
In all cases, the solution has to begin with making the busy indicator a proper property - this will magically fix your Qt Quick problems, and you can simply bind to the property and not have to use the signal explicitly at all. That's what property notifications are for, and QML handles them for you. You also don't want the setter to be public - this is internal, read-only state. You also want const-correct signatures.
After fixing all of the problems, we get:
class ManagerEngine : public QObject {
Q_OBJECT
Q_PROPERTY(bool isProcessing READ isProcessing NOTIFY isProcessingChanged)
public:
using QObject::QObject; //for C++14 & up
bool isProcessing() const;
Q_SIGNAL void isProcessingChanged(bool);
protected:
void setIsProcessing(bool);
private:
bool m_isProccessing = false;
};
/// This method is not thread-safe
void ManagerEngine::setIsProcessing(bool p) {
if (p == m_isProcessing) return;
m_isProcessing = p; // precondition of the signal
return emit isProcessingChanged(m_isProcessing);
}
/// This method is not thread-safe
bool ManagerEngine::isProcessing() const {
return m_isProcessing;
}
If you want the processing to be a state shared across all instances of the manager engine, then make it a property of the class, not of the object. In C++, a static
member declaration means that it's a class member, not object member.
class ManagerEngine : public QObject {
Q_OBJECT
Q_PROPERTY(bool isProcessing READ isProcessing NOTIFY isProcessingChanged)
public:
using QObject::QObject; //for C++14 & up
~ManagerEngine() override;
bool isProcessing() const;
Q_SIGNAL void isProcessingChanged(bool);
protected:
void setIsProcessing(bool);
private:
bool m_isProcessing = false; // per-object
static QAtomicInt m_processingCount; // per-class
};
QAtomicInt ManagerEngine::m_processingCount;
ManagerEngine::~MangerEngine() {
setIsProcessing(false);
// Perhaps it'd be more appropriate instead to simply
// Q_ASSERT(!m_isProcessing) if the engine should not be destroyed
// during processing.
}
// This method is not thread-safe, but multiple engines can
// reside in different threads.
void ManagerEngine::setIsProcessing(bool p) {
if (p == m_isProcessing) return;
int const delta = p ? (+1) : (-1);
auto count = m_processingCount.load();
Q_ASSERT(count >= 0);
Q_ASSERT(p || count > 0);
m_isProcessing = p;
while (!m_processingCount.testAndSetOrdered(count, count+delta)) {
count = m_processingCount.load();
}
// The signal will be emitted only when the global state changes,
// and exactly once per global state change.
if ((count > 0) != ((count+delta) > 0))
emit isProcessingChanged(count > 0);
return;
}
// Note: Due to data races, it is not guaranteed that the result of
// this method is the same as the parameter in the isProcessingChanged
// signal. Only the signal's parameter is guaranteed to change state
// in a race-free fashion, i.e. always toggle (alternate) and never repeat.
bool ManagerEngine::isProcessing() const {
auto const count = m_processingCount.load();
Q_ASSERT(count >= 0);
Q_ASSERT(!m_isProcessing || count > 0);
return count > 0;
}
Upvotes: 1