У меня есть считыватель данных, который берет данные из буфера и отображает вывод на консоль. Теперь я хочу видеть данные в текстовом режиме в режиме реального времени.
Я видел несколько примеров, показывающих, как данные могут быть прочитаны из текстового файла (не в режиме реального времени).
См. приложение.
/* Create a DataReader for the chatMessageTopic Topic (using the appropriate QoS). */
parentReader = chatSubscriber->create_datareader(
chatMessageTopic.in(),
DATAREADER_QOS_USE_TOPIC_QOS,
NULL,
STATUS_MASK_NONE);
checkHandle(parentReader.in(), "DDS::Subscriber::create_datareader");
/* Narrow the abstract parent into its typed representative. */
chatAdmin = Chat::ChatMessageDataReader::_narrow(parentReader.in());
checkHandle(chatAdmin.in(), "Chat::ChatMessageDataReader::_narrow");
/* Print a message that the MessageBoard has opened. */
cout << "MessageBoard has opened: send ChatMessages...." << endl << endl;
while (!terminated) {
/* Note: using read does not remove the samples from
unregistered instances from the DataReader. This means
that the DataRase would use more and more resources.
That's why we use take here instead. */
status = chatAdmin->take(
msgSeq,
infoSeq,
LENGTH_UNLIMITED,
ANY_SAMPLE_STATE,
ANY_VIEW_STATE,
ALIVE_INSTANCE_STATE );
checkStatus(status, "Chat::ChatMessageDataReader::take");
for (DDS::ULong i = 0; i < msgSeq->length(); i++) {
ChatMessage *msg = &(msgSeq[i]);
cout << msg->index << ": " << msg->content << endl;
fflush(stdout);
}
status = chatAdmin->return_loan(msgSeq, infoSeq);
checkStatus(status, "Chat::ChatMessageDataReader::return_loan");
Вы, вероятно, не хотите, чтобы ваш пользовательский интерфейс обновлялся с частотой 1000 Гц. Так что нет смысла запускать этот код в занятом цикле. Вместо этого запустите его с разумной частотой обновления, например, 30 Гц, от таймера.
По соображениям производительности это может помочь генерировать пакеты строк, а также отдельные строки для журнала:
Давайте отвлечемся от этого:
class DDSProcessor : public QObject {
Q_OBJECT
QBasicTimer m_timer;
DDS::Subscriber * m_chatSubscriber;
Chat::ChatMessageDataReader * m_chatDataReader = nullptr;
...
Q_SIGNAL void message(const QString &);
Q_SIGNAL void messages(const QStringList &);
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
auto status = chatAdmin->take(
msgSeq,
infoSeq,
LENGTH_UNLIMITED,
ANY_SAMPLE_STATE,
ANY_VIEW_STATE,
ALIVE_INSTANCE_STATE );
checkStatus(status, "Chat::ChatMessageDataReader::take");
QStringList texts;
for (DDS::ULong i = 0; i < msgSeq->length(); i++) {
auto msg = &(msgSeq[i]);
auto text = tr("%1: %2").arg(msg->index).arg(msg->content);
texts << text;
emit message(text);
}
emit messages(texts);
status = chatAdmin->return_loan(msgSeq, infoSeq);
checkStatus(status, "Chat::ChatMessageDataReader::return_loan");
}
public:
void start() {
auto reader = m_chatSubscriber->create_datareader(
m_chatMessageTopic.in(), ...);
checkHandle(read.in(), "DDS::Subscriber::create_datareader");
m_chatDataReader = Chat::ChatMessageDataReader::_narrow(reader.in());
checkHandler(m_chatDataReader.in(), "Chat::ChatMessageDataReader::_narrow");
auto text = tr("MessageBoard had opened: send ChatMessages.");
emit message(text);
emit messages(text);
m_timer.start(this, 1000/30);
}
...
};
Я недостаточно знаком с библиотекой DDS, но есть некоторые обратные вызовы, которые вы должны использовать, чтобы вместо этого получать уведомления, и тогда вы будете испускать сигнал (сигналы) от обратных вызовов. Это устранит необходимость в явном цикле обновления пользовательского интерфейса.
Все, что вам нужно сделать в пользовательском интерфейсе, это обработать сообщения, отправленные DDSProcessor:
void setup(DDSProcessor * src, QTextEdit * dst) {
connect(src, &DDSProcessor::message, dst, &QTextEdit::append);
}
Обратите внимание, что оба QTextEdit
а также QPlainTextEdit
очень медленные и не подходят для быстрой регистрации. Самый простой обходной путь — использовать модель списка с QListView
и использовать сигнал записи в пакетном журнале:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
QStringListModel logModel;
QListView view;
DDSProcessor processor;
QObject::connect(&processor, &DDSProcessor::messages, &logModel, [&](const QStringList & texts){
auto row = logModel.rowCount();
logModel.insertRows(row, texts.count());
for (auto const & text : texts)
logModel.setData(model.index(row++), text);
});
view.setModel(&logModel);
view.show();
view.setUniformItemSizes(true); // needed for performance
...
return app.exec();
}
Вот минимальный пример синхронного входа в GUI:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPlainTextEdit edit;
edit.show();
int x = 0;
while (edit.isVisible()) {
x++;
edit.appendPlainText(QString("test %1").arg(x));
qApp->processEvents();
}
return 0;
}