Emit Signal Only When QCheckBox is Checked - c++

I am creating a set of QCheckBox dynamically based on some user input like so:
QWidget *wid = new QWidget();
QVBoxLayout *layout = new QVBoxLayout();
for(int i=0; i<NumberModes; i++)
{
int k = Amplitudes(i,0);
int m = Amplitudes(i,1);
QString ks = QString::number(k);
QString ms = QString::number(m);
QString position = QString::number(i);
QString mode = "A"+ks+ms;
QCheckBox *check = new QCheckBox(mode);
connect(check, SIGNAL(toggled(bool)), &mapper, SLOT(map()));
connect(check, SIGNAL(toggled(bool)), &SelectModes, SLOT(map()));
mapper.setMapping(check,position);
SelectModes.setMapping(check,mode);
layout->addWidget(check);
updateGeometry();
}
wid->setLayout(layout);
ui->scrollArea->setWidget(wid);
The QSignalMapper are then connected to another class that performs some calculations:
connect(&SelectModes, SIGNAL(mapped(QString)), this, SIGNAL(CheckBoxClicked2(QString)));
connect(this, SIGNAL(CheckBoxClicked2(QString)), &Supress2, SLOT(ListenSelectedModes(QString)));
connect(&mapper, SIGNAL(mapped(QString)), this, SIGNAL(CheckBoxClicked(QString)));
connect(this, SIGNAL(CheckBoxClicked(QString)), &Suppress, SLOT(ListenSelectedModes(QString)));
What I need is that the classes only receive signals when the QCheckBox are checked; meaning if you check it once, and then un-check it no signal should be emitted, or received. Not sure what the best approach is.
Any ideas?

With C++11 it's doable simply and without QSignalMapper. Here's an working example.
#include <QWidget>
#include <QCheckBox>
#include <QVBoxLayout>
class QCheckBox;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
signals:
void checkBoxChecked(QCheckBox *checkBox);
};
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout *layout = new QVBoxLayout;
for (int i = 0; i < 10; ++i) {
QCheckBox *checkBox = new QCheckBox("CheckBox " + QString::number(i + 1));
connect(checkBox, &QCheckBox::toggled, [=](bool checked) {
if (checked)
emit checkBoxChecked(checkBox);
});
layout->addWidget(checkBox);
}
setLayout(layout);
}

The suggestions given by user2672165 are excellent!
If you want to monitor only the check event but not the uncheck event, one way would be to subclass the QCheckBox widget so that it emits a particular signal only when the checkbox is checked (e.g. checkBoxChecked)
Then you connect your signal mapper to the custom signal checkBoxChecked, instead of the standard toggle(bool) signal.
In this way the slot associated to the signal mapper is invoked only when the checkbox is checked and not when it is unchecked.
Here is a simple example
#include <QApplication>
#include <QtGui>
#include <QVBoxLayout>
#include <QSignalMapper>
#include <QCheckBox>
#include <QDebug>
class CheckableCheckBox : public QCheckBox {
Q_OBJECT
public:
CheckableCheckBox(const QString &text, QWidget *parent = 0)
: QCheckBox(text, parent)
{
connect(this, SIGNAL(toggled(bool)),
this, SLOT(verifyCheck(bool)));
}
signals:
void checkBoxChecked();
public slots:
void verifyCheck(bool checked) {
if (checked)
emit checkBoxChecked();
}
};
class Test : public QWidget {
Q_OBJECT
public:
Test(QWidget *parent = 0) : QWidget(parent) {
QSignalMapper *mapper = new QSignalMapper();
QVBoxLayout *layout = new QVBoxLayout();
for (int i = 0; i < 10; i++) {
QString mode = "A" + QString::number(i);
CheckableCheckBox *check = new CheckableCheckBox(mode);
connect(check, SIGNAL(checkBoxChecked()),
mapper, SLOT(map()));
mapper->setMapping(check, QString::number(i));
layout->addWidget(check);
setLayout(layout);
}
connect(mapper, SIGNAL(mapped(QString)),
this, SLOT(CheckBoxClicked(QString)));
}
public slots:
void CheckBoxClicked(const QString &mapping) {
qWarning() << "Checkbox:" << mapping << " is checked";
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test *wid = new Test();
wid->show();
return a.exec();
}
#include "main.moc"
Edit:
If you want to monitor a change in the check status and then notify to some other portions of the code the status of the checkbox (which is probably what you want) you can do something like this... You don't even need a QSignalMapper...
I have implemented a test method testMonitorCheckStatus to show what I mean. Note that you need typedef QList<bool> CheckBoxStatusList; (at least as far as I know) to use QList as an argument to slots and signals.
Edit #2:
The number of checkboxes is set at object creation
Hope this helps
#include <QApplication>
#include <QtGui>
#include <QVBoxLayout>
#include <QSignalMapper>
#include <QCheckBox>
#include <QList>
#include <QDebug>
typedef QList<bool> CheckBoxStatusList;
class Test : public QWidget {
Q_OBJECT
public:
Test(int totalCheckboxes, QWidget *parent = 0) : QWidget(parent)
{
QVBoxLayout *layout = new QVBoxLayout();
for (int i = 0; i < totalCheckboxes; i++) {
QString mode = "A" + QString::number(i);
QCheckBox *checkBox = new QCheckBox(mode);
connect(checkBox, SIGNAL(toggled(bool)),
this, SLOT(monitorCheckStatus()));
m_checkBoxList.append(checkBox);
layout->addWidget(checkBox);
}
setLayout(layout);
connect(this, SIGNAL(checkBoxStatusChanged(CheckBoxStatusList)),
this, SLOT(testMonitorCheckStatus(CheckBoxStatusList)));
}
public slots:
void monitorCheckStatus() {
CheckBoxStatusList checkBoxStatus;
for (int i = 0; i < m_checkBoxList.count(); ++i)
checkBoxStatus.append(m_checkBoxList.at(i)->isChecked());
emit checkBoxStatusChanged(checkBoxStatus);
}
void testMonitorCheckStatus(const CheckBoxStatusList &checkBoxStatus) {
for (int i = 0; i < checkBoxStatus.count(); ++i)
qWarning() << "Checkbox:" << i << " is" << (checkBoxStatus.at(i) ? "checked" : "unchecked");
qWarning(" ");
}
signals:
void checkBoxStatusChanged(const CheckBoxStatusList &checkBoxStatus);
private:
QList<QCheckBox *> m_checkBoxList;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test *wid = new Test(10);
wid->show();
return a.exec();
}
#include "main.moc"

Related

Qt, C++, XML reader crashes/freezes when I try parsing deeper data values

In an earlier Question I asked about why my program/QTcpServer was crashing all the time, and I really appreciate the help I got from everyone.
However, I have decided to try and rebuild the Program from scratch in order to see why it crashes, and I may have found something.
Allow me to post the new Code below:
//mainwindow.h
#include <QMainWindow>
#include <QPushButton>
#include <QTextEdit>
#include <QStandardItemModel>
#include <QTcpServer>
#include <QTcpSocket>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void startServer();
void handleConnection();
void readMessage();
void ReadXML(QString XMLString);
private:
QPushButton *SServer;
QTextEdit * ContainerView; //not changing to QTableView just yet
int Pallet_Number;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
};
//mainwindow.cpp
#include "mainwindow.h"
#include <QLabel>
#include <QLayout>
#include <QDebug>
#include <QDomDocument>
#include <QRegularExpression>
static QRegularExpression Box_Code("B");
static QRegularExpression Cylinder_Code("C");
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
SServer(new QPushButton("Start Listening")),
ContainerView(new /*QTableView*/QTextEdit),
tcpServer(new QTcpServer),
tcpSocket(new QTcpSocket)
{
QStringList HeaderRow;
HeaderRow.append("Pallet");
HeaderRow.append("Container");
HeaderRow.append("Code");
HeaderRow.append("Height");
HeaderRow.append("Breadth/Diameter");
HeaderRow.append("Length");
HeaderRow.append("Weight");
resize(800,300);
connect(SServer, &QPushButton::clicked, this, &MainWindow::startServer);
connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::handleConnection);
connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::handleConnection);
QLabel *Lab1(new QLabel("Listening on Port 6164"));
QHBoxLayout *HB(new QHBoxLayout);
QVBoxLayout *VB(new QVBoxLayout);
HB->addWidget(SServer);
HB->addWidget(Lab1);
VB->addItem(HB);
VB->addWidget(ContainerView);
QWidget *window(new QWidget);
window->setLayout(VB);
setCentralWidget(window);
}
MainWindow::~MainWindow()
{
}
void MainWindow::startServer()
{
if(!tcpServer->listen(QHostAddress::LocalHost, 6164)){
qDebug() << "Error connecting to Server";
tcpServer->close();
return;
} else {
qDebug() << "Started Successfully";
}
}
void MainWindow::handleConnection()
{
tcpSocket = tcpServer->nextPendingConnection();
qDebug() << "New Connection!";
connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::readMessage);
}
void MainWindow::readMessage()
{
ContainerView->clear(); //clear table to prepare for new XMLString
QByteArray buffer = tcpSocket->readAll();
QString FromContainer = QString::fromUtf8(buffer);
ReadXML(FromContainer);
}
void MainWindow::ReadXML(QString XMLString)
{
ContainerView->append(XMLString);
QDomDocument Xml_String;
Xml_String.setContent(XMLString);
QDomElement Xml_Root = Xml_String.documentElement();
if(Xml_Root.tagName() == "Pallets")
{
QDomElement Xml_Pallet = Xml_Root.firstChildElement();
while(!Xml_Pallet.isNull())
{
if(Xml_Pallet.tagName() == "Pallet")
{
int PN = Xml_Pallet.attribute("Number").toInt(nullptr,10);
QDomElement Box_Cyl = Xml_Pallet.firstChildElement();
while(!Box_Cyl.isNull())
{
if(Box_Cyl.tagName() == "Box")
{
QString BC = Box_Cyl.tagName();
ContainerView->append("Pallet No. " + QString::number(PN) + "\nContainer: " + BC);
// QDomElement Box_Info = Box_Cyl.firstChildElement();
// while(!Box_Info.isNull())
// {
// ...more code
// Box_Info = Box_Info.nextSiblingElement();
// }
} else if(Box_Cyl.tagName() == "Cylinder")
{
QString BC = Box_Cyl.tagName();
ContainerView->append("Pallet No. " + QString::number(PN) + "\nContainer: " + BC);
}
Box_Cyl = Box_Cyl.nextSiblingElement();
}
}
Xml_Pallet = Xml_Pallet.nextSiblingElement();
}
}
}
The XML String I am trying to read is shown below:
When I include the commented code to read the Elements within 'Box' or 'Cylinder' (I altered the code to check both sides), the program freezes.
This hasn't happened to me before, so I have no idea what to do.

Read the input and print factorial in Qt GUI Application using C++

Using QTCreator, I created the design of a GUI Application. I want to read the input entered by the user from lineEdit and when pushButton is clicked, it should print the factorial of that entered number on the same page. I've read some tutorials but don't understand how to code this using qtc++.
A minimal example is like that:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void hClicked();
void hTextEdit(const QString& data);
private:
QString m_linedata;
QPushButton button;
QLineEdit lineEdit;
QHBoxLayout layout;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <iostream>
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
layout.addWidget(&lineEdit);
layout.addWidget(&button);
this->setLayout(&layout);
connect(&lineEdit, &QLineEdit::textChanged, this, &MainWindow::hTextEdit);
connect(&button, &QPushButton::clicked, this , &MainWindow::hClicked);
}
MainWindow::~MainWindow()
{
}
static unsigned factorial(unsigned n)
{
unsigned result = 1;
for (unsigned i=1; i <= n; i++) {
result *= i;
}
return result;
}
void MainWindow::hClicked()
{
if (m_linedata.size() > 0) {
bool res ;
int toint = m_linedata.toInt(&res);
if (res) {
unsigned fact_result = factorial(toint);
lineEdit.clear();
lineEdit.setText(QString::number(fact_result)); }
}
}
void MainWindow::hTextEdit(const QString &data)
{
m_linedata = data;
}
and main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Just do anything you like with the data passed to the auxillary buffer.

Subclass of QPlainText does not expand to fill the layout

I do not understand why the CodeEditor example from the Qt website does not appear to work as expected. Every time I run the code it displays it like this, really small and not expanding to take up all the available space. Does anyone have any idea why? I have even tried to set a fixed size, sizepolicy and minimum sizing. Not sure what I am missing here.
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QLabel>
#include "codeeditor.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
// controls
auto *widget_main = new QWidget(this);
auto *lay_main = new QVBoxLayout(widget_main);
auto *label = new QLabel("Test");
auto *editor = new CodeEditor();
// layout
lay_main->addWidget(label);
lay_main->addWidget(editor);
lay_main->setContentsMargins(5, 5, 5, 5);
}
MainWindow::~MainWindow()
{
}
codeeditor.h:
#ifndef CODEEDITOR_H
#define CODEEDITOR_H
#include <QPlainTextEdit>
#include <QObject>
class QPaintEvent;
class QResizeEvent;
class QSize;
class QWidget;
class LineNumberArea;
// Main text editor
class CodeEditor : public QPlainTextEdit
{
Q_OBJECT
public:
CodeEditor(QWidget *parent = 0);
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberAreaWidth();
protected:
void resizeEvent(QResizeEvent *event) override;
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void highlightCurrentLine();
void updateLineNumberArea(const QRect &, int);
private:
QWidget *lineNumberArea;
};
// Line number gutter
class LineNumberArea : public QWidget
{
public:
LineNumberArea(CodeEditor *editor) : QWidget(editor) {
codeEditor = editor;
}
QSize sizeHint() const override {
return QSize(codeEditor->lineNumberAreaWidth(), 0);
}
protected:
void paintEvent(QPaintEvent *event) override {
codeEditor->lineNumberAreaPaintEvent(event);
}
private:
CodeEditor *codeEditor;
};
#endif
codeeditor.cpp:
#include "codeeditor.h"
#include <QtWidgets>
#include <QFontMetrics>
CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lineNumberArea = new LineNumberArea(this);
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
updateLineNumberAreaWidth(0);
highlightCurrentLine();
setFixedSize(200, 200);
setMinimumSize(200,200);
}
int CodeEditor::lineNumberAreaWidth()
{
int digits = 1;
int max = qMax(1, blockCount());
while (max >= 10) {
max /= 10;
++digits;
}
//int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
int space = 3 + 12 * digits;
return space;
}
void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
lineNumberArea->scroll(0, dy);
else
lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
if (rect.contains(viewport()->rect()))
updateLineNumberAreaWidth(0);
}
void CodeEditor::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
QRect cr = contentsRect();
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
void CodeEditor::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
if (!isReadOnly()) {
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(Qt::yellow).lighter(160);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(lineNumberArea);
painter.fillRect(event->rect(), Qt::lightGray);
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + (int) blockBoundingRect(block).height();
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1);
painter.setPen(Qt::black);
painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + (int) blockBoundingRect(block).height();
++blockNumber;
}
}
QMainWindow is a special widget since it has a preset layout
So you must set the main widget through setCentralWidget():
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto *widget_main = new QWidget;
auto *lay_main = new QVBoxLayout(widget_main);
auto *label = new QLabel("Test");
auto *editor = new CodeEditor();
setCentralWidget(widget_main); // <-- +++
// layout
lay_main->addWidget(label);
lay_main->addWidget(editor);
lay_main->setContentsMargins(5, 5, 5, 5);
}
On the other hand if you are going to use layouts then you should not set a fixed size to the widget, in your case remove setFixedSize(200, 200) on the other hand it is recommended that you make the connections with the new syntax:
CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lineNumberArea = new LineNumberArea(this);
connect(this, &QPlainTextEdit::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);
connect(this, &QPlainTextEdit::updateRequest, this, &CodeEditor::updateLineNumberArea);
connect(this, &QPlainTextEdit::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
updateLineNumberAreaWidth(0);
highlightCurrentLine();
// setFixedSize(200, 200); <-- ---
setMinimumSize(200,200);
}

Clearing and repopulating a QFormLayout

I'm trying to set up a QFormLayout so that some buttons show or hide the part below them, and using setHidden on the widgets I want to hide is resulting in a bad layout due to the form padding still showing.
So I tried this:
#include <QApplication>
#include <QCheckBox>
#include <QLabel>
#include <QFormLayout>
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
QCheckBox checkA;
QFormLayout * m_formLayout;
QWidget * m_widget;
public:
explicit MainWindow(QWidget *parent = 0) :
QMainWindow(parent),
m_formLayout(0L),
m_widget(0L)
{
populate();
connect(&checkA, &QCheckBox::stateChanged, this, &MainWindow::populate);
}
virtual ~MainWindow() { clear(); }
bool doesOwnObject(void * it) const
{
return (uintptr_t)this <= (uintptr_t)it && (uintptr_t)it < (uintptr_t)(this+1);
}
void clear()
{
if(m_formLayout)
{
QLayoutItem *child;
while ((child = m_formLayout->takeAt(0)) != 0)
{
QLayout * layout = child->layout();
QSpacerItem * spacer = child->spacerItem();
QWidget * widget = child->widget();
if(layout && !doesOwnObject(layout)) delete layout;
if(spacer && !doesOwnObject(spacer)) delete spacer;
if(widget && !doesOwnObject(widget)) delete widget;
}
delete m_formLayout;
m_formLayout = 0L;
}
}
void populate()
{
if(m_widget) { clear(); return; }
m_widget = new QWidget(this);
setCentralWidget(m_widget);
m_formLayout = new QFormLayout(m_widget);
m_formLayout->addRow(tr("Show Check Box B:"), &checkA);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
But that doesn't seem to work as clear() doesn't seem to be actually depopulating the form layout. The widgets remain where they were before the QFormLayout was deleted. And if m_widget is deleted then the program will crash as it tries to delete checkA, because checkA has not been removed from the now deleted form.
How do I fix this?
I have come to a solution that has the desirable (or what I understood) behavior. However, I've moved everything to pointers (since is what I am used to with Qt).
Header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QCheckBox>
#include <QLayoutItem>
#include <QFormLayout>
#include <QMainWindow>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
QCheckBox *checkA, *checkB;
QLabel *labelA, *labelB, *labelC;
QFormLayout * m_formLayout;
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
void clear();
public slots:
void populate();
};
#endif // MAINWINDOW_H
cpp file:
#include "mainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget * centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
m_formLayout = new QFormLayout(centralWidget);
checkA = new QCheckBox;
labelA = new QLabel("Show Check Box B:");
connect(checkA, &QCheckBox::stateChanged, this, &MainWindow::populate);
int row = 0;
m_formLayout->insertRow(row++, labelA, checkA);
checkB = new QCheckBox;
labelB = new QLabel("Check Box B:");
m_formLayout->insertRow(row++, labelB, checkB);
labelC = new QLabel("Bottom label");
m_formLayout->insertRow(row++,labelC);
populate();
}
MainWindow::~MainWindow() {
}
void MainWindow::clear()
{
if (!checkA->isChecked())
{
checkB->hide();
labelB->hide();
}
}
void MainWindow::populate()
{
clear();
if(checkA->isChecked())
{
checkB->show();
labelB->show();
}
}
Solution:
void clear()
{
QLayoutItem *child;
while ((child = m_formLayout->takeAt(0)) != 0)
{
QLayout * layout = child->layout();
QSpacerItem * spacer = child->spacerItem();
QWidget * widget = child->widget();
if(layout && !doesOwnObject(layout)) delete layout;
if(spacer && !doesOwnObject(spacer)) delete spacer;
if(widget)
{
if(doesOwnObject(widget)) widget->setParent(0L);
else delete widget;
}
}
}
setParent had to be called.

How to use automatically added Qt-elements

My programm can add new QLabels and QLineEdits to a QScrollArea after a button is clicked. The idea is to create a grocery list. My problem is when a second Button is clicked I want to get the text of all the QLineEdits. But I don't know how to use those elements, because every new QLineEdit-variable has the same name and I don't know how to change that.
Below is a small example:
my MainWindow.h:
#ifndef MainWINDOW_H
#define MainWINDOW_H
#include <QMainWindow>
#include <string>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int i;
private:
Ui::MainWindow *ui;
private slots:
void on_create_clicked();
read_text();
};
#endif // MainWINDOW_H
my MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_create_clicked()));
connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(read_text()));
i = 1;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_create_clicked()
{
if(i < 10)
{
i ++;
QLabel *label_2 = new QLabel();
QString s = QString::number(zaehlerHeight) + ". ";
label_2->setText(s);
ui->scrollArea->widget()->layout()->addWidget(label_2);
QLineEdit *lineEdit = new QLineEdit();
ui->scrollArea_2->widget()->layout()->addWidget(lineEdit);
}
else{
ui->label->setText("already 10");
}
}
void MainWindow::read_text()
{
QString mytext = ui->lineEdit->text();
}
I would simply store the pointer to each QLineEdit in a QVector, and then loop in this vector to get the text of each.
Header:
#ifndef MainWINDOW_H
#define MainWINDOW_H
#include <QMainWindow>
#include <string>
#include <QVector>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int i;
private:
Ui::MainWindow *ui;
QVector<QLineEdit *> m_VecLineEdits;
private slots:
void on_create_clicked();
private:
void read_text();
void GetAllTextEdit();
};
#endif // MainWINDOW_H
In Cpp file, change the following:
void MainWindow::on_create_clicked()
{
if(i < 10)
{
i ++;
QLabel *label_2 = new QLabel();
QString s = QString::number(zaehlerHeight) + ". ";
label_2->setText(s);
ui->scrollArea->widget()->layout()->addWidget(label_2);
QLineEdit *lineEdit = new QLineEdit();
m_VecLineEdits.push_back(lineEdit); // <-- Line added here to save the pointers in a QVector.
ui->scrollArea_2->widget()->layout()->addWidget(lineEdit);
}
else{
ui->label->setText("already 10");
}
}
void MainWindow::GetAllTextEdit()
{
for(int j = 0; j<m_VecLineEdits.size(); ++j)
{
QString lineEditText = m_VecLineEdits.at(j)->text();
/* Do anything with this value */
}
}
If you delete your QLineEdit, remember to also remove them from the QVector.
If you want to change the name of the variable ( ie the pointer to the QLineEdit ) each time you slot is called, and provided that i will stay small ( < 10 ), you can use switch(i) for example and choose a different variable name for each case, but you will have to store all those variables as members of your class. So it's better to store the pointers in a QList or a QVector and loop over those containers to access the text() method on each QLineEdit.
you can't, because you don't have any pointer or reference to those objects, one solution would be having a array of QLabel in your class definition.
ex:
QVector<QLabel*> _labels;
and adding and instantiating one by one with the press of the button and then you will have the whole list of objects, thus their names