I have problem with one class in my project, after click appears new window with QTableWidget and QPushButton, after clicking the button I should have "test" on stdout, but nothing shows, here are parts of this code:
Header:
class ClientsSelector : public QWidget {
Q_OBJECT
public:
ClientsSelector(InvoiceTab* parent);
QWidget *window;
private:
QPushButton *accept;
public slots:
void loadData();
Constructor:
window = new QWidget();
layout = new QGridLayout();
layout->addWidget(table, 0, 0);
/*code*/
accept = new QPushButton(QString::fromUtf8("Load data"));
connect(accept, SIGNAL(clicked()), this, SLOT(loadData()));
layout->addWidget(accept, 0, 1);
/*code*/
window->setLayout(layout);
window->show();
Method:
void ClientsSelector::loadData() {
QTextStream std(stdout);
std << "test" << endl;
}
I have not even one warning nor error. I have nothing on stdout, it looks like button was connected to wrong object(?)
How do you instantiate ClientsSelector? Isn't it a singleton or global variable by chance? Try moving the connect call to a separate init function which is called after the ClientsSelector constructor. It helped me in similar WTF situations. It has something to do with the fact that each QObject inheritor has a static metadata member and you can't be sure about when it is fully initialized until the constructor finishes. connect won't work without that metadata.
See for example here: http://www.qtcentre.org/threads/9479-connect-in-constructor
If still lost, go through this checklist. Qt signals are so easy to use, everybody sometimes forgets it also has some requirements.
Seems like you forgot a closing " on the test printout.
Try using
qDebug() << "test";
instead of QTextstream
You can do following to make sure that the connection was made and slot is called.
connect function returns status of connection. Check if the connection was made properly.
put a breakpoint and see if the loadData() is called when button is pressed.
This might help to find the cause.
Related
As in Qt5, there's a new signal-slot syntax and I tried utilizing it.
Firstly, I created a void return type function:
void update()
{
cerr << "complete";
}
And connected it to &QRadioButton::pressed
QRadioButton *button = new QRadioButton;
QObject::connect(button, &QRadioButton::pressed, update);
Things went fine. Afterward, I tried inserting a parameter:
void update(bool trigger)
{
if (!trigger) {return;}
cerr << "complete";
}
And tried connecting:
QRadioButton *button = new QRadioButton;
QObject::connect(button, &QRadioButton::toggled(bool), update);
But it returned error: called to non-static member function without an object argument.
I tried this as well:
QObject::connect(button, &QRadioButton::toggled(bool), update(bool));
with the same result.
So, how can I patch this? Or, more favorable, how can I implement my function as a slot and get Qt to do the job the old fashion way with SIGNAL() and SLOT()?
Sidenote: I fully understood and also tested the first case (with void return type), but I want to know if I ever have to deal with the second case (which will be a lot, actually), what would be a good option.
You don't have to set the signature since Qt will use the signature of the slot so your initial code should work:
QObject::connect(button, &QRadioButton::pressed, update);
I have written a QT code which starts a new process on a button click, that process have to execute a shell script and append the Std output/error on text Browser dynamically based upon the script result. The code gets failed in the custom Slot. This is what my window.h is
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
QPushButton *goButton;
QTextBrowser *statusWindow;
QProcess *process;
private slots:
void go_Button_Clicked();
void updateOutput();
};
And this is how my window.cpp is
Window::Window(QWidget *parent) : QWidget(parent)
{
// Text Browser
statusWindow = new QTextBrowser(this);
// Create the Go button, make "this" the parent
goButton = new QPushButton(this);
connect(goButton, SIGNAL (clicked()), this, SLOT (go_Button_Clicked()));
}
void Window::go_Button_Clicked()
{
// Step1 - Create a new process
QProcess *process = new QProcess(this);
// Step2 - Connect the Signals and slot
qDebug() << connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(updateOutput()));
// Step3 - Start the Script process
process->start("/home/root/script.sh");
qDebug() << "Process in main";
}
void Window::updateOutput()
{
qDebug() << "Process in update Output";
//statusWindow->append(process->readAllStandardOutput());
}
So whenever i uncommented lines in update Output the GUI crashes as soon as i hit the button. using qdebug i managed to find that the GUI crashes bcoz of the line "statusWindow->append(process->readAllStandardOutput());" .
If the line is commented the debug message keeps on printing on console, but with the un-commented line i get the debug message once and then GUI crashes.Here is the debug output.
true
true
Process in main
Process in update Output
Process killed by signal
Any idea whats going on here, and i am familiar with Debugging in QT
Replace:
QProcess *process = new QProcess(this);
by
process = new QProcess(this);
You are using uninitialized member variable process, because in Window::go_Button_Clicked() you are creating a local variable.
Edit
Actually, the code is very error prone. What happens, when the user presses the button multiple times. Then in the slot you may read the the output from wrong process.
One workaround could be: You don't define QProcess as member at all, but do it like now - as a local variable. Then in the slot, you can cast the sender to QProcess*, and unless it fails use this instance. It will be always the right one. Afterwards, don't forget to delete the sender. Use deleteLater() for this.
Inside your void Window::go_Button_Clicked() slote you hide QProcess *process declared at .h file with new variable
QProcess *process = new QProcess(this);
Replace this line with
process = new QProcess(this);
But when you click second time you'll get memory leak, and can not get more data from first process. So you chould change you design somehow.
I want to make a QLabel clickable and followed this "how-to". I was not sure how to get this piece of code into my GUI (I am quite newbie to qt). What I did was:
I created a new class (just copy/paste of ClickableLabel from the link, but I changed the signal to clicked(QMouseEvent* event))
I added a QLabel to my GUI and "promoted" it to a ClickableLable
I connected the signal to a slot of my main window where I std::cout some stuff:
connect(this->ui->label,SIGNAL(clicked(QMouseEvent*)),
this,SLOT(on_label_clicked(QMouseEvent*)));
It seems to work. The problem is that each time I click on the label the mousePressedEvent gets called twice. I also tried mouseReleasedEvent but its the same.
Any ideas what could go wrong?
EDIT: Here is my modified ClickableLable:
class MyClickableLabel : public QLabel {
Q_OBJECT
public:
MyClickableLabel(QWidget* parent=0);
~GBoardLabel();
signals:
void clicked(QMouseEvent* event);
protected:
void mouseReleaseEvent(QMouseEvent* event);
};
MyClickableLabel::MyClickableLabel(QWidget* parent) : QLabel(parent) {this->setText("");}
MyClickableLabel::~MyClickableLabel() {}
void MyClickableLabel::mouseReleaseEvent(QMouseEvent *event){
std::cout << "CLICKED R" << std::endl;
std::cout << event->type() << std::endl;
std::cout << event->pos().x() << std::endl;
std::cout << event->pos().y() << std::endl;
emit clicked(event);
}
The couts in the in the above method I added only later and realized that the mouseReleaseEvent is actually only called once. But when I connect the clicked to a slot of my mainwindow, this slot recieves the event twice.
Then I removed the connect statement and to my surprise the signal is still emited and recieved (only once). I am a bit puzzled how this works, because I am pretty sure that I do not mistakenly have a connect anywhere in the code.
My label is working, but I would like to understand what is going on. Actually I am not 100% sure anymore that I didn't use some Qt creator feature make the connection. However, I have no idea where to find such connections. For example, I have a QButton on the same main window. In the gui editor I right clicked it and then "show slots"->"clicked()"->"OK" and automatically a method called on_pushButton_clicked() is created, but I have no idea, where this is called / how the button's signal is connected to this method. On the other hand, I do not get the MyClickableLabel::clicked(QMouseEvent*) listed in the list of slots for my label, thus I don't think I created the connection this way...
I could fix it, but I do not really understand what is going on...
It was not the mousePressEvent that was fired twice, but my on_label_clicked slot recieved the event twice.
I removed the connect statement and now the on_label_clicked is called only once per click. It seems like, there is something going on under the hood. Maybe when the slot is called on_label_clicked it gets automatically ("qtmatically") connected to the mouse events emmited from the child called label ?
EDIT: Still didnt find the official docs, but this blog explains it quite nicely. In summary, one just needs to use the naming convention for the slot
void on_<widget name="">_<signal name="">(<signal parameters="">);
to make use of the auto connect feature.
I am implementing a simple function where slider value is constantly displayed on label and qDebug(). I already got the label updated using signal/slots, but somehow the qDebug() thread is not working properly. I expected to see the console flooded with the value of the slider.
Below is my code:
SliderThread.h:
class HorizontalSliderThread : public QThread {
Q_OBJECT
public:
HorizontalSliderThread(Ui::MainWindow *ui);//in order to call slider value in HorizontalSliderThread class
~HorizontalSliderThread();
public slots:
void process();
private:
};
SliderThread.cpp
HorizontalSliderThread::HorizontalSliderThread(Ui::MainWindow *ui){
ui_global = *ui;
}
void HorizontalSliderThread::process(){
qDebug("Test Thread");
int value = ui_global.horizontalSlider_windowSize->value();
QObject::connect(ui_global.horizontalSlider_windowSize,SIGNAL(valueChanged(int)),ui_global.label_SliderWindowSize,SLOT(setNum(int)));//update value to label
qDebug()<<value; //update value in console
}
mainwindow.h
move Ui::MainWindow *ui; from private to public.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread* thread = new QThread;
HorizontalSliderThread* slider = new HorizontalSliderThread(ui);
slider->moveToThread(thread);
connect(thread, SIGNAL(started()), slider, SLOT(process()));
thread->start();
}
Current Output: qDebug() displays the value of slider once, label is updated constantly.
Expected Output: qDebug() displays the value of slider continuously, label is updated constantly.
Since label is updated when the slider is moved, then the signal/slot for this function is working, which means my thread should be working. Don't know what I'm doing wrong.
QThread implementation is reference from: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
I am fairly new to this, especially QThread, so if there is a better way to implement this function, please let me know!
Thanks a lot.
EDIT1: add slider->moveToThread(thread);
Well you've only connected the started() signal to your process() function, so your thread starts and it calls process, which dutifully shows your debug output and returns.
I suspect you want to call your process function every time the value changes, which would require another signal/slot connection (along these lines):
connect(ui_global.horizontalSlider_windowSize, SIGNAL(valueChanged(int)), thread, SLOT(setNum(int)));
Also, it looks like you intend for your HorizontalSliderThread to actually run in that separate thread you've created, in which case you'll need a call to QObject::moveToThread() in there, something along these lines:
slider->moveTothread(thread);
I am just getting my feet wet with Qt, I am trying to pull the string from a QlineEdit and append it to a QTextBrowser after clicking a button(for simplicity/error checking I am just having it append the word appended at the moment).
The program runs, and the GUI gets brought up on the screen, but whenever I click the button, my program seg faults.
Here's my code, I cut a lot out that was unnecessary:
HEADER:
#ifndef TCD2_GUI_H
#define TCD2_GUI_H
//bunch of includes
class TCD2_GUI : public QWidget
{
Q_OBJECT
public:
TCD2_GUI(QWidget *window = 0);
//bunch of other members
QLineEdit *a1_1;
QTextBrowser *stdoutput;
public slots:
void applySettings(void);
private:
};
#endif // TCD2_GUI_H
and here is the snippet of the cpp of which causes the fault
QTextBrowser *stdoutput = new QTextBrowser();
stdoutput->append("Welcome!");
QObject::connect(apply, SIGNAL(clicked()), this, SLOT(applySettings()));
//------------------------------------------------------Standard Output END
//layout things
}
void TCD2_GUI::applySettings()
{
stdoutput->append("appended");
}
stdoutput in your applySettings() function refer to the member of the TCD2_GUI class whereas stdoutput in your piece of code where the crash happens is a local variable.
Try to add in your constructor by example:
stdoutput = new QTextBrowser();
andremove the following line from your piece of code:
QTextBrowser stdoutput = new QTextBrowser();
looking at the code provided, my guess would be stdoutput is declared twice. Once as a member of the *TCD2_GUI* class, second time as a local variable in the method (class constructor?) where you do layout. ApplySettings uses a class member which is not initialized, hence segmentation fault.
Changing your code to:
stdoutput = new QTextBrowser();
stdoutput->append("Welcome!");
QObject::connect(apply, SIGNAL(clicked()), this, SLOT(applySettings()));
might fix the problem.
hope this helps, regards