QfileSystemWatcher doesn't work - qt

This is how I am initializing the watcher:
QFileSystemWatcher watcher;
bool isWatched = watcher.addPath("../stylesheets/main.style");
if (isWatched) qDebug() << "Stylesheet is being watched.";
connect(&watcher, &QFileSystemWatcher::fileChanged, this, &PCLViewer::updateStyle );
But my update style function never gets called, when I modify, delete or rename the file! I've also tried connecting the slots and signals like this:
connect(&watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateStyle(QString)) );
The signature for the updateStyle functions is this:
public slots:
void updateStyle(const QString &path);
I'm using ubuntu.

If anyone is having the same problem.
Try this:
QFileSystemWatcher *watcher = new QFileSystemWatcher();
bool beingWatched = watcher->addPath("Enter your path here");
if (beingWatched ) qDebug() << "Being watched";
QObject::connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(handleFileChanged(QString)));
I don't know why but you need to create a pointer, at least on my system, to emit a signal or it won't work.

The slot function signature was wrong. I had to use void updateStyle (QString path); for it to get called.

Related

qt6: Connect QFileDialog::filesSelected to a slot

Essentially I want to trigger some code after the my QFileDiag has 1 or more files selected and is accepted ("open" button clicked), the problem is that I can't seem to actually trigger my code in the slot.
Here is the code in my main widget
file_select_diag = new QFileDiag(this)
connect(file_select_diag, &QFileDialog::fileSelected, this,
&MainWidget::connect_test);
auto files = file_select_diag->getOpenFileName(
this,
tr("test"),
QDir::homePath(),
tr("text (*.txt)");
void MainWidget::connect_test(QString str)
{
cout << str.toStdString();
}
And here is the header declaration
{
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = 0); //Constructor
~MainWidget(); // Destructor
private slots:
void connect_test(QString str);
void connect_test2(); //like above but cout << "HIT" << end;
private:
QFileDialog *file_select_diag;
I've tried connecting to both connect_test and connect_test2, when I run my app and select files, hit open, nothing happens.
Solution (copied from G.M.'s comment below)
Note that QFileDialog::getOpenFileName is a static member of
QFileDialog so the call file_select_diag->getOpenFileName(...)
effectively creates a QFileDialog instance independent of
file_select_diagand calls getOpenFileName against that.
So effectively the two approaches here are either go entirely with the static method getOpenFileName and do not initialize file_select_diag or go entirely for the instance approach, configure the file_select_diag then use file_select_diag->show(), in which case the signal will work.

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 use connect with member function

I want to connect the tabBarDoubleClicked signal with a member function but the compiler keeps barking at me with:
/home/ron/src/kterminal/sessionstack.cpp:79:56: error: invalid use of non-static member function
this, SessionStack::editTabLabel(session->id()));
^
and I'm not sure how to fix it, my code looks like:
int SessionStack::addSession(Session::SessionType type)
{
Session* session = new Session(type, this);
connect(session, SIGNAL(titleChanged(int,QString)), this, SIGNAL(titleChanged(int,QString)));
connect(session, SIGNAL(terminalManuallyActivated(Terminal*)), this, SLOT(handleManualTerminalActivation(Terminal*)));
connect(session, SIGNAL(activityDetected(Terminal*)), m_window, SLOT(handleTerminalActivity(Terminal*)));
connect(session, SIGNAL(silenceDetected(Terminal*)), m_window, SLOT(handleTerminalSilence(Terminal*)));
connect(session, SIGNAL(destroyed(int)), this, SLOT(cleanup(int)));
m_sessions.insert(session->id(), session);
QString tab_label = QString("Shell (") + QString::number(session->id(), 16) + ")";
addTab(session->widget(), tr(qPrintable(tab_label)));
emit sessionAdded(session->id());
raiseSession(session->id());
connect(this, tabBarDoubleClicked,
this, SessionStack::editTabLabel(session->id()));
return session->id();
}
void SessionStack::editTabLabel(int tabIndex)
{
How can I get editTabLabel() invoked when the tab is double clicked?
EDIT1
In my header I have the following declared:
class SessionStack : public QTabWidget
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kterminal")
public:
explicit SessionStack(QWidget* parent, QWidget* window);
~SessionStack();
private slots:
void tabBarDoubleClicked(int index);
void editTabLabel(int tabIndex);
};
the error occurs because you just forgot to add SIGNAL and SLOT macros at
connect(this, tabBarDoubleClicked, this, SessionStack::editTabLabel(session->id()));
You can't pass session->id() while connecting, you can only pass the argument when you emit the signal.
Please note that your code is not going to connect anyway in runtime since the signal misses an argument (int), so that it matches the editTabLabel slot. So you need to fix that as well.. should be
connect(this, SINGAL(tabBarDoubleClicked(int), this, SLOT(editTabLabel(int)));
if the signal "tabBarDoubleClicked" is builtin and you can't change it to add an argument then you might consider QSignalMapper http://doc.qt.io/qt-5/qsignalmapper.html

Why can't I use QMessageBox in QApplication::notify() derived method

As I understand it, the way to handle exceptions happening inside the event loop in Qt is to override QApplication::notify() and handle it there. I have tried that and it works:
class Application : public QApplication
{
Q_OBJECT
public:
explicit Application( int& argc, char** argv );
// override to handle out of memory exceptions
bool notify( QObject* receiver, QEvent* e );
signals:
public slots:
private:
char* m_buffer;
};
Application::Application(int &argc, char **argv)
:QApplication( argc, argv )
{
m_buffer = new char[1024*1024];
}
bool Application::notify(QObject *receiver, QEvent *e)
{
try
{
return QApplication::notify( receiver, e );
}
catch( std::bad_alloc& )
{
if ( m_buffer )
{
delete[] m_buffer;
m_buffer = NULL;
}
// calling QMessageBox from here doesn't work
// even if release a load of reserved memory
// don't know why
QMessageBox::critical( NULL, "Exception", "Application out of memory" );
}
But the message box is blank when it appears (i.e. not rendered correctly). I thought perhaps the process didn't have enough memory. So I tried allocating 1MB of memory at the start (see m_buffer above) and then releasing it before the QMessageBox displayed. But that didn't work either. Any ideas?
I could be interpretting QApplication::notify wrong, but I'm getting the impression that you're attempting to create a GUI object (QMessageBox) when the Qt event loop crashes. I don't believe that's possible.
For exception safety, my understanding is that you have to wrap the whole QApplication::exec function with a try-catch sequence, as in the Exception Safety docs.
Consider implementing a custom error handler using qCritical and qWarning. I like to redirect those functions to a log file in my temp directory to debug crashes. Of course, your program still crashes unlike in exception handling, but at least you know why. I can provide example code if necessary.
QMessageBox::exec(), which is used by the static convenience methods critical(), warning(), etc., opens a local event loop and only returns to the main event loop once the message box is closed. Local event loops are nasty in general, opening in the midst of event handling (QApplication::notify) is even more so. You better use QDialog::open to open the message box without blocking, or even better, defer the message box:
In your application class:
Q_INVOKABLE void showMessage( const QString& message ); // in your Application class, does the QMessageBox::critical() call
Instead of calling QMessageBox::critical() directly, replace it by something like this:
QMetaObject::invokeMethod( this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, "Application out of memory") );

How to delete a QProcess instance correctly?

I have a class looking like this:
class FakeRunner : public QObject
{
Q_OBJECT
private:
QProcess* proc;
public:
FakeRunner();
int run()
{
if (proc)
return -1;
proc = new QProcess();
QStringList args;
QString programName = "fake.exe";
connect(comp, SIGNAL(started()), this, SLOT(procStarted()));
connect(comp, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(procError(QProcess::ProcessError)));
connect(comp, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(procFinished(int, QProcess::ExitStatus)));
proc->start(programName, args);
return 0;
};
private slots:
void procStarted() {};
void procFinished(int, QProcess::ExitStatus) {};
void procError(QProcess::ProcessError);
}
Since "fake.exe" does not exist on my system, proc emits the error() signal. If I handle it like following, my program crashes:
void FakeRunner::procError(QProcess::ProcessError rc)
{
delete proc;
proc = 0;
}
It works well, though, if I don't delete the pointer. So, the question is how (and when) should I delete the pointer to QProcess? I believe I have to delete it to avoid a memory leak. FakeRunner::run() can be invoked many times, so the leak, if there is one, will grow.
Thanks!
You can't delete QObject instance inside slot which is connected to a signal in this instance using normal delete operator. This is due to the fact that if signal and slot connected using direct connection then the slot actually called from the signal implementation made by moc. This is like attempt to delete this; from inside the member of a class. There is a solution QObject::deleteLater(). Object will be deleted by Qt event loop inside events processing function. So you need to call proc->deleteLater() in your case.
And you don't need to disconnect signal from slot since Qt do it automatically when QObject is deleted.

Resources