How to pass value from one SLOT to another SLOT - qt

This question is absolutely a newbie question so I apologize for that. I have a SLOT which pretty much looks like this.
void MainWindow::on_actionSelect_for_hashing_triggered()
{
QFile file(QFileDialog::getOpenFileName (this, tr("Open File"),
"",tr("")));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QByteArray line = file.readAll();
}
Now I want to pass line to my another SLOT which is look like this..
void MainWindow::on_pushButton_clicked()
{
line2 = line; // QByteArray line2 has been assigned globally
qDebug()<<line2;
}
So here I simply want to print line2 which will receive value from line from first SLOT.
How might I do that ?

void MainWindow::on_actionSelect_for_hashing_triggered()
{
QFile file(QFileDialog::getOpenFileName (this, tr("Open File"), "",tr("")));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QByteArray line = file.readAll();
on_pushButton_clicked( line );
}
void MainWindow::on_pushButton_clicked( const QByteArray& line )
{
line2 = line; // QByteArray line2 has been assigned globally
qDebug()<<line2;
}
Just call the method and pass the byte array. If you need an on_pushButton_clicked(), then just overload or provide a default argument.
If you want to be able to connect/disconnect them at runtime, you will have to get on_actionSelect_for_hashing_triggered() to emit something that on_pushButton_clicked(..) can receive.
And I'm going to give the usual speech on not using global variables...

Related

How to wait for Async lamda function to finish before returning value in a QT Web Assembly

so I wrote a programm for my thesis in Qt and now i am supposed to turn it into a working web assembly, which wasnt a real problem except for the filedownload part. I rewrote my filedownload method from:
QString costumfile::read(QString filename){
QString fileName = QFileDialog::getOpenFileName(nullptr, filename, "", "Text Files (*.txt )");
QFile file(filename);
qDebug()<<filename<<"filename";
if(!file.open(QFile::ReadOnly |
QFile::Text))
{
qDebug() << " Could not open the file for reading";
return "";
}
QTextStream in(&file);
QString myText = in.readAll();
//qDebug() << myText;
file.close();
return myText;
}
To this:
QString costumfile::read(QString filename)
{
QMessageBox msgBox;
QString textUser="Open" + filename;
msgBox.setText(textUser);
msgBox.exec();
QString text="hallo";
qDebug()<<filename;
auto fileContentReady = [&](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
msgBox.setText("Error");
msgBox.exec();
} else {
text=fileContent;
qDebug()<<text<<"texstis";
return fileContent;
}
return fileContent;
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
and the problem is that the return doesnt wait for the lambda function because its asynch...
I then tried using eventloops which works fine in the Destop applikation but isnt supported in the webassembly Applikation.
So does someone have a good idea how to wait for the fileContentReady Function?
As far as I know, Qt for WebAssembly currently does not support waiting using event loops (at least Qt 6.2 does not). See Qt wiki:
"Nested event loops are not supported. Applications should not call e.g. QDialog::exec() or create a new QEventLoop object."
https://wiki.qt.io/Qt_for_WebAssembly
So you would have to modify your method to handle the asynchronous call. What I mean is that whatever you want to do with the file, you can write directly into the fileContentReady lambda you have. If this is a generic function, you can let the caller register a done callback to execute when the file is ready. Something like:
QString costumfile::read(QString filename,
const std::function<void(const QString&)>& done)
{
...
auto fileContentReady = [=](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
// Report error
} else {
text=fileContent;
qDebug()<<text<<"texstis";
done(text);
}
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
// When calling costumfile::read
read(filename, [=] (const QString& text) {
// Do something with `text`
});
Also, about the usage of QMessageBox exec(). This can also cause problems as it internally creates a nested event loop which is not yet supported in Qt for WebAssembly. Instead use the show() method.
auto msgBox = new QMessageBox();
msgBox->setText(textUser);
connect(msgBox, &QMessageBox::finished, &QMessageBox::deleteLater);
msgBox->show();

QPixmap.loadFromData() does not load image from QByteArray

I'm creating a socket-based program to send a screenshot from one user to another user. I need to convert a screenshot to a byte array before sending. After I convert my screenshot to a QByteArray I insert 4 bytes to the beginning of the array to mark that it is a picture (it is the number 20 to tell me it is a picture and not text or something else).
After I send the byte array via a socket to other user, when it is received I read the first 4 bytes to know what it is. Since it was a picture I then convert it from a QByteArray to QPixmap to show it on a label. I use secondPixmap.loadFromData(byteArray,"JPEG") to load it but it not load any picture.
This is a sample of my code:
void MainWindow::shootScreen()
{
originalPixmap = QPixmap(); // clear image for low memory situations
// on embedded devices.
originalPixmap = QGuiApplication::primaryScreen()->grabWindow(0);
scaledPixmap = originalPixmap.scaled(500, 500);
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
originalPixmap.save(&buffer,"JPEG",5);
qDebug() << bArray.size() << "diz0";
byteArray= QByteArray();
QDataStream ds(&byteArray,QIODevice::ReadWrite);
int32_t c = 20;
ds << c;
ds<<bArray;
}
void MainWindow::updateScreenshotLabel()
{
this->ui->label->setPixmap(secondPixmap.scaled(this->ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
void MainWindow::on_pushButton_clicked()
{
shootScreen();
}
void MainWindow::on_pushButton_2_clicked()
{
secondPixmap = QPixmap();
QDataStream ds(&byteArray,QIODevice::ReadOnly);
qint32 code;
ds>>code;
secondPixmap.loadFromData(byteArray,"JPEG");
updateScreenshotLabel();
}
Your MainWindow::on_pushButton_2_clicked implementation looks odd. You have...
QDataStream ds(&byteArray,QIODevice::ReadOnly);
which creates a read-only QDataStream that will read it's input data from byteArray. But later you have...
secondPixmap.loadFromData(byteArray,"JPEG");
which attempts to read the QPixmap directly from the same QByteArray -- bypassing the QDataStream completely.
You can also make use of the QPixmap static members that read from/write to a QDataStream. So I think you're looking for something like...
QDataStream ds(&byteArray,QIODevice::ReadOnly);
qint32 code;
ds >> code;
if (code == 20)
ds >> secondPixmap;
And likewise for your MainWindow::shootScreen implementation. You could reduce your code a fair bit by making use of QDataStream & operator<<(QDataStream &stream, const QPixmap &pixmap).

How to search for a string in a text file using Qt

I'm trying to search for a string in a text file; my aim is to write it only if it isn't already written inside my text file.
Here's my function (I don't know how to put inside the while loop):
QFile MyFile("text.txt");
MyFile.open(QIODevice::ReadWrite);
QTextStream in (&MyFile);
while(!MyFile.atEnd())
{ //do something to search string inside }
MyFile.close();
How can I do that? From Qt's Help, method "contains" works with const variable only; can I use it to look for my string?
You can do the following:
[..]
QString searchString("the string I am looking for");
[..]
QTextStream in (&MyFile);
QString line;
do {
line = in.readLine();
if (!line.contains(searchString, Qt::CaseSensitive)) {
// do something
}
} while (!line.isNull());
In case of not large file
QFile MyFile("text.txt");
MyFile.open(QIODevice::ReadWrite);
QTextStream in (&MyFile);
const QString content = in.readAll();
if( !content.contains( "String" ) {
//do something
}
MyFile.close();
To not repeat other answers in case of larger files do as vahancho suggested

Saving a qlistwidget after closing application

I have a program that allows for a user to create a profile that saves values using qsettings, the user accesses their profile by clicking on the name in a qlistwidget. I am trying to save the names of the profiles by using a text file but I am having trouble saving more than one profile name at a time. thank you! here is the code:
for saving a profilename to the text document
void Profile::writeProfilenames()
{
QString profilename = ui->lineEdit_profilename->text();
profilename = profilename.simplified();
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
QTextStream out(&pfile);
out << profilename;
pfile.flush();
pfile.close();
}
for retrieving the profile names from the document
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QString proname = pfile.readLine();
QListWidgetItem *itm = new QListWidgetItem;
itm->setText(proname);
ui->listWidget_profiles->insertItem(0,itm);
}
P.S. if you know of a better way to do this then feel free to share! (with example please)
I don't quite see why you're saving the list of names in a text file, while the settings themselves are saved in a platform-specific fashion using QSettings.
The code you show has several problems:
Presumably you don't want to "write" the name to the file, overwriting the existing contents at the beginning, but specifically to append to the file. You also must specify a writable path to the file, so far you're using the current working directory that is: variable, not under your control, and not necessarily writable. Your code also doesn't handle repeated names.
QFile is a proper C++ class, and embodies the RAII principles. You don't have to do anything to flush and close the file. The compiler takes care of generating the proper code for you. That's why you're using C++ and not C, after all. Yes, your code compiles, but it reads like C, and such verbosity is unnecessary and counterproductive.
You're only retrieving one name from the file. You want to retrieve all of them.
I'd say that you should dispense with the file access, set up your application's identification, a crucial prerequisite to using QSettings, and, finally, use them:
struct Profile {
QString name;
int age;
}
void saveProfiles(const QList<Profile> & profiles)
{
QSettings s;
s.beginWriteArray("profiles");
for (int i = 0; i < profiles.size(); ++i) {
s.setArrayIndex(i);
const Profile & p = profiles.at(i);
s.setValue("name", p.name);
s.setValue("age", p.age);
}
s.endArray(); //optional
}
QList<Profile> loadProfiles()
{
QList<Profile> profiles;
QSettings s;
int size = s.beginReadArray("profiles");
for (int i = 0; i < size; ++i) {
s.setArrayIndex(i);
Profile p;
p.name = s.value("name").toString();
p.age = s.value("age").toInt();
profiles << p;
}
s.endArray(); // optional
return profiles;
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
app.setOrganizationName("fluxD613"); // ideally use setOrganizationDomain instead
app.setApplicationName("fluxer");
...
return app.exec();
}
After a lot more research and trial and error I came up with the following code that does the trick:
this function is implemented when I close the profiles dialog window and return to the main window using QCloseEvent.
void Profile::writeProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QFile::WriteOnly | QIODevice::Text))
{
return;
}
for(int row = 0; row < ui->listWidget_profiles->count(); row++)
{
QListWidgetItem *item = ui->listWidget_profiles->item(row);
QTextStream out(&pfile);
out << item->text().simplified() << "\n";
}
pfile.close();
}
reading the list of profilenames is implemented when I open the dialog window just under ui->setup(this).
void Profile::readProfilenames()
{
QFile pfile("profilenames.txt");
if (!pfile.open(QIODevice::ReadOnly |
QIODevice::Text))
{
return;
}
QTextStream in(&pfile);
while (!in.atEnd())
{
QString line = in.readLine();
QListWidgetItem *item = new QListWidgetItem;
item->setText(line);
ui->listWidget_profiles->addItem(item);
}
pfile.close();
}
I am now working on making sure the user does not enter a profilename that already exists and deleting a profilename from the QListWidget.

Opening text file by using push button in Qt

what should be the contents in the area of signal and slots of the push button in the Qt, so that after clicking the push button only the text file will open.
void MainWindow::on_pushButton_clicked()
{
....
}
You can use whatever you want in order to open file, like FILE, fstream, QFile ecc. You simply call a class method, but inside that function you can put everything.
You're using Qt, so you can check QFile class of QT.
It can be done like:
void MainWindow::on_pushButton_clicked()
{
QFile file( filename );
if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
QMessageBox::warning(this, tr("Error opening!"), tr("Could not open the file"));
QTextStream stream( &file );
while( !stream.atEnd() )
{
QString lineText;
lineText = stream.readLine(); //Read a line of text
QStringList tokens= lineText.split(" ",QString::SkipEmptyParts); //Take tokens from the line
}
file.close();
}

Resources