How to fix "index < m_series->count()" error in xychart.cpp? - c++

I started to use QtCharts in my application. The chart that I am considering is a Line Chart, using the objects QChart and QLineSeries. As all the points are added dynamically, I use the signal/slot system to update the chart:
QLineSeries* serie = new QLineSeries(this);
connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));
void MyChart::onPointAdded(int index) {
// Delete the first items if the number of points has reached a threshold
while (serie->points().length() >= threshold)
serie->remove(0);
}
The function onPointAdded is called when a point is added in serie (a QLineSeries object). The code snippet that I gave removes the first points in serie such as the number of points in the graph is always fixed (except at the beginning).
When I run this code in Release, there is no problem. However, when I run it on Debug and the number of points reaches the threshold, I obtain the following error message:
This dialog box does not stop the program, but each time a point is added (and reach the threshold) a new dialog box appears on top of the previous one.
The following is the minimal code to reproduce the error:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QChart>
#include <QLineSeries>
#include <QMainWindow>
#include <QValueAxis>
#include <QtCharts/QChart>
#include <QtCharts/QLineSeries>
QT_CHARTS_USE_NAMESPACE
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QChart* chart = nullptr;
QLineSeries* serie = nullptr;
int threshold = 5;
private slots:
void onAddPointButtonClicked();
void onPointAdded(int index);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
chart = new QChart;
serie = new QLineSeries(this);
connect(ui->bt_addPoint, SIGNAL(clicked()), this, SLOT(onAddPointButtonClicked()));
connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));
chart->legend()->hide();
chart->addSeries(serie);
ui->graphicsView->setChart(chart);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::onAddPointButtonClicked() {
serie->append(0, 1);
}
void MainWindow::onPointAdded(int index) {
while (serie->points().length() >= threshold)
serie->remove(0);
}
I used an UI Form to generate the graphical interface. This interface contains a QChartView and a QPushButton (to add dynamically the points).
My Qt version is 5.11.2, and the bug has been produced using MSVC 2017 64-bits. The plugin QtCharts is needed to use the QChart, QChartView and QLineSeries.
I would like to know if it is possible to either fix this problem or to disable the Qt Debug Dialog Messages.

Cause
It is not a bug, but an expected result of the order in which the slots MainWindow::onPointAdded (in your code) and XYChart::handlePointAdded are executed. Here is the whole story:
From the error message it becomes clear, that in the file xychart.cpp on line 142 the check of index against the count of m_series fails. The thing, which invalidates the check, is your serie->remove(0);. The reason is that your slot is executed before the slot, where the check is made, because your connect statement comes first. The question is: first to what? Well, this is the tricky part and I have to admit that it is indeed not immediatelly obvious. However, with some digging in the source code, one could get to the bottom of the problem. The path is the following:
chart = new QChart; in your code instantiates a QChart, which in turn instantiates a PIMPL QChartPrivate
QChartPrivate connects in it's constructor ChartDataSet::seriesAdded to ChartPresenter::handleSeriesAdded:
QObject::connect(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), m_presenter, SLOT(handleSeriesAdded(QAbstractSeries*)));
IMPORTANT Now you connect QLineSeries::pointAdded to MainWindow::onPointAdded
chart->addSeries(serie); in your code causes the ChartPresenter::handleSeriesAdded slot to be executed, where QLineSeriesPrivate::initializeGraphics is called:
series->d_ptr->initializeGraphics(rootItem());
In QLineSeriesPrivate::initializeGraphics a LineChartItem is instantiated:
LineChartItem *line = new LineChartItem(q,parent);
LineChartItem calls the constructor of its base class XYChart in the initializer list of its own constructor
IMPORTANT Only now is the connect statement executed, which causes the troublesome for you XYChart::handlePointAdded slot to be called when a point is added to the series:
QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
Focusing only on the steps marked as important, it becomes obvious in which order do both connect statements come. This is also the order in which the respective slots are called.
Solution
Having this cause in mind, I would suggest you to first add the series to the chart and then connect the pointAdded signal, i.e.:
move
connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));
anywhere after
chart->addSeries(serie);

Related

Having issues understanding pointers in c++

I am currently working in QT and recently I noticed something that really confused me.
As far as I can tell normally when we want to create a pointer we have to use the following syntax in C++:
int number = 10;
int* pNumber = &number;
(or something similar to that)
I wanted to create a pointer to a button which was created in QT design. It was for testing purposes only. (I am new to QT and c++ so I wanted to test things out)
But then I noticed something strange that I could not understand. for some reason when I created the pointer of type "OPushButton" with the name of "button" I did not have to use the "&" with the "(*ui).pushButton_5" syntax. (pushButton_5 is the name of my button in my ui)
The code works and the text "5" is added to my "lineEdit" in QT. How does this work? Am I missing something about pointers?
Here is my code:
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPushButton* button = (*ui).pushButton_5;
ui->lineEdit->setText((*button).text());
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h:
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
& is not the way to create pointers, it's the way to acquire a pointer to a specific thing that you have access to.
If somebody else tells you where a thing is, you don't need the help of & to find out.
void g(int* q)
{
int* p = q; // 'q' is the location of some unknown 'int', and so is `p`.
}
You need & if you have a thing and want to know where that thing is.
void f()
{
int x = 5;
int* p = &x; // The location of 'x'.
g(&x); // Pass the location of 'x' to 'g'.
}
Also, we usually write x->y rather than (*x).y.
This convention makes a lot of sense if you look at more than one level of indirection – compare x->y->z->w to (*(*(*x).y).z).w.

Qt custom SLOT of subclass not recognised by CONNECT

Background
I am writing a media player application in Qt. I have subclassed QMediaPlayer and created a new SLOT which is capable of interpreting an int and passing it as qint64 to QMediaPlayer::SetPosition(qint64).
QMediaPlayer::PositionChanged fires a signal to the cslider slider_playback (a horizontal slider subclass). This makes the slider move as a song is playedback. There are also some subclassed labels (clabel) which receive signals regarding the song duration and song playback position.
Problem
The problem i have occurs when I build & run, I receive the following error:
Starting /home/daniel/DeveloperProjects/build-Player-Desktop_Qt_5_9_1_GCC_64bit-Debug/Player...
QObject::connect: No such slot QMediaPlayer::set_playback_position(int) in ../Player/mainwindow.cpp:23
QObject::connect: (sender name: 'slider_playback')
The slider should be able to control the position of the playback. The offending line of code is preceeded by a '// Player seek' comment in the file.
I think the error indicates that the base class is being referred to for the SLOT, whereas the slots is actually part ofthe derived class.
Why is this error occuring and what action would resolve the issue? The slots in my clabel and cslider classes work without issue. The difference is that those classes have constructors and destructors. I have not implemented a constructor in the QMediaPlayer subclass as I do not want to override the base class constructor.
cmediaplayer.h (full file)
#ifndef CMEDIAPLAYER_H
#define CMEDIAPLAYER_H
#include <QMediaPlayer>
//#include <QObject>
class cmediaplayer : public QMediaPlayer
{
Q_OBJECT
public slots:
void set_playback_position(int);
};
#endif // CMEDIAPLAYER_H
cmediaplayer.cpp (full file)
#include "cmediaplayer.h"
void cmediaplayer::set_playback_position(int v) {
this->setPosition( (qint64)v );
}
mainwindow.h (full file)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include "cmediaplayer.h"
#include "clabel.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QPalette m_pal;
QString media_file_str="/usr/share/example-content/Ubuntu_Free_Culture_Showcase/Jenyfa Duncan - Australia.ogg";
//QMediaPlayer * player ;
cmediaplayer * player; // My custom type
private slots:
void on_pushButton_pressed();
void on_pushButton_released();
void on_button_playback_clicked();
};
mainwindow.cpp (full file)
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
//player = new QMediaPlayer;
player = new cmediaplayer; // My custom type
// set max time on playback slider
connect(player, SIGNAL(durationChanged(qint64)), ui->slider_playback, SLOT(set_qint64_max(qint64)));
// st max time on playback label
connect(player, SIGNAL(durationChanged(qint64)), ui->label_track_length, SLOT(setIntText(qint64)));
// set slider playback position
connect(player, SIGNAL(positionChanged(qint64)), ui->label_track_position, SLOT(setIntText(qint64)));
// Player seek
connect(ui->slider_playback,
SIGNAL(valueChanged(int)),
player,
SLOT(set_playback_position(int)));
// Player volume
connect(ui->slider_volume,SIGNAL(valueChanged(int)),player,SLOT(setVolume(int)));
ui->slider_volume->setValue(50); // set player initial value
}
MainWindow::~MainWindow() {
delete ui;
delete player;
//delete playlist;
}
void MainWindow::on_pushButton_pressed() {
m_pal=this->palette().color(QPalette::Background);
QPalette pal=palette();
pal.setColor(QPalette::Background,Qt::gray);
this->setAutoFillBackground(true);
this->setPalette(pal);
player->setMedia(QUrl::fromLocalFile(media_file_str));
player->setPlaybackRate(1);
player->play();
}
void MainWindow::on_pushButton_released() {
QPalette pal=m_pal;
this->setAutoFillBackground(true);
this->setPalette(pal);
//player->stop();
}
void MainWindow::on_button_playback_clicked()
{
//player->play();
}
Qt creates a new class that implements the actual connection between the slots and the signals but many times this one is not updated. The classes they refer to have a name similar to moc_xxx.cpp and these are created in the build folder.
To force them to update we must click on the make clean submenu that is located in the Menu Build of QtCreator, and then run qmake in the same menu.
Or you can manually remove the build folder and compile it back
Perhaps, it could help somebody. I had a similar issue when trying to use a SLOT function in the connect call. Even though the slot was declared and defined in the subclass, the connect function not recognize it, issuing a message which says that the slot function is not part of the base class.
In my case, the problem was that I didn't place the Q_OBJECT in the beginning of the class declaration. After that, I had to clean (otherwise, various errors occur in compilation step) and build the project again to had the slot function working properly.

Qt parent mechanism

There is one QPushButton in a QWidget, click the button should open another QWidget, as coded below:
project.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = untitled
TEMPLATE = app
CONFIG(debug, debug|release) {
DESTDIR = debug
} else {
DESTDIR = release
}
INCLUDEPATH += ..
SOURCES += ../main.cpp\
../widget.cpp \
../secondwidget.cpp
HEADERS += ../widget.h \
../secondwidget.h
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QVBoxLayout>
#include <QPushButton>
#include "secondwidget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(400, 300);
QVBoxLayout *vLayout = new QVBoxLayout(this);
QPushButton *bt = new QPushButton("Open 2nd Widget");
vLayout->addWidget(bt, 1, Qt::AlignRight);
SecondWidget *secondWidget = new SecondWidget();
// SecondWidget *secondWidget = new SecondWidget(this);
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}
Widget::~Widget()
{
}
secondwidget.h
#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H
#include <QWidget>
class SecondWidget : public QWidget
{
Q_OBJECT
public:
explicit SecondWidget(QWidget *parent = 0);
signals:
public slots:
};
#endif // SECONDWIDGET_H
secondwidget.cpp
#include "secondwidget.h"
SecondWidget::SecondWidget(QWidget *parent) : QWidget(parent)
{
setAttribute( Qt::WA_QuitOnClose, false );
}
Passing this for the SecondWidget constructor (as in the commented line) will brake my logic at some point. So the SecondWidget doesn't show anymore, when the button is clicked.
What's going on?
In addition to the problems with your destructor and constructor (and the memory leak you have because of the second), and the project file here are a few things that you may want to know in order to understand the whole parent situation:
You don't need to pass this. The purpose of assigning a parent is to be able to simplify the cleanup procedure for QObject instances (including all classes inheriting from the QObject class). Qt parent-child model follows the C++ standard that is destructors are invoked in the reversed order of their constructors. In simple terms this means the following:
Imagine you create widget A, B and C. Using the parent property you assign B and C to be children of A. So here we have the order of creation:
A (parent)
B,C (children)
Now at some point you want to destroy your widgets (example: closing the application). The standard C++ way is to destroy them in the following (reversed to the construction) order:
B, C (children)
A (parent)
And this is indeed what happens if we go for the parent first. However we are dealing with Qt here so we have to consider one additional feature the library provides - slots and signals.
Whenever a QObject gets destroyed it emits a signal. Based on the role the object plays in the parent-child relationship the outcome is one of the following:
only the QObject that is destroyed gets destroyed - this is what happens when a child gets destroyed before we destroy its parent
all children of that QObject get destroyed first followed by the destruction of the QObject itself - this is what happens when a parent gets destroyed. The emitted signal is caught by all its children which in return also get eliminated.
However assigning a parent is not mandatory. You can do the cleanup manually yourself. Read more about the parent-child model in the Qt documentation.
In addition to all that ownership transfer (a widget becomes a child of another widget) often happens automatically so it is not necessary to explicitly specify a widget's parent. Again taking things out of the Qt documentation an exception is made here. If you add a widget to a layout, the ownership is NOT transferred to the layout itself but to the QWidget it is part of.
Finally there is one important case when not assigning a parent makes things very, very different. Here I shall quote the Qt documentation on QObject:
Setting parent to 0 constructs an object with no parent. If the object is a widget, it will become a top-level window.
So if you have a QWidget and don't add it to some layout (and indirectly to the QWidget that has that layout) for example it will automatically become a separate window.
EDIT:
Check your constructor and in particular the way you work with your secondWidget object. As I've mentioned above in case you don't want to assign it to a parent widget you need to take care of the cleaning.
You dynamically allocate the memory for it
SecondWidget *secondWidget = new SecondWidget();
and even connect it to your button
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
however you never release the allocated memory using delete or assigning it to a parent widget, which will take care of it automatically. Hence you create a memory leak. Connecting a QObject via signals and slots doesn't have anything to do with transfer of ownership.
I personally assume that you actually want a secondWidget to be an extra window shown on the screen. In this case you need to create a class member of type SecondWidget
SecondWidget *secondWidget;
then allocate it inside your constructor and connect whichever slots and signals you want
Widget::Widget(QWidget *parent) : QWidget(parent)
{
//...
secondWidget = new SecondWidget();
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}
and finally release the memory inside your constructor:
Widget::~Widget()
{
delete secondWidget;
}
Otherwise as I said you are basically creating a reference to a memory block and right after you leave your constructor that reference gets destroyed since it runs out of scope.
EDIT 2:
Here is a small example how to do it if you want secondWidget as a child to your main widget:
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.hpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "secondwidget.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
SecondWidget *secondWidget = new SecondWidget(this); # secondWidget is now officially adopted by Widget
# If you skip the parent assignment inside SecondWidget you can call secondWidget->setParent(this) here
connect(ui->pushButton, SIGNAL(clicked(bool)), secondWidget, SLOT(show()));
}
Widget::~Widget()
{
delete ui;
}
secondwidget.hpp
#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H
#include <QObject>
#include <QDialog>
class SecondWidget : public QDialog
{
Q_OBJECT
public:
explicit SecondWidget(QWidget *parent = 0);
~SecondWidget();
};
#endif // SECONDWIDGET_H
secondwidget.cpp
#include "secondwidget.h"
#include <QFormLayout>
#include <QLabel>
SecondWidget::SecondWidget(QWidget *parent) : QDialog(parent)
{
# If you don't call the constructor of your superclass you can still assign a parent by invoking setParent(parent) here
QFormLayout *layout = new QFormLayout();
QLabel *label = new QLabel("SecondWidget here");
layout->addWidget(label); # Transfer ownership of label to SecondWidget
setLayout(layout);
}
SecondWidget::~SecondWidget()
{
}
Note the setParent(parent) inside the SecondWidget's constructor. You either have to invoke the superclass constructor (as you have done) or manually call setParent(parent). If you don't do that yoursecondWidgetwill not be assigned as a child to your main widget where you create it and thus you will produce a memory leak. You can also invokesecondWidget->setParent(this)` from within the constructor of your main widget in order to set the parent.
Here is how you can check if the parent-child hierarchy is okay:
To each QObject that you have (QWidget, QLayout etc. are all subclasses of QObject) assign an object name using QObject::setObjectName("some name")
At the end of both of your constructors add:
for(int i = 0; i < this->children().count(); i++)
std::cout << this->children()[i]->objectName().toStdString() << std::endl; // Add #include <iostream> to get the output
which basically traverses all the children of this (Widget or SecondWidget) and displays its children. In my case I got
label // Printing out children of SecondWidget
formLayout // Printing out children of SecondWidget
gridLayout // Printing out children of Widget
pushButton // Printing out children of Widget
main second widget // Printing out children of Widget
once I launched my application.
EDIT 3: Ah, I didn't notice that you are calling the QWidget(parent) in you SecondWidget constructor. This also does the trick so you don't need setParent(parent). I have altered my second EDIT.
This usually happens if
classes are linked
destructor calls aren't properly being called
Makefile needs some changes.
Actual Error?
Makefile needs to be remade using the cmd prompt or Terminal
Make sure that your destructor doesn't call itself so this change the remedy of execution.

How to easily get the button Press in a dialog box in Qt/C++

I have wrote an app which mainly is an equivalent to mac osx finder. When copying file into a folder, I'm checking if a file of the same name already exist. In case it exist, I'm asking the user if he want to cancel, overwrite or not overwrite.
The Dialog box for the overwrite has been created with QT designer and generate a dialogoverwrite.ui, .cpp and .h.
User Interface
dialogoverwrite.cpp
#include <QDialogButtonBox>
#include "dialogoverwrite.h"
#include "ui_dialogoverwrite.h"
DialogOverwrite::DialogOverwrite(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogOverwrite)
{
ui->setupUi(this);
}
DialogOverwrite::~DialogOverwrite()
{
delete ui;
}
dialogoverwrite.h
#include <QDialog>
#include <QDialogButtonBox>
namespace Ui {
class DialogOverwrite;
}
class DialogOverwrite : public QDialog
{
Q_OBJECT
public:
explicit DialogOverwrite(QWidget *parent = 0);
~DialogOverwrite();
private:
Ui::DialogOverwrite *ui;
};
I'm using this class in My TreeWidget application as shown below, I will only add the required code
DialogOverwrite *OverwriteDialog = new DialogOverwrite;
OverwriteDialog->exec();
A kind of OverwriteDialog.button.value could be perfect for me.
the exec will show the dialog and wait for a user action. How can I easily catch the return value : Cancel, Yes, YesToAll, No, NoToAll
I'm looking for an easy to get it. I would like to avoid any additional method in the dialogoverwrite class with signal/connecT. I really just need the button value to react.
Thanks a lot
Call QDialog::done(int r) with a value that represents one of the closing buttons. This value is returned by exec().
Default values are provided by QDialog::DialogCode enum.

qt4 designer add custom class

Hi i have made a gui in qt4 designer and want to add custom slots with custom class.
It project compiles nicely without errors but my custom function wont work what am i doing wrong? I will show u the header file qt4 designer made for me and ill show u my custom file as well as the main.cpp.. first the main.cpp
I have revised my code, here is what i have now i have added a file called sweetest.cpp and edited the sweetest.h here are my new file and the error i recieve..
First main.cpp
#include "ui_sweetguiform.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *widget = new QWidget;
Ui::SweetGuiForm ui;
ui.setupUi(widget);
widget->show();
return app.exec();
}
now my custom header file sweetest.cpp
#include "sweetest.h"
// trying to include the .moc file wouldnt work at all.
now the sweettest.h file with my code
#include "ui_sweetguiform.h"
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
SweetGuiForm( ): ui( new Ui::SweetGuiForm )
{
ui->setupUi( this );
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted()));
}
public slots:
void on_buttonBox_accepted()
{
ui.textEdit->setText(QString::number(23));
}
protected:
Ui::SweetGuiForm* ui;
};
Here is the compile error i recieve.. I am really stuck
In file included from sweetest.cpp:1:
sweetest.h: In member function ‘void SweetGuiForm::on_buttonBox_accepted()’:
sweetest.h:16: error: request for member ‘textEdit’ in ‘((SweetGuiForm*)this)->SweetGuiForm::ui’, which is of non-class type ‘Ui::SweetGuiForm*’
make: *** [sweetest.o] Error 1
I think im getting closer
The way that signals and slots work is that you must connect a signal to a slot. In your code, the simplest way to do that is in the constructor for the SweetGuiForm. You need to add:
SweetGuiForm() : ui(new Ui::SweetGuiForm) {
ui->setupUi(this);
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted()));
}
When the buttonBox emits its accepted signal all slots connected to it will be called.
update 1
On further inspection of your code, you are also missing the Qt macros that are used by the Qt MOC (meta-object compiler) system (http://qt-project.org/doc/qt-4.8/moc.html):
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
...
};
You also have to push the code through the MOC tool. It will generate a source file that needs to be included in your source. As I recall, you must include that in a cpp file; inclusion in a header is problematic. The following should be sufficient:
sweetguiform.cpp:
#include "suiteguiform.h"
#include "sweetguiform.moc"
update 2
On further further reflection, I had forgotten about the automatic signal/slot connection feature when you name your slots using special names (such as on_buttonBox_accepted). There is a blog post on just that here: http://qtway.blogspot.com/2010/08/automatic-connections-using-qt-signals.html. I've not used it myself, so I can't comment on its ability to work when using a ui member variable, though I suspect that it does not work in that arrangement. Regardless, you still need the Q_OBJECT macro and MOC.
Ok guys i figured it out and thought ide share what i found.
First the documentation is excellent in qt4 use it.
I found you can use qt4 designer to generate the hearder files, first i complied it with out custom slots and generated the ui_sweetgui2.h, then i could open the sweetgui2.h file generated by the first compile i did delete what qt4 put in there and put my custom slots in at that stage. did my head in for hours.... days.
so here is the simplest app on earth but its got me started so here are the files and code that worked for me and the documentation basically got me to click on to whats going on.
main.cpp
Strait from the documentation just changed the class name "SweetGuiForm".
#include <QApplication>
#include "sweetgui2.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SweetGuiForm sweetgui;
sweetgui.show();
return app.exec();
}
next sweetgui2.cpp
My first attempt at c++.. ugly but works. But again i found everything about getting the text from the textEdit and type casting it to a int in the calculator example and searching for toPlainText() in the qt4 assistant. notice below im including the file that i will define the new slots that ill show further on in my explanation. hope im making sense.
#include <QtGui>
#include "sweetgui2.h"
SweetGuiForm::SweetGuiForm(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
void SweetGuiForm::on_buttonBox_accepted()
{
QString stringamount = ui.textEdit->toPlainText();
int digitamount = stringamount.toInt();
ui.textEdit->setText(QString::number(25 + digitamount));
}
next sweetgui2.h the one we included above My custom header file with my custom slot.... simple as i said from the calculator example and twisted a lil.. you will get it this is not what it looks like when you generate it from designer on the first compile this is after i have deleted nearly all what was there and opened the calculator example and followed in the tutorial wich shows you how to make your first custom slot .
#ifndef SWEETGUI2_H
#define SWEETGUI2_H
#include "ui_sweetgui2.h"
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
SweetGuiForm(QWidget *parent = 0);
private slots:
void on_buttonBox_accepted();
private:
Ui::SweetGuiForm ui;
};
#endif // SWEETGUI2_H
Again Straight from the documentation. I used the calculator example to get the basic flow.
next ui_sweetgui2.h
I include this file because i was trying to add my slots to the sweetgui2.h that was generated by qt4 desinger. doesnt work guys ..so i compiled first with sweetgui2.h file you generate with the designer, i go to forms menu then view code that is where u can save header files. then of course save the ui file.
and compile then you end up with the ui_sweetgui2.h file wich looked like the sweetgui2.h generated by the designer
#ifndef UI_SWEETGUI2_H
#define UI_SWEETGUI2_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QHeaderView>
#include <QtGui/QTextEdit>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_SweetGuiForm
{
public:
QDialogButtonBox *buttonBox;
QTextEdit *textEdit;
void setupUi(QWidget *SweetGuiForm)
{
if (SweetGuiForm->objectName().isEmpty())
SweetGuiForm->setObjectName(QString::fromUtf8("SweetGuiForm"));
SweetGuiForm->resize(486, 238);
buttonBox = new QDialogButtonBox(SweetGuiForm);
buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
buttonBox->setGeometry(QRect(150, 200, 181, 26));
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
textEdit = new QTextEdit(SweetGuiForm);
textEdit->setObjectName(QString::fromUtf8("textEdit"));
textEdit->setGeometry(QRect(150, 50, 221, 91));
retranslateUi(SweetGuiForm);
QObject::connect(buttonBox, SIGNAL(rejected()), SweetGuiForm, SLOT(close()));
QMetaObject::connectSlotsByName(SweetGuiForm);
} // setupUi
void retranslateUi(QWidget *SweetGuiForm)
{
SweetGuiForm->setWindowTitle(QApplication::translate("SweetGuiForm", "SweetGuiBack", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class SweetGuiForm: public Ui_SweetGuiForm {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_SWEETGUI2_H
Then i recompiled again with my custom slots and shazam! now i can begin to learn some c++.
thanks for all the hints guys, between you all and the documentation i got there.
hope this helps. The main thing to look at is the order things are included i mean my sweetgui2.cpp file
includes the sweetgui2.h file. wich grabs all my custom stuff.
My sweetgui2.h file
includes the ui_sweetgui2.h wich has all the stuff the designer made when i did the first compile. Main.cpp calls my SweetGuiForm class .
As you all can see my first couple days with c++ but this is a good starting point. it made me put the basic flow together in my mind. qt4 assistant look at it.. its well explained and the examples seem very good. ho ho ho merry xmas. hope my explanation helps.