I have subclassed QComboBox to customize it for special needs. The subclass is used to promote QComboBoxes in a ui file from QtDesigner. Everything works except that when I put a break point in a slot, the program does not stop at the breakpoint. I do however know that it is being called from the result it generates. I checked other slots in my program and they work fine with breakpoints. Doing a clean and rebuild all did not fix it. What could be causing this and is there anything I can do about it? The slot in question is the only one in the subclass and is called "do_indexChanged()". You can find the slot on line 37 of the class header below and the signal-slot connection on line 10 of the class source file.
CLASS HEADER:
#ifndef WVQCOMBOBOX_H
#define WVQCOMBOBOX_H
#include <QWidget>
#include <QObject>
#include <QComboBox>
#include <QVariant>
class wvQComboBox : public QComboBox
{
Q_OBJECT
//Q_PROPERTY(bool writeEnable READ writeEnable WRITE setWriteEnable)
public:
explicit wvQComboBox(QWidget *parent = 0);
bool writeEnable() {
return this->property("writeEnable").toBool();
}
void setWriteEnable(const bool & writeEnable){
this->setProperty("writeEnable",writeEnable);
}
bool newValReady() {
return this->property("newValReady").toBool();
}
void setNewValReady(const bool & newValReady){
this->setProperty("newValReady",newValReady);
}
QString getNewVal();
int getNewValIndex();
int oldVal; //comboBox Index before user edit began
private slots:
void do_indexChanged(){
this->setWriteEnable(true);
if(oldVal!=currentIndex()){
this->setNewValReady(true);
oldVal=currentIndex();
}
}
protected:
void focusInEvent ( QFocusEvent * event );
//void focusOutEvent ( QFocusEvent * event );//dont need because of currentIndexChanged(int)
};
#endif // WVQCOMBOBOX_H
#include "wvqcombobox.h"
wvQComboBox::wvQComboBox(QWidget *parent) :
QComboBox(parent)
{
this->setWriteEnable(true);
this->setNewValReady(false);
oldVal=this->currentIndex();
connect(this,SIGNAL(currentIndexChanged(int)),this,SLOT(do_indexChanged()));
}
void wvQComboBox::focusInEvent ( QFocusEvent * event ) {
this->setWriteEnable(false);
oldVal=this->currentIndex();
}
QString wvQComboBox::getNewVal(){
setNewValReady(false);
return this->currentText();
}
int wvQComboBox::getNewValIndex(){
setNewValReady(false);
return this->currentIndex();
}
This is most likely due to the fact that that file was not compilled with debug info, therefore the debugger won't be able to break there. Try linking your app to a debug version of libQtGui*.so/.dylib/.dll
I found the problem. All I needed to do was to put the function definition in the .cpp file.
Related
I need some help understanding how to access the QT GUI ui from another class/another cpp file.
Background: I am working on a project that consists of many cpp and hpp files. I am not the original author. This project is to control a USRP to receive/send data....with various parameters. Originally, you had to manually change parameter values inside several cpp files (i..e start frequency, steps, duration of receive, etc). Then re-compile and then run the executable. I wrote a simple Qt GUI interface in the main.cpp function where the users would enter in the GUI basic usrp receive parameters. Then the GUI interface would pass these values back into the uspr function that would actually execute the USRP functionality. This part is actually working great and I am happy (my first GUI!, Yay!)
One thing that I would like to do is to also display the current frequency in the main GUI window via the LCDNumber widget. This frequency is managed by another class, in another cpp file.
Here is what I tried:
Attempt #1: Make the MainWindow ui publicly available int the class/cpp file where the Frequency is established:
freq_transmit.cpp:
......
#include "mainwindow.hpp"
#include "ui_mainwindow.hpp"
.....
void Receiver::run()
{
//bunch of lines of code about USRP stuff
.....
rxCenterFreq // <---variable that holds the current frequency (which changes every second)
ui->lcdnumber->display(rxCenterFreq); // <-- -compiler error: ui not declared in this scope
............
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCore>
#include <QCoreApplication>
#include <QPalette>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
Ui::MainWindow *ui;
QPalette temp_red;
QPalette temp_green;
private slots:
void on_button_CalcSchedule_clicked();
void on_button_Reset_clicked();
void execute_run_usrp();
void on_button_QUIT_clicked();
void on_AutoSchedulerCheckBox_stateChanged(int arg1);
void on_button_manul_CalcSchedule_clicked();
void on_button_EXECUTE_clicked();
void on_button_SeeSchedule_clicked();
void on_button_STOP_clicked();
void function_test();
public slots:
void updateTXFreq(double a);
private:
void reset_sweep_values();
std::string calc_schedule_start_time(int minute_cadence);
void calc_cadence();
double calc_sweep_duration();
int nearest_cadence(int numToRound, int multiple);
signals:
void send_start_schedule(std::string, double, int, int);
};
#endif // MAINWINDOW_H
Attempt #2: Use Qt CONNECT functionality:
Step 1: generate a SIGNAL / emit function in the freq_transmit.hpp header:
....
signals:
void sendTXFreq(double a);
Step 2: Enter this emit signal in the freq_transmit.cpp file where the Frequency is being generated:
freq_transmit.cpp:
......
#include "mainwindow.hpp"
#include "ui_mainwindow.hpp"
.....
void Receiver::run()
{
//bunch of lines of code about USRP stuff
.....
emit sendTXFreq(rxCenterFreq); // emit signal to QT
....
Step 3: Declare a SLOT in mainwindow.h to accept emitted signal
mainwindow.hpp:
...
public slots:
void updateTXFreq(double a);
Step 4: Implementation:
mainwindow.cpp:
....
void MainWindow::updateTXFreq(double a)
{
ui->lcdnumber->display(a);
}
connect(&Receiver, &Receiver::sendTXFreq, this, &MainWindow::updateTXFreq); // <-- error: expected primary expression before ','
which is the comma after "&Receiver", which is a class that has various functions in it, including the Receiver::run() where Frequency is generated.`
Long story short, I am trying to have the generated frequency linked to a LCDNumber widget so that it shows on the GUI the value of frequency as the USRP code runs.
PS: I am not an expert C++ coder, I am just now learning about classes and QT GUI. Somebody mentioned that I should "create a pointer of my MainWindow in the freq_transmit.cpp file" so that then I can accesss ui elements direclty in that class, but I thought I tried that with ui->lcdnumber->display(rxCenterFreq);
Any guidance much appreciated and thank you!
I'm having trouble moving from VC++ to Qt-style programming with slots/signals. I wanted to create a button with an image that, when clicked, changed to another image, and when released, changed back to its original. I created a class called ClickableQLabel that inherits from QLabel, but it's telling me that certain functions are re-defined. Specifically, the ones that are emitted.
MainProgram.cpp
#include "MainProgram.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
CodeVault w;
w.show();
return a.exec();
}
MainProgram.h
#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
Q_OBJECT
public:
explicit MainProgram(QWidget *parent = 0);
~MainProgram();
private:
Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H
clickableqlabel.h
#ifndef CLICKABLEQLABEL_H
#define CLICKABLEQLABEL_H
#include <QLabel>
#include <QMouseEvent>
using namespace Qt;
class ClickableQLabel : public QLabel {
Q_OBJECT
QPixmap pushed;
QPixmap unpushed;
public:
ClickableQLabel(QWidget *parent = 0);
void mousePressEvent(QMouseEvent *eve );
void mouseReleaseEvent(QMouseEvent *eve );
void setPushed(QPixmap &p);
void setUnpushed(QPixmap &p);
signals:
void leftButtonPressed(ClickableQLabel* sender);
void leftButtonReleased(ClickableQLabel* sender);
};
#endif // CLICKABLEQLABEL_H
clickableqlabel.cpp
#include "clickableqlabel.h"
ClickableQLabel::ClickableQLabel(QWidget *parent) : QLabel(parent){
// set up qlabel
}
void ClickableQLabel::setPushed(QPixmap &p){
pushed = p;
}
void ClickableQLabel::setUnpushed(QPixmap &p){
unpushed = p;
}
void ClickableQLabel::leftButtonPressed(ClickableQLabel* sender){
if(!pushed.isNull())
sender->setPixmap(pushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::leftButtonReleased(ClickableQLabel* sender){
if(!unpushed.isNull())
sender->setPixmap(unpushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::mousePressEvent(QMouseEvent *eve ){
if(eve->button() == Qt::LeftButton){
emit leftButtonPressed(this);
}
}
void ClickableQLabel::mouseReleaseEvent(QMouseEvent *eve ){
if(eve->button() == Qt::LeftButton){
emit leftButtonReleased(this);
}
}
What I receive is the following 3 errors:
moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonPressed(class ClickableQLabel *)" (?leftButtonPressed#ClickableQLabel##QEAAXPEAV1##Z) already defined in clickableqlabel.obj
moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonReleased(class ClickableQLabel *)" (?leftButtonReleased#ClickableQLabel##QEAAXPEAV1##Z) already defined in clickableqlabel.obj
debug\CodeVault.exe:-1: error: LNK1169: one or more multiply defined symbols found
The two functions that are causing the errors are the two signals in the clickableqlabel.h file. How am I supposed to set up the connect function and where?
You shouldn't provide an implementation for your signals. You just declare signals in the class header. the Qt moc provides an implementation that is responsible to call the slots connected to the signal when it is emitted, see this. Because you are providing an implementation and Qt moc is providing another one, you end up with two different implementations and the linker complains.
so, to make some piece of code execute when a signal is emitted, you can put it in some slot that is connected to that signal, or you can execute it manually before emitting the signal. . .
Another thing to note is that your signals have a parameter named sender. normally there is no need to do this, QObject::sender() provides similar functionality.
How am I supposed to set up the connect function and where?
When you instantiate your ClickableQLabel in your MainProgram window for example (You can do this by using ClickableQLabel in a .ui form file), you can connect its signals to slots of the MainProgram, like this.
mainprogram.h
#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
Q_OBJECT
public:
explicit MainProgram(QWidget *parent = 0);
~MainProgram();
public slots:
void labelPressed();
void labelReleased();
private:
Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H
then in the constructor connect the ClickableQLabel's signals to the MainProgram's slots , something like this:
connect(clickableLabel, SIGNAL(leftButtonPressed()), this, SLOT(labelPressed()));
where clickableLabel is your ClickableQLabel object.
You should not explicitly define signal "functions" - they are simply emitted (as you do in the mousePressEvent() and mouseReleaseEvent() functions).
If you want some action performed (such as setPixmap), you would either do that in the slot functions that are connected to those signals, or perhaps directly in the mousePressEvent and mouseReleaseEvent functions.
Unrelated, but you may also need to do something like qRegisterMetaType<ClickableQLabel>() to use that data type with the signal/slot mechanism.
You don't need to subclass QLabel to achieve this: put an onLabelButtonClicked slot (method) in your MainWindow class, which is connected to the QPushButton clicked() signal, and which calls setText / setIcon as required.
If you want to re-use this clickable element you can of course encapsulate it in a class, but subclassing and handling raw-events is only required in Qt when defining new kinds of widget; if you're simply composing standard functionality (being clicked, adjusting appearance) then slots on your main window / dialog class are usually sufficient.
I am trying to add property title into the main window of my application. But when I try to compile it, the compiler gives me this error:
mainwindow.cpp:19: undefined reference to `MainWindow::titleChanged(QString const&)'
I tried it on mingw and msvc2013 both fails on the same line with this error. The header/source files:
mainwindow.h:
#ifndef MAINWINDOW
#define MAINWINDOW
#include <QObject>
#include <QString>
class MainWindow : public QObject {
QOBJECT_H
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
public:
MainWindow();
QString getTitle();
public slots:
void setTitle(const QString& title);
signals:
void titleChanged(const QString& title);
private:
QString title_;
};
#endif // MAINWINDOW
mainwindow.cpp:
#include "mainwindow.h"
#include <QString>
MainWindow::MainWindow()
{
}
QString MainWindow::getTitle()
{
return title_;
}
void MainWindow::setTitle(const QString& title)
{
if (title_ != title) {
title_ = title;
emit titleChanged(title);
}
}
If I add the method below to the end of mainwindow.cpp file, then the application compiles and runs, but the signal isn't emitted:
void MainWindow::titleChanged(const QString&)
{
}
I tried to cleaning out the project's build folders, it doesn't help :(. I am using QT 5.4 and working on QT Creator.
This question was already answered in comments by someone else. I just wanted to highlight the answer. The error in my case was in the header file
mainwindow.h:
class MainWindow : public QObject {
QOBJECT_H // This should be Q_OBJECT
...
I confused the QOBJECT_H macro used in QObject.h header file as an include guard with the Q_OBJECT macro used by QT's moc tool. Since the intellisense will offer you both options, they are easy to confuse.
I also got pointed to a good reading about common problems with signals/slots worth for reading: My signal / slot connection does not work
I am trying to subclass QEditLine so that I can define a new SIGNAL that sends an object identifier. At the moment, I connect a parent signal to a slot in the new class and from that slot I emits a proper new signal with the additional object identifier.
I cannot understand one thing. The problem is I don't know how to define a new signal function itself. I don't know what I should put there. I mean I know its arguments but I don't know what it shpould do as a function. I am doing this for the first time and it may looks very silly ;p but I really stuck there >.<.
Can anybody please provide some clues. It is probably a very easy problem.
Thanks
// myqeditline.h
#ifndef MYQEDITLINE_H
#define MYQEDITLINE_H
#include <QWidget>
#include <QLineEdit>
#include <QString>
class MyQEditLine : public QLineEdit
{
Q_OBJECT
public:
explicit MyQEditLine(const QString& n, QWidget *parent = 0);
protected:
QString name;
signals:
void textChanged(QString textCHanged, QString sender);
protected slots:
public slots:
void myTextChanged(QString textChanged);
};
#endif // MYQEDITLINE_H
// myqeditline.cpp
#include "myqeditline.h"
MyQEditLine::MyQEditLine(const QString &n, QWidget *parent)
: QLineEdit(parent),name(n) {
connect(this,SIGNAL(textChanged(QString)),this,SLOT(myTextChanged(QString)));
}
void MyQEditLine::myTextChanged(QString textChanged) {
emit textChanged(QString textChanged, QString name);
}
I just realised that the answer to my question is on this Qt Project website, in section regarding "Signals", in 4th paragraph. It says: "Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void)."
I want to read a 50MB file and send it over tcp. The file contains only floats. First I created only a Mainwindow, witch reads one line and sends it to the Server, but the gui got frozen. So I created a class that depends on QThread called QSendThread. Here is the Code for the class QThread:
#ifndef QSENDTHREAD_H
#define QSENDTHREAD_H
#include <QThread>
#include <QLabel>
#include <QFile>
#include <QMessageBox>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
class QSendThread : public QThread
{
Q_OBJECT
public:
QSendThread(QTcpSocket* qtcpso, QLabel* qlbl, QFile* qfiel, QObject *parent = NULL);
~QSendThread();
protected:
void run(void);
private:
QTcpSocket* qtcpsoDest;
QLabel* qlblRef;
QFile* qfileRef;
signals:
void error(QString qstrError);
};
#endif // QSENDTHREAD_H
#include "qsendthread.h"
QSendThread::QSendThread(QTcpSocket* qtcpso, QLabel* qlbl, QFile* qfile, QObject *parent)
: QThread(parent)
{
qtcpsoDest = qtcpso;
qlblRef = qlbl;
qfileRef = qfile;
}
QSendThread::~QSendThread()
{
}
void QSendThread::run(void)
{
int iLine = 0;
do
{
QByteArray qbarrBlock;
QDataStream qdstrmOut(&qbarrBlock, QIODevice::WriteOnly);
// show witch line is read
qlblRef->setText(tr("Reading Line: %1").arg(++iLine));
qdstrmOut.setVersion(QDataStream::Qt_4_6);
qdstrmOut << (quint16)0;
qdstrmOut << qfileRef->readLine().data();
qdstrmOut.device()->seek(0);
qdstrmOut << (quint16)(qbarrBlock.size() - sizeof(quint16));
qtcpsoDest->write(qbarrBlock);
qtcpsoDest->flush();
qbarrBlock.clear();
} while(!qfileRef->atEnd());
}
But the program crashing in the method qregion::qt_region_strictContains(const QRegion ®ion, const QRect &rect)
Is the method to read the file like I am doing wrong?
Thanks for Help.
First, you shouldn't really need to subclass QThread. The Qt documentation is misleading on this point. See this accepted answer for a similar question for lots of good info.
Second, you can only correctly access the gui from the main thread so your call qlblRef->setText() would be a problem. Accessing the gui from a thread other than the main one can be done using signals and slots or postEvent(). You can read up on events here.
Finally, this documentation is really required reading for working with threads in Qt. Pay particular attention to the section on threads and QObjects.
Addition:
To follow the advice above, you could certainly wrap your file reading code in a QObject subclass. An alternative (which I have little experience with myself) may be to try putting your code in QtConcurrent::run() and getting the result with a QFuture.