Как получать текущие обновления переменных в строке состояния в C с помощью сигналов и слотов Qt?

#c #qt #statusbar #signals-slots

#c #qt #строка состояния #сигналы-слоты

Вопрос:

Я использую проприетарный API-интерфейс драйвера в своем приложении на C / Qt. Существует объект с именем «статус», который по сути является целочисленным значением, которое можно использовать для отслеживания ошибок. Значение 0 указывает на то, что все в порядке, отрицательное значение — это конкретная ошибка. Я хотел бы запрограммировать строку состояния (используя QStatusBar Qt), которая будет предоставлять мне текущие обновления с текущим значением «статус» по мере выполнения частей кода. Упрощенный пример того, что у меня есть в настоящее время:

DriverInterfaceClass.h

 #ifndef DRIVERINTERFACECLASS_H
#define DRIVERINTERFACECLASS_H

#include <QObject>
#include "multicam.h"

class DriverInterfaceClass : public QObject
{
    Q_OBJECT
public:
    DriverInterfaceClass(QObject *parent = nullptr);
    ~DriverInterfaceClass();

private:
    void setStatus(int value);

private:
    MCSTATUS status;

signals:
    void statusChanged(const QStringamp; status, int timeout);
};

#endif // DRIVERINTERFACECLASS_H
 

DriverInterfaceClass.cpp

 #include "driverinterfaceclass.h"

DriverInterfaceClass::DriverInterfaceClass(QObject *parent)
    : QObject(parent)
{
    setStatus(McOpenDriver(NULL));
    status = McSetParamStr(MC_CONFIGURATION, MC_ErrorLog, "error.log");
}

DriverInterfaceClass::~DriverInterfaceClass()
{
    setStatus(McCloseDriver());
}

void DriverInterfaceClass::setStatus(int value)
{
    status = value;
    QString statusStr = QString::number(status);
    emit statusChanged(statusStr, 0);
}
 

Главное окно.h

 #ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "driverinterfaceclass.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    DriverInterfaceClass *driver;
};
#endif // MAINWINDOW_H
 

MainWindow.cpp

 #include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    driver = new DriverInterfaceClass(this);
    connect(driver, amp;DriverInterfaceClass::statusChanged, ui->statusbar, amp;QStatusBar::showMessage);
}

MainWindow::~MainWindow()
{
    delete ui;
}
 

У меня проблема с выяснением, как обновить строку состояния значением переменной «статус». Я не получаю никаких сообщений в строке состояния с помощью этого кода. Возможно, я что-то упускаю в том, как я инициализирую свою переменную?

Комментарии:

1. Статус не должен устанавливаться вручную. Что-то, например DriverInterfaceClass . должно справиться с этим.

2. На самом деле мне нужно, чтобы статус обновлялся независимо от того, выполнено ли условие status != value — я хочу, чтобы строка состояния получала соответствующее значение из нескольких точек в моем программном обеспечении. Что вы имеете в виду, говоря, что класс должен справиться с этим?

3. Подумайте об этом так: имеет ли смысл прийти ко мне и сказать, что я чувствую, или лучше СПРОСИТЬ меня, что я чувствую.

4. Другими словами, интерфейс драйвера не должен иметь общедоступного метода установки статуса. Вместо этого статус должен быть установлен внутри компании. для внешнего мира статус является свойством, доступным только для чтения DriverInterfaceClass .

5. Это, конечно, имеет смысл. Однако моя переменная состояния каким-то образом не обновляется с этими настройками параметров, поэтому я получаю значение, с которым оно было инициализировано каждый раз при использовании метода getter.

Ответ №1:

Причина

statusChanged Сигнал страдает от неосознаваемого существования. Другими словами, driver объект кричит — СТАТУС ЧАААААААНГЕД!!!!, но никто этого не слышит. И вот почему.

Ваш код выполняется в следующем порядке:

 driver = new DriverInterfaceClass(this);
 

Затем, как часть конструктора:

 setStatus(McOpenDriver(NULL));
status = McSetParamStr(MC_CONFIGURATION, MC_ErrorLog, "error.log");
 

Только после этого выполняется оператор connect:

 connect(driver, amp;DriverInterfaceClass::statusChanged, ui->statusbar, amp;QStatusBar::showMessage);
 

Очевидно, что сигнал излучается setStatus ДО того, КАК он будет подключен к слоту of ui->statusbar .

Примечание: Вы также устанавливаете значение status напрямую, без вызова setStatus , т. е. status = McSetParamStr(... Таким образом, сигнал вообще не передается. Однако вызов setStatus вместо этого не поможет по той же причине, что и выше.

Перемещение connect раньше new приведет к ошибке компилятора, потому что вы не можете подключиться к чему-то, чего не существует.

Решение

Не излучайте сигналы от конструкторов. Делайте это, когда происходит какое-то событие.

Комментарии:

1. Спасибо @scopchanov! Вот почему мой пример не работал. Я следил за вашим ответом, и после вызова нового метода для открытия драйвера вне конструктора строка состояния была обновлена, как и ожидалось.

2. @szumial, добро пожаловать! Я рад, что ваша проблема решена.

Ответ №2:

Чтобы удовлетворить вашему инварианту «испускать сигнал всякий раз, когда установлен статус», вам нужно использовать setStatus(McSetParamInt(... whatever)); метод, не изменяйте status = xxx; напрямую (кроме тела setStatus метода). Затем просто немного измените свою функцию настройки, чтобы также выдавать информацию о желаемом сообщении, которое будет отображаться на QStatusBar :

 void DriverInterfaceClass::setStatus(int value)
{
    if (status != value)
    {
        status = value;
        emit statusChanged(myStatusValueToString(status));
    }
}
 

где должен быть сигнал decl:

 signals:
    void statusChanged(const QStringamp; msg);
 

и myStatusValueToString это просто простое сопоставление:

 QString myStatusValueToString(int status)
{
  if (status == 0) return "OK";
  ... etc ...
}
 

Соединение должно выглядеть следующим образом:

 QObject::connect(driver, amp;DriverInterfaceClass::statusChanged, statusBar, amp;QStatusBar::showMessage);
 

Комментарии:

1. Я думаю, вы неправильно поняли вопрос. OP уже сделал это и имеет проблемы с вызовом setStatus , а не с его реализацией.

2. Я думаю, что, по крайней мере, первое предложение этого ответа должно быть полезным для OP. Не вносите изменения за пределами функции настройки. status

3.Да, честно говоря, вопрос мне не на 100% понятен. Я думал, что основная проблема заключается в том, что OP пытается вызвать status = McSetParamInt(...); status = getStatus(); setStatus(status) , что является а) избыточным, б) не определяет, изменился статус или нет; Давайте подождем, пока он прокомментирует.

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

5. @szumial Хорошо, тогда вам нужно отредактировать вопрос с помощью воспроизводимого примера (да, я знаю, что для Qt это может быть немного больше кода, чем обычно) проблемы, потому что для меня это работает так, как должно, т.Е. QStatusBar обновляется при изменении значения статуса.