Как использовать сигнал в базовом классе от всего унаследованного класса в qt?

У меня есть приложение QT Quick 2, у меня есть базовый класс для моих классов C ++

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;
};

У меня есть много классов, которые унаследовали от класса выше

class BookManager : public ManagerEngine
{
};

void BookManager::getList(bool refreshList){
setIsProcssing(true);
//get data from server
setIsProcssing(false);
}

Сейчас в этих классах я хочу показать BusyIndicator когда метод получает некоторые данные с сервера.

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
}

Все работает нормально в BookPage.qml и … (выше) и на странице thease будет отображаться busyIndicator. Но я хочу сделать это вовремя.

Я попробовал это: я использую базовый классManagerEngine для отображения BusyIndicator

Я хочу отобразить busyIndicator, как показано ниже. (Я объявил базовый класс на главной странице. Теперь, если я открою BookPage.qml для отображения списка книг, теперь busyIndicator должен быть видимым

main.qml

ManagerEngine{
id: me
onIsProcessingChanged: {
progressIndicator.visible=isProcessing;
}
}
BusyIndicator{
id:busyIndicator
}

Но это не работает. Есть ли другой способ сделать эту работу (например, могу ли я использовать статическое ключевое слово)

0

Решение

Это никогда не сработает, поскольку кажется, что эти классы работают в основном потоке, и когда обработка выполняется, обновления пользовательского интерфейса не выполняются, а ваше приложение заморожено.

Во всех случаях решение должно начинаться с того, чтобы сделать индикатор занятости надлежащим свойством — это волшебным образом решит ваши проблемы с Qt Quick, и вы можете просто связать это свойство и вообще не использовать сигнал явно. Вот для чего нужны уведомления о свойствах, и QML обрабатывает их для вас. Вы также не хотите, чтобы установщик был общедоступным — это внутреннее состояние только для чтения. Вам также нужны постоянные правильные подписи.

После устранения всех проблем мы получаем:

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;
}

Если вы хотите, чтобы обработка была состоянием, общим для всех экземпляров механизма менеджера, то сделайте это свойством класса, а не объекта. В C ++ static Объявление члена означает, что это член класса, а не член объекта.

Интерфейс

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;
}
0

Другие решения

Других решений пока нет …