#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 обновляется при изменении значения статуса.