I am trying to know how Qt implements meta object compiling which enables them to provide signal slot mechanism in Qt. I am not able to finding much details in the documentation.
EDIT::I am not able to get the source code of _id = QObject::qt_metacall(_c, _id, _a);
Following is source file and corresponding moc file.
#ifndef SSOBJECT_H
#define SSOBJECT_H
#include <QObject>
class ssObject : public QObject
{
Q_OBJECT
public:
explicit ssObject(QObject *parent = 0);
signals:
void readyToPrint();
void readyToPrint1(int);
void readyToPrint2(float);
private slots:
int print();
};
#endif // SSOBJECT_H
//output from MOC
#include "../ssobject.h"
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'ssobject.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 62
#error "This file was generated using the moc from 4.6.1. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_ssObject[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
4, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// signals: signature, parameters, type, tag, flags
10, 9, 9, 9, 0x05,
25, 9, 9, 9, 0x05,
44, 9, 9, 9, 0x05,
// slots: signature, parameters, type, tag, flags
69, 9, 65, 9, 0x08,
0 // eod
};
static const char qt_meta_stringdata_ssObject[] = {
"ssObject\0\0readyToPrint()\0readyToPrint1(int)\0"
"readyToPrint2(float)\0int\0print()\0"
};
const QMetaObject ssObject::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_ssObject,
qt_meta_data_ssObject, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &ssObject::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *ssObject::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *ssObject::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_ssObject))
return static_cast<void*>(const_cast< ssObject*>(this));
return QObject::qt_metacast(_clname);
}
int ssObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: readyToPrint(); break;
case 1: readyToPrint1((*reinterpret_cast< int(*)>(_a[1]))); break;
case 2: readyToPrint2((*reinterpret_cast< float(*)>(_a[1]))); break;
case 3: { int _r = print();
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
default: ;
}
_id -= 4;
}
return _id;
}
// SIGNAL 0
void ssObject::readyToPrint()
{
QMetaObject::activate(this, &staticMetaObject, 0, 0);
}
// SIGNAL 1
void ssObject::readyToPrint1(int _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
// SIGNAL 2
void ssObject::readyToPrint2(float _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
QT_END_MOC_NAMESPACE
Also explain how
QObject::connect(ssobj1,SIGNAL(readyToPrint()),ssobj1,SLOT(print()))
expands
The best way to figure this out is to download the source code and have a look.
Related
I am getting these two errors when initializing vc below.
#include <iostream>
#include <complex>
#include <math>
#include <vector>
#include <limits>
#include <list>
#include <string>
class Vector {
private:
double* elem; // elem points to an array of sz doubles
int sz;
public:
Vector(int s) :elem{ new double [s] }, sz{ s } // constructor: acquire resources
{
for (int i = 0; i != s; ++i) elem[i] = 0; // initialize elements
~Vector() { delete[] elem; } // destructor: release resources
double& operator[](int i);
int size() const;
void push_back(double);
};
double& Vector::operator[](int i)
{
// TODO: insert return statement here
// added below since the funtion needs to return a double and
return elem[i];
}
int Vector::size() const
{
return sz;
}
void Vector::push_back(double)
{
}
class Container {
public:
virtual double& operator[](int) = 0; // pure virtual function
virtual int size() const = 0; // const member function (§3.2.1.1)
virtual ~Container() {} // destructor (§3.2.1.2)
};
// use function uses Container interface.
void use(Container& c)
{
const int sz = c.size();
for (int i=0; i!=sz; ++i)
cout << c[i] << '\n';
}
class Vector_container : public Container { // List_container implements Container
Vector v;
public:
Vector_container(int s) : v(s) {} // Vector of s elements
void ˜Vector_container() {}
double& operator[](int i) { return v[i]; }
int size() const { return v.size(); }
};
void main()
{
Vector_container vc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
use(vc)
}
I receive both errors pointing at this line Vector_container vc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
Error E0289 is - no instance of constructor "Vector_container::Vector_container" matches the argument list
Error C2440 'initializing': cannot convert from 'initializer list' to 'Vector_container'
I was able to solve the issue by modifying the Vector_container and initializing using Initializer-list constructor below:
class Vector_container : public Container {
std::list<double> ld;
public:
Vector_container() { }
Vector_container(initializer_list<double> il) : ld{ il } {}
~Vector_container() {}
double& operator[](int i);
int size() const { return ld.size(); }
};
double& Vector_container::operator[](int i)
{
for (auto& x : ld) {
if (i == 0) return x;
--i;
}
}
I am beginner to qt. I was working on calculator gui application, I have already defined slots like numPressed() when any of the number pushbutton is pressed on the calculator that will be displayed on the lineEdit.
void Calculator::numPressed(){
QPushButton *button = (QPushButton *)sender();
QString buttonValue = button->text();
Qstring display = ui->lineEdit->text();
Qdouble ProcessedValue = previousValue + buttonValue.toDouble();
.
.
.
ui->lineEdit->setText(QString::number(ProcessedValue));
}
connect(ui->add_button,SIGNAL(released),this,SLOT(numPressed));
Here add_button is a QPushbutton name on the UI.
What i want to achieve is?
When a number key is pressed on the key board i want to connect the number pressed and number pushbutton on the calculator which fills the lineEdit with the number that i have pressed on the keyboard?
PS: I want to connect number pressed on the keyboard to the number on the pushbutton.
If QPushButton is used for the calculator buttons then the solution might be very easy:
Qt provides a concept for short cuts. Actions as well as certain widgets (QPushButton included) are already prepared for this.
QPushButton::shortcut (inherited from base class QAbstractButton):
This property holds the mnemonic associated with the button
Access functions:
QKeySequence shortcut() const
void setShortcut(const QKeySequence &key)
Example:
// a button with label '0'
QPushButton qBtn0("0");
// set shortcut for key 0
qBtn0.setShortcut(QKeySequence("0"));
To try this out, I used my (old) pocket calculator example and added the support of shortcut keys.
The one-and-only source code qCalc.cc:
#include <QtWidgets>
class Calculator: public QWidget {
private:
const char *const _error;
int _accuSum, _accuProd;
char _op;
bool _clr;
QGridLayout _qGrid;
QLineEdit _qView;
QPushButton _qBtnClr;
QPushButton _qBtn7, _qBtn8, _qBtn9, _qBtnDiv;
QPushButton _qBtn4, _qBtn5, _qBtn6, _qBtnMul;
QPushButton _qBtn1, _qBtn2, _qBtn3, _qBtnSub;
QPushButton _qBtnNeg, _qBtn0, _qBtnEqu, _qBtnAdd;
public:
explicit Calculator(QWidget *pQParent = nullptr);
virtual ~Calculator() = default;
Calculator(const Calculator&) = delete;;
Calculator operator=(const Calculator&) = delete;
private:
void clear(bool);
void negate(bool);
void addDigit(char digit);
void eval(char op);
};
Calculator::Calculator(QWidget *pQParent):
QWidget(pQParent),
_error("ERROR"), _accuSum(0), _accuProd(0), _op(' '), _clr(true),
_qBtnClr("C"),
_qBtn7("7"), _qBtn8("8"), _qBtn9("9"), _qBtnDiv("/"),
_qBtn4("4"), _qBtn5("5"), _qBtn6("6"), _qBtnMul("*"),
_qBtn1("1"), _qBtn2("2"), _qBtn3("3"), _qBtnSub("-"),
_qBtnNeg("-"), _qBtn0("0"), _qBtnEqu("="), _qBtnAdd("+")
{
// setup GUI
_qView.setReadOnly(true);
_qGrid.addWidget(&_qView, 0, 0, 1, 3);
_qBtnClr.setShortcut(QKeySequence("C"));
_qGrid.addWidget(&_qBtnClr, 0, 3);
_qBtn7.setShortcut(QKeySequence("7"));
_qGrid.addWidget(&_qBtn7, 1, 0);
_qBtn8.setShortcut(QKeySequence("8"));
_qGrid.addWidget(&_qBtn8, 1, 1);
_qBtn9.setShortcut(QKeySequence("9"));
_qGrid.addWidget(&_qBtn9, 1, 2);
_qBtnDiv.setShortcut(QKeySequence("/"));
_qGrid.addWidget(&_qBtnDiv, 1, 3);
_qBtn4.setShortcut(QKeySequence("4"));
_qGrid.addWidget(&_qBtn4, 2, 0);
_qBtn5.setShortcut(QKeySequence("5"));
_qGrid.addWidget(&_qBtn5, 2, 1);
_qBtn6.setShortcut(QKeySequence("6"));
_qGrid.addWidget(&_qBtn6, 2, 2);
_qBtnMul.setShortcut(QKeySequence("*"));
_qGrid.addWidget(&_qBtnMul, 2, 3);
_qBtn1.setShortcut(QKeySequence("1"));
_qGrid.addWidget(&_qBtn1, 3, 0);
_qBtn2.setShortcut(QKeySequence("2"));
_qGrid.addWidget(&_qBtn2, 3, 1);
_qBtn3.setShortcut(QKeySequence("3"));
_qGrid.addWidget(&_qBtn3, 3, 2);
_qBtnSub.setShortcut(QKeySequence("-"));
_qGrid.addWidget(&_qBtnSub, 3, 3);
/// #todo _qBtnNeg.setShortcut(QKeySequence("???"));
_qGrid.addWidget(&_qBtnNeg, 4, 0);
_qBtn0.setShortcut(QKeySequence("0"));
_qGrid.addWidget(&_qBtn0, 4, 1);
_qBtnEqu.setShortcut(QKeySequence(Qt::Key_Enter));
_qGrid.addWidget(&_qBtnEqu, 4, 2);
_qBtnAdd.setShortcut(QKeySequence("+"));
_qGrid.addWidget(&_qBtnAdd, 4, 3);
setLayout(&_qGrid);
// connect signal handlers
connect(&_qBtnClr, &QPushButton::clicked,
this, &Calculator::clear);
connect(&_qBtn7, &QPushButton::clicked,
[this](bool) { addDigit('7'); });
connect(&_qBtn8, &QPushButton::clicked,
[this](bool) { addDigit('8'); });
connect(&_qBtn9, &QPushButton::clicked,
[this](bool) { addDigit('9'); });
connect(&_qBtnDiv, &QPushButton::clicked,
[this](bool) { eval('/'); });
connect(&_qBtn4, &QPushButton::clicked,
[this](bool) { addDigit('4'); });
connect(&_qBtn5, &QPushButton::clicked,
[this](bool) { addDigit('5'); });
connect(&_qBtn6, &QPushButton::clicked,
[this](bool) { addDigit('6'); });
connect(&_qBtnMul, &QPushButton::clicked,
[this](bool) { eval('*'); });
connect(&_qBtn1, &QPushButton::clicked,
[this](bool) { addDigit('1'); });
connect(&_qBtn2, &QPushButton::clicked,
[this](bool) { addDigit('2'); });
connect(&_qBtn3, &QPushButton::clicked,
[this](bool) { addDigit('3'); });
connect(&_qBtnSub, &QPushButton::clicked,
[this](bool) { eval('-'); });
connect(&_qBtnNeg, &QPushButton::clicked,
this, &Calculator::negate);
connect(&_qBtnClr, &QPushButton::clicked,
this, &Calculator::clear);
connect(&_qBtn0, &QPushButton::clicked,
[this](bool) { addDigit('0'); });
connect(&_qBtnEqu, &QPushButton::clicked,
[this](bool) { eval('='); });
connect(&_qBtnAdd, &QPushButton::clicked,
[this](bool) { eval('+'); });
// init
clear(false);
}
void Calculator::clear(bool)
{
_qView.setText("+0");
_accuSum = _accuProd = 0; _op = ' ';
_clr = false;
}
void Calculator::negate(bool)
{
QString text = _qView.text();
if (text == _error) return;
text[0] = text[0] == '-' ? '+' : '-';
_qView.setText(text);
}
void Calculator::addDigit(char c)
{
QString text = _qView.text();
if (text == _error) return;
if (_clr) text = "+";
else if (text == "+0" || text == "-0") text.chop(1);
if (text.length() < 10) text += c;
_clr = false;
_qView.setText(text);
}
void Calculator::eval(char op)
{
QString text = _qView.text();
if (text == _error) return;
int value = text.toInt();
switch (_op) {
case '+':
_accuSum += _accuProd;
_accuProd = value;
break;
case '-':
_accuSum += _accuProd;
_accuProd = -value;
break;
case '*':
_accuProd *= value;
break;
case '/':
if (value == 0) {
_qView.setText("ERROR"); return;
}
_accuProd /= value;
break;
default:
_accuProd = value;
}
switch (op) {
case '=':
case '+': case '-':
_accuProd += _accuSum; _accuSum = 0;
}
text = QString::number(_accuProd);
if (text[0] != '-') text.insert(0, '+');
_qView.setText(text);
_op = op; _clr = true;
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
Calculator qCalc;
qCalc.show();
return app.exec();
}
A Qt project file to build qCalc.pro:
SOURCES = qCalc.cc
QT = widgets
Built and tested in VS2017 with Qt 5.13:
I created a QtGuiApplication with qt designer and add a simple class on it. In spite of this class inherits from QObject class and has Q_OBJECT macro in private section, the code doesn't run and I confronted with this error:
LNK2001 unresolved external symbol "public: virtual struct QMetaObject
const * __cdecl Sender::metaObject(void)const "
(?metaObject#Sender##UEBAPEBUQMetaObject##XZ) QtGuiApplication1
class header:
#ifndef SENDER_H
#define SENDER_H
#include <QObject>
class Sender : public QObject
{
Q_OBJECT
public:
explicit Sender(QObject *parent = 0);
void fireSignal();
signals:
void foo(const QString& arg);
};
#endif // SENDER_H
class cpp:
#include "Sender.h"
Sender::Sender(QObject *parent) :
QObject(parent)
{
}
void Sender::fireSignal()
{
emit foo("aa");
}
GUI header:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiApplication1.h"
class QtGuiApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication1(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplication1Class ui;
};
GUI cpp:
#include "QtGuiApplication1.h"
#include <QPainter>
QtGuiApplication1::QtGuiApplication1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
When I comment Q_OBJECT macro and emit foo("aa"); it works.
Where do I make mistakes? Thanks.
edited: attach moc_Sender.cpp
/****************************************************************************
** Meta object code from reading C++ file 'Sender.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.11.1)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../Sender.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'Sender.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.11.1. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_Sender_t {
QByteArrayData data[4];
char stringdata0[16];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_Sender_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_Sender_t qt_meta_stringdata_Sender = {
{
QT_MOC_LITERAL(0, 0, 6), // "Sender"
QT_MOC_LITERAL(1, 7, 3), // "foo"
QT_MOC_LITERAL(2, 11, 0), // ""
QT_MOC_LITERAL(3, 12, 3) // "arg"
},
"Sender\0foo\0\0arg"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_Sender[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
1, // signalCount
// signals: name, argc, parameters, tag, flags
1, 1, 19, 2, 0x06 /* Public */,
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
0 // eod
};
void Sender::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Sender *_t = static_cast<Sender *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->foo((*reinterpret_cast< const QString(*)>(_a[1]))); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Sender::*)(const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Sender::foo)) {
*result = 0;
return;
}
}
}
}
QT_INIT_METAOBJECT const QMetaObject Sender::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_Sender.data,
qt_meta_data_Sender, qt_static_metacall, nullptr, nullptr}
};
const QMetaObject *Sender::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *Sender::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_Sender.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
int Sender::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 1)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 1;
}
return _id;
}
// SIGNAL 0
void Sender::foo(const QString & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
I have a class with a lot of member functions. Here are the ones giving me trouble (Segmentation Fault):
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"
MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
blah
}
MainWindow::~MainWindow(){delete ui;}
void MainWindow::resetHandle() {
//Open the first found LabJack U3.
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = GoOne(*lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
}
void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
char err[255];
if((lngErrorcode == 1015) && (!isOpen))
{
isOpen = true;
//STOP EVERYTHING
MainWindow::on_pushButton_clicked(false);
//Create an error message dialog only to prompt to connect labjack.
QMessageBox *msg = new QMessageBox();
msg->show();
msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");
}
if(lngErrorcode == 1003)
{
//attempt to solve handle problem by resetting handle
OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
GoOne(*lngHandle);
}
if(lngErrorcode != LJE_NOERROR)
{
ui->textBrowser->show();
ui->exitTextBrowser->show();
ErrorToString(lngErrorcode,err);
ui->textBrowser->setText(err);
}
}
void MainWindow::update_timer_complete()
{
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
//I really wanted to check if stuff is working during each update.
resetHandle(); //Will call runningError() handler if problem
}
I can call my error handling function runningError() from any member function except void update_timer_complete(). When I do, I get a .exe crash.
There were a lot more member functions omitted.
If this helps, here is the class definition header file:
#include <QMainWindow>
#include "LabJackUD.h"
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0, LJ_HANDLE* lngHandle = 0);
~MainWindow();
private slots:
void cycle_timer_complete();
void next_timer_complete(bool update = false);
void update_timer_complete();
void on_radioButton_pressed();
void on_radioButton_2_pressed();
void on_radioButton_released();
void on_radioButton_3_pressed();
void on_radioButton_4_pressed();
void on_pushButton_toggled(bool checked);
void on_pushButton_clicked();
void on_pushButton_4_clicked();
void on_pushButton_clicked(bool checked);
void on_exitTextBrowser_clicked();
private:
Ui::MainWindow *ui;
LJ_HANDLE *lngHandle;
LJ_ERROR lngErrorcode;
void clearAll();
void runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration);
QTimer *cycleComplete;
QTimer *nextExperiment;
QTimer *updateLCDs;
int selectedPin;
int timer1;
int timer2;
int timer3;
int prevTime, prevSpin1, prevSpin2, prevSpin3, prevSpin4;
void resetHandle();
void updatePins();
};
What could allow two equivalent member functions of the form private void doStuff() to have unequal access to the same member function? One calls it fine, the other calls it and produces a segmentation fault!
If really required, here is the full code:
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"
bool isOpen = false;
MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
lngHandle = lngHandle2;
cycleComplete = new QTimer(this);
nextExperiment = new QTimer(this);
updateLCDs = new QTimer(this);
selectedPin = 0;
timer1 = 0;
timer2 = 0;
timer3 = 0;
lngErrorcode = 0;
connect(cycleComplete,SIGNAL(timeout()),this,SLOT(cycle_timer_complete()));
connect(nextExperiment,SIGNAL(timeout()),this,SLOT(next_timer_complete()));
connect(updateLCDs,SIGNAL(timeout()),this,SLOT(update_timer_complete()));
ui->textBrowser->hide();
ui->textBrowser->raise();
ui->exitTextBrowser->hide();
ui->exitTextBrowser->raise();
clearAll();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resetHandle() {
//Open the first found LabJack U3.
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = GoOne(*lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
}
void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
char err[255];
if((lngErrorcode == 1015) && (!isOpen))
{
isOpen = true;
//STOP EVERYTHING
MainWindow::on_pushButton_clicked(false);
//Create an error message dialog only to prompt to connect labjack.
QMessageBox *msg = new QMessageBox();
msg->show();
msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");
}
if(lngErrorcode == 1003)
{
//attempt to solve handle problem by resetting handle
OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
GoOne(*lngHandle);
}
if(lngErrorcode != LJE_NOERROR)
{
ui->textBrowser->show();
ui->exitTextBrowser->show();
ErrorToString(lngErrorcode,err);
ui->textBrowser->setText(err);
//Qdebugging purposes
qDebug() << ("Error number = ") << lngErrorcode;
qDebug() << ("Error string = ") << err;
qDebug() << ("Source line number = ") << lngLineNumber;
qDebug() << ("Iteration = ") << lngIteration;
}
}
void MainWindow::clearAll() {
lngErrorcode = eDO(*lngHandle, 4, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 5, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 6, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 7, 0);
runningErrors(lngErrorcode, __LINE__, 0);
ui->radioButton->setChecked(false);
ui->radioButton_2->setChecked(false);
ui->radioButton_3->setChecked(false);
ui->radioButton_4->setChecked(false);
}
void MainWindow::on_radioButton_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 4, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 1 pressed";
ui->radioButton->setChecked(true);
}
void MainWindow::on_radioButton_2_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 5, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 2 pressed";
ui->radioButton_2->setChecked(true);
}
void MainWindow::on_radioButton_3_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 6, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 3 pressed";
ui->radioButton_3->setChecked(true);
}
void MainWindow::on_radioButton_4_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 7, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 4 pressed";
ui->radioButton_4->setChecked(true);
}
void MainWindow::on_pushButton_toggled(bool checked)
{
}
void MainWindow::on_pushButton_clicked()
{
}
void MainWindow::cycle_timer_complete()
{
qDebug()<<"cycleComplete timeout";
}
void MainWindow::next_timer_complete(bool update)
{
qDebug()<<"nextExperiment timeout";
if (!update) {
selectedPin++;
}
qDebug()<<"selectedPin is " << selectedPin;
switch ( selectedPin ) {
case 4:
qDebug() << "case 4";
if (!update) {
nextExperiment->start((ui->spinBox->value())*1000*7);
}
MainWindow::on_radioButton_pressed();
break;
case 5:
qDebug() << "case 5";
nextExperiment->start((ui->spinBox_2->value())*1000*7);
MainWindow::on_radioButton_2_pressed();
break;
case 6:
qDebug() << "case 6";
nextExperiment->start((ui->spinBox_3->value())*1000*7);
MainWindow::on_radioButton_3_pressed();
break;
case 7:
qDebug() << "case 7";
nextExperiment->start((ui->spinBox_4->value())*1000*7);
MainWindow::on_radioButton_4_pressed();
break;
case 8:
qDebug() << "case 8";
MainWindow::on_pushButton_clicked(true);
break;
}
//ui->pushButton->setText("Timer Complete");
}
void MainWindow::update_timer_complete()
{
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
//I really wanted to check if stuff is working during each update.
resetHandle();
}
void MainWindow::on_pushButton_4_clicked()
{
//figure out the total cycle time
int t_total = ui->spinBox->value();
t_total += ui->spinBox_2->value();
t_total += ui->spinBox_3->value();
t_total += ui->spinBox_4->value();
//continue counting from previous state, correct for new values
int newCycleTime = timer1;
int newExpTime = timer2;
int c1 = ui->spinBox->value();
int c2 = ui->spinBox_2->value();
int c3 = ui->spinBox_3->value();
int c4 = ui->spinBox_4->value();
switch(selectedPin) {
case 4:
newExpTime += (c1 - prevSpin1)*1000*7;
newCycleTime += (c1+c2+c3+c4-prevSpin1-prevSpin2-prevSpin3-prevSpin4)*1000*7;
case 5:
newExpTime += (c2 - prevSpin2)*1000*7;
newCycleTime += (c2+c3+c4-prevSpin2-prevSpin3-prevSpin4)*1000*7;
case 6:
newExpTime += (c3 - prevSpin3)*1000*7;
newCycleTime += (c3+c4-prevSpin3-prevSpin4)*1000*7;
case 7:
newExpTime += (c4 - prevSpin4)*1000*7;
newCycleTime += (c4-prevSpin4)*1000*7;
}
cycleComplete->start(newCycleTime);
nextExperiment->start(newExpTime);
updateLCDs->start(timer3);
//change back appearance
ui->pushButton_4->setEnabled(false);
ui->pushButton->setText("STOP");
ui->radioButton->setEnabled(false);
ui->radioButton_2->setEnabled(false);
ui->radioButton_3->setEnabled(false);
ui->radioButton_4->setEnabled(false);
ui->pushButton->setChecked(true);
prevSpin1 = c1;
prevSpin2 = c2;
prevSpin3 = c3;
prevSpin4 = c4;
//no dialog open so reset
isOpen=false;
}
void MainWindow::on_radioButton_released()
{
}
void MainWindow::on_pushButton_clicked(bool checked)
{
if(checked) {
//START NRML OPERATION
//selectedPin will become 4 very shortly.
selectedPin = 3;
//figure out the total cycle time
int t_total = ui->spinBox->value();
t_total += ui->spinBox_2->value();
t_total += ui->spinBox_3->value();
t_total += ui->spinBox_4->value();
t_total *= 1000*7;
//keep track for continue option.
prevTime = t_total;
//configure timers
cycleComplete->setInterval(t_total);
nextExperiment->setInterval(0);
updateLCDs->setInterval(100);
ui->pushButton->setText("STOP");
ui->radioButton->setEnabled(false);
ui->radioButton_2->setEnabled(false);
ui->radioButton_3->setEnabled(false);
ui->radioButton_4->setEnabled(false);
ui->pushButton_4->setEnabled(false);
ui->spinBox->setEnabled(false);
ui->spinBox_2->setEnabled(false);
ui->spinBox_3->setEnabled(false);
ui->spinBox_4->setEnabled(false);
//start timers
cycleComplete->start();
nextExperiment->start();
updateLCDs->start();
//no dialog open so reset
isOpen=false;
} else {
//STOP EVERYTHING REVERT EVERYTHING
//enable continue button
ui->pushButton_4->setEnabled(true);
//revert appearance
ui->pushButton->setText("START");
ui->radioButton->setEnabled(true);
ui->radioButton_2->setEnabled(true);
ui->radioButton_3->setEnabled(true);
ui->radioButton_4->setEnabled(true);
ui->spinBox->setEnabled(true);
ui->spinBox_2->setEnabled(true);
ui->spinBox_3->setEnabled(true);
ui->spinBox_4->setEnabled(true);
//copy the current state for continuing
//+1 because finished timer is -1
timer1 = (cycleComplete->remainingTime()+1);
timer2 = (nextExperiment->remainingTime()+1);
timer3 = (updateLCDs->remainingTime()+1);
prevSpin1 = ui->spinBox->value();
prevSpin2 = ui->spinBox_2->value();
prevSpin3 = ui->spinBox_3->value();
prevSpin4 = ui->spinBox_4->value();
//stop the timers
cycleComplete->stop();
nextExperiment->stop();
updateLCDs->stop();
}
}
void MainWindow::on_exitTextBrowser_clicked()
{
ui->textBrowser->hide();
ui->exitTextBrowser->hide();
}
Strangely, the solution was rearange the body of the definition of the member function void update_timer_complete() {body}. I had to put
//I really wanted to check if stuff is working during each update.
resetHandle(); //Will call runningError() handler if problem
above
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
For some reason, the other way around produces a crash. I would love to hear an explanation, and if one is given, I will select it as the answer.
I've just started working with Arduino. I seem to write code like this often:
int input_pins[] = {6, 3, 8, 2};
int input_state[4];
void setup() {
}
void loop() {
for (int i = 0; i < 4; i++){
input_state[i] = digitalRead(input_pins[i]);
}
}
Is there a preprocessor (or something like it) to produce the following effective code?
int input_state[4];
void setup() {
}
void loop() {
input_state[0] = digitalRead(6);
input_state[1] = digitalRead(3);
input_state[2] = digitalRead(8);
input_state[3] = digitalRead(2);
}
Arduino programming has C++ underneath, why do you want to use something as limited as preprocessing?
If you start out with the following code:
///////////////////////////////////////
class DigitalRead
{
public:
DigitalRead(int pins[]);
int operator[](const int index);
int len;
int *mypins;
};
DigitalRead::DigitalRead(int pins[])
{
mypins = pins;
for(len = 0; pins[len] != -1; len++) {};
}
int DigitalRead::operator[](const int index)
{
if (index > len) return -1;
return digitalRead(mypins[index]);
}
///////////////////////////////////////
int pins[] = {6, 3, 8, 2, -1};
DigitalRead input_state = DigitalRead(pins);
void setup()
{
}
void loop()
{
// print the state of pin 6, change as needed
Serial.println(input_state[0]);
}
you can improve on things (setting the pins for input in DigitalRead::DigitalRead e.g.)j. Once things work move the stuff between /////// lines into a library.