I wrote this code:
void StartToSendCommand(QString fileName, QPlainTextEdit *textEdit)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTimer * inputTimer=new QTimer(textEdit);
QTextStream in(&file);
QString line;
while (!in.atEnd()) {
line = in.readLine();
if (line==""||line[0]=="#")
continue;
qDebug()<<line;
//TO DO: make also a waiting time between letters.
inputTimer->start(GWaitingTimeBetweenCommand);
QApplication::processEvents();
QThread::sleep(2);`
}
inputTimer->deleteLater();
SendCommandByUsb(fileName, line);
}
and I want to do that when its read from the file its also make a wait for 1 second between any letter.
how can I make it?
If you want to wait for individual letters, you can also do this with a QTimer interval. Once the condition is met, you can submit the file.
Here would be a small example, oriented towards a typewriter but has the same effect:
.h
....
private slots:
void typeWriter();
private:
QString line;
QTimer *timer;
....
.cpp
//constructor
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
line = "C:/.../readme.txt";
timer = new QTimer(this);
connect(timer,&QTimer::timeout, this, &MainWindow::typeWriter);
timer->start(1000);
}
void MainWindow::typeWriter()
{
static int counter = 0;
if(counter < line.length())
{
counter ++;
ui->label->setText(line.mid(0, counter));
//SendCommandByUsb(fileName, line.mid(0, counter));
timer->setInterval(1000);
qDebug() << counter << " : " << line.length() << " : " << line.mid(0, counter);
}
if(counter == line.length())
{
qDebug() << "end";
timer->stop();
}
}
the length of the string is compared with the counter. it is counted until it reaches the length of the string. the string method QString::mid can be thought of as a slice. it is sliced from index 0 (i.e. the beginning of the string) to the end, the counter takes care of that.
The timer interval defines the interval between the next call.
Just for info (because that's how the question read):
If you want to open a file and always want to wait a second for a letter to be read, you have to consider that you don't have a valid file path. Well that wouldn't make sense because you have to commit the file before anything is read at all.
Related
I'm trying to establish a live communication between a QT program and a VS C++ program. However, I can read anything unless I close the writechannel in which I can't write anything anymore. Furthermore, the code I have now reads a continuous stream of output when I write one line to the VS C++ program when it should be waiting for the next input. Is there a way to establish synchronous communication with the two? What is wrong with my current program?
I've read documentation and can't seem to get a clear answer.
My Qt code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
process = new QProcess(this);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
//connect(process, SIGNAL(readyReadStandardError()),this,SLOT(readOutput()));
process->setArguments(args);
process->setProgram("C:\\Users\\chten\\OneDrive\\Desktop\\QProcess\\test\\Debug\\test.exe");
process->start();
process->waitForStarted();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readOutput() {
ui->input->append(process->readAllStandardOutput());
}
void MainWindow::on_pushButton_2_pressed()
{
process->write("left");
process->waitForBytesWritten();
process->closeWriteChannel();
}
My C++ code:
cout << "waiting for response..." << endl;
string input_line;
//getline(cin, input_line);
//cout << input_line << endl;
while (true) {
getline(cin, input_line);
cout << input_line << endl;
for(int i = 0; i<9999999; i++){}
}
return 0;
I think the problem is that you never write a line to the child process, you just have...
process->write("left");
No newline. In the meantime the child is executing...
getline(cin, input_line);
waiting for the newline delimiter.
The reason closing the write channel appears to work is that it will cause the getline call in the child to receive an end-of-file condition and return. However, it will also set the eofbit in the input stream's state causing further calls to getline to return immediately: hence the "continuous stream of output" you refer to.
Try changing the implementation of MainWindow::on_pushButton_2_pressed to...
void MainWindow::on_pushButton_2_pressed ()
{
process->write("left\n");
process->waitForBytesWritten();
}
and change the child's source code to...
std::cout << "waiting for response..." << endl;
std::string input_line;
while (std::getline(std::cin, input_line)) {
std::cout << input_line << std::endl;
for(int i = 0; i<9999999; i++) {
}
}
return 0;
(All untested.)
As an aside, using Qt functions such as waitFoStarted, waitForBytesWritten etc. can be convenient but should be avoided. Far better to connect to and handle the various signals available.
I'm new to QT and I'm trying to create a program that shows different images depending on input from a serial interface.
I realize that there are a number of ways to achieve this and I'm looking for input from someone with experience in QT.
My idea was to send new data to a compare function that returns an integer to the main function, this integer will determine what picture will be shown. However, using a while loop results in the picture being re-drawn and not static.
My question is, should i start another thread for the image viewer, or use a different class for it?
Or is this approach hideous and should i start over?
Thankful for any input!
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
QObject::connect(&serial, &QSerialPort::readyRead, [&]
{
int comp=0;
int landscape =1;
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
comp= compare(total_data,datas);
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
qDebug() << datas;
});
This is the compare function that reads data from serial interface
int compare(int x, QByteArray y)
{
int r=0;
for(int i = 0; i <= x ; i++){
if (strncmp (y, "\x00",1) ==0)
{
//picture();
r=1;
return r;
}
}
return r;
}
By doing this:
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
You are creating a local QLabel on the stack. It will be destroyed at each iteration.
Qt uses its own mechanism to update its objects (the event loop) and you just have to change the picture in your QLabel when needed.
So, what you can do, it's creating a QLabel in your widget and change the image in your slot:
class Window: public QWidget
{
Q_OBJECT
public:
enum ImageType {
landscape = 1,
};
Window(QObject* parent=nullptr): QWidget(parent),
myLabel(new QLabel(this))
{
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
connect(&serial, &QSerialPort::readyRead, this, &Window::updateImage);
}
public slots:
void updateImage()
{
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
int const comp = compare(total_data,datas);
if (comp == Window::landscape)
myLabel->setPixmap("landscape.png");
else
myLabel->setPixmap("anotherImg.png");
qDebug() << datas;
}
private:
QLabel* myLabel;
QSerialPort serial;
};
You can use signals/slots and a thread (only if you want to do more actions during the program execution). It is very typical when using the serial line, as it is an asynchronus protocol that has to be pulled to know if there exist new data.
To do so, emit a signal every time you receive data from serial line and create a slot that process it. In this way you will use similar than an event driven system.
So i have 2 classes, one named ConsoleInput, which contains member function check4Flood and second named AntiFloodSys, in which connect function for signal-slot system is present, and also its signal (QTimer) and slot.
AntiFloodSys object is in check4Flood member function which scope never ends as inside there is infinite while loop. Thus the object is never destroyed. So when the object anti is created, the constuctor of AntiFloodSys class is called and therefore the connection between signal and slot.
My question at which point of the code the connection timeout signal and mySlot is separated, so the slot is never fired?
ConsoleInput cpp file looks like this:
void ConsoleInput::check4Flood(int& lineCounter)
{
AntiFloodSys anti;
while(1)
{
std::string chatLine[2];
std::cin >> chatLine[0] >> chatLine[1];
anti.input(chatLine[0], chatLine[1]);
}
}
and AntiFloodSys class like this:
AntiFloodSys::AntiFloodSys(QObject *parent) : QObject(parent)
{
timeFrame = 1000 ;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
timer->start(timeFrame);
std::cout << "AntiFloodSys constructor - timer starts " << "\n";
}
AntiFloodSys::~AntiFloodSys()
{
std::cout << "AntiFloodSys Destructor" << "\n";
}
void AntiFloodSys::input(std::string nick_, std::string line_)
{
nick = nick_;
line = line_;
std::cout << "nick: " << nick << " line: " << line << " " << "\n";
}
void AntiFloodSys::mySlot()
{
std::cout << "slot" << "\n";
}
The problem is your while(1): the Qt event loop is never processed because your program is blocked in this loop.
You can force the event loop processing calling QCoreApplication::processEvents() but the std::cin is a blocking function. So, it will not completly solve your problem.
You should move your loop in a dedicated thread that will send data to the main thread (e.g. signals/slots system).
You can also use the QSocketNotifier class to create a non blocking stdin access.
A quick example:
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(): QWidget(), input(new QLabel("Edit", this))
{
connect(this, &Widget::displayText, input, &QLabel::setText);
}
private:
QLabel* input;
signals:
void displayText(QString const&);
};
class UserInput: public QObject
{
Q_OBJECT
public:
UserInput(): QObject()
{}
public slots:
void run()
{
while(1) // User Input in an infinite loop
{
std::string line;
std::cin >> line;
emit inputReceived(QString::fromStdString(line));
}
}
signals:
void inputReceived(QString const&);
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
Widget* w = new Widget();
UserInput* input = new UserInput();
QThread* thread = new QThread();
input->moveToThread(thread); // Move the user input in another thread
QObject::connect(thread, &QThread::started, input, &UserInput::run);
QObject::connect(input, &UserInput::inputReceived, w, &Widget::displayText);
thread->start();
w->show();
return app.exec();
}
I am creating an application which prints text through a POS printer.
The prints works fine. But for POS printer there are control commands to do certain functions like : paper cut, cashdraw open etc.. For eg:
Function: Partial cut
Code:
ASCII———-> ESC i
Hex ————-> 1B 69
Decimal—-> 27 105
When I try to send command 27 105 it just prints on paper instead of performing action.. I’m not exactly sure how to send it… Can someone suggest how to write to the socket…
#include "lanprinterui.h"
#include "ui_lanprinterui.h"
LanPrinterUI::LanPrinterUI(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::LanPrinterUI)
{
ui->setupUi(this);
m_TextInput = ui->textEdit;
m_pSocket = new QTcpSocket();
m_pSocket->connectToHost("192.168.1.20", 9100);
m_ConnectStatus = true;
QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(print()));
}
LanPrinterUI::~LanPrinterUI()
{
delete ui;
delete m_pSocket;
}
void LanPrinterUI::print()
{
const int Timeout = 5 * 1000;
if (!m_ConnectStatus)
{
m_pSocket->connectToHost("192.168.1.20", 9100);
}
if (!m_pSocket->waitForConnected(Timeout))
{
//sent error
qDebug ("error in waitForConnected()");
qDebug (qPrintable(m_pSocket->errorString()));
m_ConnectStatus = false;
return;
}
m_ConnectStatus = true;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << m_TextInput->toPlainText();
out << '\n';
m_pSocket->write(block);
}
What you want is
out << "\n\x1Bi";
That is, you want, after the '\n' char, to send the '\x1B' char (also known as "escape") and the 'i' char. You could also have written this as:
out << '\n' << "\x1b\x69";
or:
out << '\n' << char(27) << char(105);
or:
out << '\n' << char(0x1b) << char(0x69);
(or any other valid combination)
Another, better idea, would be to put in your class:
class LanPrinterUI {
private:
static const QString PARTIAL_PAPER_CUT = "\x1bi";
static const QString CASHDRAWER_OPEN = "\x1b....";
//...
};
And then you would just:
out << '\n' << PARTIAL_PAPER_CUT;
(which would be much better than hardcoded constants)
This questions is often asked. Many recommend use readyReadStandardOutput for this purpose
What's the best way of implementation QProcess, which reading stdout and stderr in "real time"? I want to add messages in DisplayEdit. What i must change in my code (you can see it below )? May be use QThread for writing in DisplayEdit?
I've already the following code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QDebug>
#include <QCloseEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
process = new QProcess(this);
connect(process, SIGNAL(readyReadStandardOutput()),SLOT(slotDataOnStdout()));
connect(process, SIGNAL(readyReadStandardError()), SLOT(slotProcessError()));
connect(process, SIGNAL(error(QProcess::ProcessError)),SLOT(slotProcessError()));
connect(process, SIGNAL(started()),SLOT(slotProcessStart()));
connect(process, SIGNAL(finished(int)),SLOT(slotProcessFinish(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_EnterButton_clicked()
{
QStringList args = ui->ArgsEdit->text().split(" ");
QString cmd = ui->CommandEdit->text();
process->start(cmd, args);
}
void MainWindow::slotDataOnStdout()
{
qDebug() << "slotDataOnStdout";
ui->DisplayEdit->append(process->readAllStandardOutput() + '\n');
}
void MainWindow::slotStderr()
{
qDebug() << "std error";
}
void MainWindow::slotProcessError()
{
qDebug() << "error";
}
void MainWindow::slotProcessStart()
{
qDebug() << "start";
}
void MainWindow::slotProcessFinish(int exitCode)
{
qDebug() << "finish: " << exitCode;
QString str = process->readAllStandardOutput();
qDebug() << str;
}
And i want to execude the binary file of countdown timer. The code of my timer (i have took it from clock reference:
#include <stdio.h>
#include <time.h>
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
int main ()
{
int n;
printf ("Starting countdown...\n");
for (n=10; n>0; n--)
{
printf ("%d\n",n);
wait (1);
}
printf ("FIRE!!!\n");
return 0;
}
Looks mostly right. You did forgot to clean up the process, or think about what to do when the process isn't finished yet.
As for the timer, use the QTimer::timeout signal.