qt6: Connect QFileDialog::filesSelected to a slot - qt

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.

Related

QObject: Cannot create children for a parent that is in a different thread & QProcess [duplicate]

I am using Qt 4.6.0 (32 bit) under Windows 7 Ultimate. Consider the following QThread:
Interface
class ResultThread : public QThread
{
Q_OBJECT
QString _post_data;
QNetworkAccessManager _net_acc_mgr;
signals:
void onFinished(QNetworkReply* net_reply);
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
ResultThread();
void run();
void setPostData(const QString& post_data);
};
Implementation
ResultThread::ResultThread() : _net_acc_mgr(this)
{
connect(&_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void ResultThread::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void ResultThread::setPostData(const QString& post_data)
{
_post_data = post_data;
}
void ResultThread::run()
{
_net_acc_mgr.post(QNetworkRequest(QUrl("http://[omitted]")),
QByteArray(_post_data.toStdString().c_str()));
}
Whenever _net_acc_mgr.post() is executed in ResultThread::run(), I got the following Application Output in Qt Creator:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x22fe58), parent's thread is QThread(0x9284190), current thread is ResultThread(0x22fe48)
What does this mean? How to solve it?
The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.
This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.
Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.
The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.
I received this error message when I forgot to set the QNetworkRequestManager's parent.
nam = new QNetworkAccessManager(this);

Can't write to Qt5 textEdit box with ui->control->setText(message)

I am trying to put the data passed to a mainwindow.cpp function on the screen with the typical ui->control->setText(message) without success. The same line works if it is in a timer loop or a button function but not from display_that_data function
"MainWindow::display_that_data()" is called from myudp.cpp with the following lines
MainWindow show_tlm;
show_tlm.display_that_data(data_source, buf_copy);
mainwindow.cpp (updated to include emitting a signal for a SIGNAL/SLOT connection)
The SIGNAL/SLOT connection is set up in the constructor with the following line
connect (this, SIGNAL (showdata_signal()), this, SLOT(showdata_slot()));
void MainWindow::display_that_data(QByteArray data_source, QByteArray tlmBuf){
QString msg ;
msg = " in display_that_data";
qDebug() << msg ;
ui->tlm_vals->setText(msg);
//generate a signal which will trigger showdata_slot
emit showdata_signal();
msg = " in display_that_data after emit showdata_signal()";
qDebug() << msg ;
}
void MainWindow::showdata_slot() {
QString msg = "showdata_slot called";
qDebug() << msg ;
ui->tlm_vals->setText(msg);
}
Runtime debug messages show that code is making it to the showdata_slot but it is still not writing to the ui->tlm_vals
" in display_that_data"
"showdata_slot called"
" in display_that_data after emit showdata_signal()"
but.... neither one of the ui->tlm_vals->setText(msg) lines are putting text on the ui
"MainWindow::realtimeDataSlot()" is called by at timer timout signal as follows:
void MainWindow::setupRealtimeDataDemo(QCustomPlot *customPlot) {
// setup a timer that repeatedly calls MainWindow::realtimeDataSlot
connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot()));
dataTimer.start(1000);
}
void MainWindow::realtimeDataSlot(){
QString temp = QString("%1").arg(epochTime, 10, 10, QChar('0'));
ui->tlm_vals->setText(temp);
}
And this works perfectly (of course I have to disable it to see if showdata_slot is writing to the ui)
I thought the problem was a needed SIGNAL and SLOT connection to trigger the write to the ui but generating a SIGNAL/SLOT connection (which debug shows as working) still does not write to the ui from the slot function.
For completeness mainwindow.h contains the following
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setupRealtimeDataDemo(QCustomPlot *customPlot);
void display_that_data (QByteArray data_source, QByteArray tlmBuf);
private slots:
void realtimeDataSlot();
void showdata_slot();
private:
Ui::MainWindow *ui;
QTimer dataTimer;
What am I missing/doing wrong?
Somewhere deeply embedded in Qt there is a difference between gui mouse click generated event and code generated event and this somehow caues Qt behavior to vary with the same lines of code. I will repost a more more "root level" question on this topic.

connect in QT issue - no connection?

I have a custom class derived from QGraphicsPixmapItem. Its called GraphPixmapItemCustom and it's overloaded method is:
void GraphPixmapItemCustom::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsPixmapItem::mousePressEvent(event);
GraphMarkItemCustom *ptr;
if(event->button() == Qt::RightButton)
{
qDebug("Before emit");
emit addPoint(QPointF(event->pos().x(), event->pos().y()));
qDebug("After emit");
markList.append(new GraphMarkItemCustom(QPointF(event->pos().x(), event->pos().y())));
ptr = markList.last();
markGroup->addToGroup(ptr);
//this->scene()->addItem(ptr);
}
}
the signal is declared at header:
signals:
void addPoint(QPointF position);
In main class that has a pointer to object of class GraphPixmapItemCustom called
private:
GraphPixmapItemCustom *pixItemRGB;
and in the main class I have a slot called:
private slots:
void pointAdd(QPointF position);
In the main class constructor I have a connection:
connect(pixItemRGB, SIGNAL(addPoint(QPointF)), this, SLOT(pointAdd(QPointF)));
In the slot I have only qDebug("YUPPY IT ACTUALLY WORKS!");
But the slot is not beeing fired. Why? I have deleted all moc files and everything that didn't have to be there. So only .pro, .h and .cpp files along with .ui forms where neccesary were left.
I have checked most hits at Google. What is the best (I'm not sured - maybe i modified something) that it worked! I remember the working effects of this connection. Help!
You have to connect the signal after creating the GraphPixmapItemCustom object with the new operator.

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.

QT EventTransition implementation

I am trying to build an QT State Maschine. I have some States, and for those States i need Transition that alter the Graphics on my gui.
The Problem i having and the only reason i am asking, i am Stuck and Point 1.
The compiler cant identifie the QTEventTransition. I have QT 4.6 wroking with QT Creator on Windows.
The compiler does not find Header #include < QtEventTransition >
This is what i did i never did this bevor but i think it should be correct, I have A Header File where i have my Transitions Declareted like this:
class validateBoatTransition : public QtEventTransition
{
public:
validateBoatTransition(Widget *widget,ServerSkeleton* server);
protected:
bool eventTest(QEvent *e);
void onTransition(QEvent *);
private:
Chart* ourChart;
Message current;
BarelySocket* myBarelySocket;
};
Than i have my Cpp File where i have this:
validateBoatTransition::validateBoatTransition(Widget *widget,ServerSkeleton* server)
{
}
void validateBoatTransition::onTransition(QEvent *e)
{
/*
My Logik should go here
*/
}
What i want is that if the Transition is activated by an Button (clicked) it should fire this transition!
I searched the net, but cant find an solution. Can i do that? I should i think.
Yours Thomas
Maybe you should take a look to signals/slot mechanism. I think this is what you need to achieve what you want.
Make your onTransition function a slot instead of an event handler and connect it to the signal clicked of the button.
class validateBoatTransition : public QtEventTransition
{
...
public slots:
void onTransition();
...
}
Somewhere in your code, connect the button to the slot:
QObject::connect(myButton, signal(clicked()), myValidateBoatTransition, slot(onTransition());
Each time the button will be clicked the execution will go through the onTransition function.
I think you're trying to use wrong classes/mechanisms to achieve your goals. If I understand you correctly, you have some GUI and after clicking some button you want to validate some stuff and if this validation is successful the state machine should change it's state. I'd write it this way:
Create some class to handle validation:
class BoatValidator : public QObject
{
Q_OBJECT
// boring stuff like constructor, etc.
public slots:
void validate()
{
if ( /*your validation logic goes here*/ ) {
emit boatTransition();
}
}
signals:
void boatTransition(); // emitted if validation is succesful
};
Then you connect your QPushButton::clicked() to BoatValidator::validate() and use BoatValidator::boatTransition() signal to drive the state machine:
QStateMachine machine;
QState *state1 = new QState(&machine);
QState *state2 = new QState(&machine);
// more state machine setup
// connect validator and button
QPushButton button;
BoatValidator validator;
connect(&button, SIGNAL(clicked()), &validator, SLOT(validate()));
// use validator to change states
state1->addTransition(&validator, SIGNAL(boatTransition()), state2);
Generally I'd use signal to drive state machine, unless some transitions are obviously event driven (for example some QEvent::Enter/QEvent::Leave on GUI widgets, etc.).
What i wanted to do is build a Qt State Machine. The Problem was that i could not trigger my own Transitions (let alone with my own Events). The answers given are good but would lead to a messy code. Why should i use a QT State Machine if i could not use the QT Transitions?
The First Problem above is solved, if you create a new Project. QT Creater is very annoying.
But here now my solution , may it help others.
First my State:
class ServerState : public QState
{
Q_OBJECT
public:
ServerState(QPushButton * pushButton);
~ServerState();
public slots:
void buttonWasClicked();
protected:
void onEntry(QEvent *e);
void onExit(QEvent *e);
private:
QPushButton * pushButton;
};
Normal, but you see i added an Slot. This slot enables me to connect a bottom signal or a Widget Mouse Press Signal to it !
Like this:
QStateMachine *machine = new QStateMachine(this);
ServerState *s1 = new ServerState(connectButton);
connect(connectButton, SIGNAL(clicked()), s1, SLOT(buttonWasClicked()));
machine->addState(s1);
s1->addTransition(connectTransition);
all i needed to to is now fire a declared Event like this one :
#define RegisterToServerEventIndex User+5
class ConnectToServerEvent : public QEvent
{
public:
ConnectToServerEvent() : QEvent(QEvent::Type(QEvent::ConnectToServerEventIndex))
{}
};
when the slot was called:
void ServerState::buttonWasClicked()
{
this->machine()->postEvent(new ConnectToServerEvent());
qDebug("ServerState::buttonWasClicked");
}
The QT State Machine would now call all the Transitions , link with this state:
ConnectToServerTransition::ConnectToServerTransition(QPushButton * pushButtonB,ServerSkeleton* serverSkeleton)
{
this->pushButtonB = pushButtonB;
this->pushButtonB->hide();
this->serverSkeleton = serverSkeleton;
qDebug("ConnectToServerTransition::ConnectToServerTransition");
}
bool ConnectToServerTransition::eventTest(QEvent *e)
{
return (e->type() == QEvent::ConnectToServerEventIndex);
}
void ConnectToServerTransition::onTransition(QEvent *e)
{
if (true == this->serverSkeleton->initalisieren())
{
this->pushButtonB->show();
}else{
qDebug("Conection to Server faild");
}
emit kill();
return;
}
Whats so great that i dare to post?
Well first you can link a Qt SM to a widget where a mouse press event , or somthing else, is called and process the raw data to a an level you need later in your program. All you then need to do is, to emit the singal:
void Widget::mousePressEvent(QMouseEvent *event){
Coordinates current;
current.line = 0;
current.row = A;
current.row = (Row) (event->x() / 30); // 30 = breite von einen Feld
current.line = event->y() / 30; // 30 = länge von einen Feld
emit this->clicked(current);
return;
}
Then this enhenced information (current) is passed to the slot at my state, where i chose to call the correct transition that does the work. You could link more transitions to it, if you need it.
But most importend you dont need to reprogramm the Transition, a think i realy disliked.
Thank you for your help , i could not done it alone.

Resources