QT: signals from QMenu and QAction - qt

My problem is to make a menu to load files. Here's my code:
QStringList fileNameList;
fileNameList << "file1" << "file2" << "file3";
QMenuBar *menubar = new QMenuBar();
QMenu *menu = menubar->addMenu("File");
QMenu *load = menu->addMenu("Load");
foreach (QString fileName, fileNameList) {
QAction *loadFile = new QAction(fileName, this);
load->addAction(loadFile);
connect(load,SIGNAL(triggered(QAction*)),this, SLOT(load(QAction*)));
}
And a slot:
void MainWindow::load(QAction* action) {
qDebug() << action->text();
}
After I click any action button, qDebug shows:
"file1"
"file1"
"file1"
But I need to run that action only once! QAction does not have a signal from which I can get
its name. How to solve this? Thank you!

The problem is that you create the same connection tree times in the loop. What you probably need, is just doing it only once:
[..]
foreach (QString fileName, fileNameList) {
QAction *loadFile = new QAction(fileName, this);
load->addAction(loadFile);
}
connect(load, SIGNAL(triggered(QAction *)), this, SLOT(load(QAction *)));
UPDATE
The alternative solution would be:
foreach (QString fileName, fileNameList) {
QAction *loadFile = new QAction(fileName, this);
load->addAction(loadFile);
connect(loadFile, SIGNAL(triggered()), this, SLOT(load()));
}
with the corresponding slot:
void MainWindow::load() {
QAction *action = qobject_cast<QAction *>(sender());
if (action)
qDebug() << action->text();
}

Related

QProcess ReadAllStandardError()

I need to connect a QProcess to an error handler, but I'm unsure how to pass the error string to the slot. What's below compiles, but doesn't work.
QString MainWindow::RunProcess(QString cstring)
{
QProcess *process = new QProcess(this);
connect(process,SIGNAL(readyReadStandardError()),this,SLOT( adberror(process::ReadAllStandardError() ) ))
process->start(cstring);
}
void MainWindow::adberror(QString errtxt)
{
qDebug() << "error handler";
qDebug() << errtxt;
}
I can induce a a process error, but adberror() never triggers.
When run, in the Application Output pane I see:
QObject::connect: No such slot MainWindow::adberror(process::ReadAllStandardError() )
QObject::connect: (receiver name: 'MainWindow')
edit: this is Qt 5.6. I did a new qmake/clean.
you have two options
1- wait before reading the output
QString MainWindow::RunProcess(QString cstring)
{
QProcess process;
process.start(cstring);
process.waitForFinished();
QString str = process.readAllStandardOutput();
}
2- make you process a member variable and remove your 1st argument from adberror. So,
in RunProcess
connect(process,SIGNAL(readyReadStandardError()),this,SLOT(adberror()))
then in adberror
QString str = process->readAllStandardOutput();
note that in your code you have a problem since your signal and slot args don't to match .. Also, ReadAllStandardError is not going to be ready anyways !
Edit: more code for the 2nd solution
mainwindow.h
class MainWindow
{
private://methods
void adberror();
private://attributes
QProcess* process;
};
mainwindow.cpp
QString MainWindow::RunProcess(QString cstring)
{
process = new QProcess(this);
connect(process,SIGNAL(readyReadStandardError()),this,SLOT(adberror()));
connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
process->start(cstring);
}
void MainWindow::adberror()
{
QString str = process->readAllStandardOutput();
qDebug() << str;
}
To process the readyReadStandardError() signal you should define the slot as:
private slots:
void adberror();
and use it:
connect(process,SIGNAL(readyReadStandardError()),this,SLOT( adberror() ));
i.e. with no arguments. Keep child process as a field of your MainWindow class to read data when it will be available.

How to select file from MainMenu in Qt?

I load all text files from my folder to the MainMenu in my Qt application.
void MainWindow::loadFilesToMainMenu() {
QString pathToDir("/myfiles");
QDirIterator it(pathToDir, QStringList() << "*.txt", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QString curPathName = it.next();
QStringList fileSegments = curPathName.split('/');
QString curFileName = fileSegments.at(fileSegments.size() - 1);
QAction* action = new QAction(tr(curFileName.toStdString().c_str()), this);
action->setStatusTip(tr(curPathName.toStdString().c_str()));
ui->menuFileList->addAction(action);
// if new style selected?
connect(action, SIGNAL(triggered()), this, SLOT(onLoadFile()));
}
}
There I create QActions for all files in my folder 'myfiles' and I connect these each of these ations to the SLOT onLoadfile():
void MainWindow::onLoadFile() {
QAction *action = qobject_cast<QAction *>(sender());
if (action)
{
qDebug() << " onLoadFile " << action->data().toString();
}
}
So each time I select one of those files in my MainMenu, this SLOt is triggered, but my debug message says:
onLoadFile ""
When I for instance select /myfiles/file1.txt
onLoadFile "/myfiles/file1.txt"
Wham am I missing? Thanx in advance
The answer from #m.s. solves my question very well...
You should use QAction::setData() before trying to read the data – m.s

Multiple file insert in QTreewidget using Drag and Drop events

I am working in Qt4.7 on MAC OSx. I want to insert files in QTreewidget using the Drag and Drop events. I want to add multiple files at a time. I am using this:
void MainWindow::dragEnterEvent(QDragEnterEvent * e)
{
if(e->mimeData()->hasUrls())
{
e->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent * e)
{
QTreeWidgetItem *Items = new QTreeWidgetItem(ui->treeWidget);
foreach(const QUrl &url,e->mimeData()->urls())
{
const QString &filename = url.toLocalFile();
qDebug() << "Dropped file:" << filename;
Items->setText(0,filename);
}
}
Using this, I am able to insert only one file at a time. Is there anyone who can help me out in this issue ? Your help will really appreciate.
Thanks,
Ashish.
The problem is that you create only one tree view item. However you need one per each Url you passed with the mime data:
void MainWindow::dropEvent(QDropEvent *e)
{
foreach(const QUrl &url, e->mimeData()->urls()) {
QString filename = url.toLocalFile();
qDebug() << "Dropped file:" << filename;
QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
item->setText(0, filename);
}
}

Connect slots QAction dynamically to a function

I want to add some QAction dynamically from settings file :
_settings.beginGroup("openRecent");
QStringList recentList = _settings.childKeys();
foreach(QString recentFile, recentList)
{
QAction * action = new QAction(_settings.value(recentFile, "empty").toString(), this);
action->setObjectName(_settings.value(recentFile, "empty").toString());
connect(action, SIGNAL(triggered()), this, openFile(action->objectName()));
_recentFileButtons.append(action);
}
_settings.endGroup();
which fails to compile due to this line connect(action, SIGNAL(triggered()), this, openFile(action->objectName()));
Question :
How do I connect a QAction to a given function (with parameters)?
you can't, not directly
there are 2 options available:
use sender() to get the sending QObject and use that
use a QSignalMapper which will add a single parameter to the signal
signalMapper->setMapping(action, action->objectName());
connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
and connect signalMapper to this:
connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(openFile(QString)));
You cannot pass parameters in that way. I would suggest to do the following:
connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
And in your openFile() slot just do:
void MyClass::openFile()
{
QObject *obj = sender();
QString objName = obj->objectName();
[..]
}

Qt HTTP GET freezes screen

I'm writing a Qt program to get an image from site and insert in a QLabel. When I send my request my screen freezes and nothing more occurs.
Notice I'm new in Qt.
Based on my initial knowledge of Qt it's enough send a signal when download is finished.
...
MapReader::MapReader(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
imageLabelMap = ui.imageMap;
getImageButton = ui.getImageButton;
networkManager = new QNetworkAccessManager(this);
setup();
}
MapReader::~MapReader()
{
}
void MapReader::setup()
{
QObject::connect(getImageButton, SIGNAL(clicked()), this, SLOT(triggerDownload()));
QObject::connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedDownload(QNetworkReply*)));
}
void MapReader::setImage(QByteArray imageBytes)
{
QImage map;
...
}
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
}
void MapReader::finishedDownload(QNetworkReply* reply)
{
reply->deleteLater();
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
}
I think there is some code missing that might give us a clue. You have
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
But I don't see where loop is defined? Sounds like you are running an additional event loop?
Regardless, you don't need that. This should be as simple as:
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(finished()), this, SLOT(finishedDownload()));
}
void MapReader::finishedDownload()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); // sender() allows us to see who triggered this slot - in this case the QNetworkReply
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
reply->deleteLater();
}
Make sure you have defined finishedDownload() as a slot in your header file

Resources