I have done some coding for L00 (name of my first QLineEdit).
I want to do the same for other 99 widgets (up to L99). I don't wanna copy paste it 100 hundred times.
void MainWindow::on_L00_returnPressed(){
QString c = ui->L00->text();
char d = QString(c).at(0).toLatin1();
if(d>=65&&d<=90||d>=97&&d<=122)
{
square[0]=d;
ui->MessageBox->setText("Alphabet succesfully entered");
ui->L00->setReadOnly(true);
ui->L00->setStyleSheet("QLineEdit { background: rgb(0, 255, 255);}");
}
else
{
ui->MessageBox->setText("Enter Alphabets Only");
ui->L00->setText("");
}
}
If you add all these widget through Qt Designer the objects will have the same name of the variable, so we can get them through findChild, then apply connect the signal ReturnPressed to a lambda function and not having to create a slot for each QLineEdit.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
int n = 100;
for(int i=0; i<n; i++){
QString name = QString("L%1").arg(i, 2, 10, QChar('0'));
QLineEdit* w = findChild<QLineEdit *>(name);
connect(w, &QLineEdit::returnPressed, [=](){
QString c = w->text();
char d = QString(c).at(0).toLatin1();
if((d>=65&& d<=90)||(d>=97&&d<=122))
{
square[i]=d;
ui->MessageBox->setText("Alphabet succesfully entered");
w->setReadOnly(true);
w->setStyleSheet("QLineEdit { background: rgb(0, 255, 255);}");
}
else
{
ui->MessageBox->setText("Enter Alphabets Only");
w->clear();
}
});
}
}
Note: I have considered that square[i] corresponds to the QLineEdit L-i.
Another solution is to connect all to the same slot and obtain the object through the function sender().
*.h
private slots:
void onReturnPressed();
*.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(QLineEdit* w: findChildren<QLineEdit *>()){
connect(w, &QLineEdit::returnPressed, this, &MainWindow::onReturnPressed);
}
}
void MainWindow::onReturnPressed()
{
QLineEdit* w =qobject_cast<QLineEdit *>(sender());
int i = w->objectName().remove(0, 1).toInt();
QString c = w->text();
char d = QString(c).at(0).toLatin1();
if((d>=65&& d<=90)||(d>=97&&d<=122))
{
square[i]=d;
ui->MessageBox->setText("Alphabet succesfully entered");
w->setReadOnly(true);
w->setStyleSheet("QLineEdit { background: rgb(0, 255, 255);}");
}
else
{
ui->MessageBox->setText("Enter Alphabets Only");
w->clear();
}
}
For old version:
*.h
private slots:
void onReturnPressed();
.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
int n = 100;
for(int i=0; i<n; i++){
QString name = QString("L%1").arg(i, 2, 10, QChar('0'));
QLineEdit* w = findChild<QLineEdit *>(name);
if(w)
connect(w, SIGNAL(returnPressed()), this, SLOT(onReturnPressed()));
}
}
void MainWindow::onReturnPressed()
{
QLineEdit* w =qobject_cast<QLineEdit *>(sender());
int i = w->objectName().remove(0, 1).toInt();
QString c = w->text();
char d = QString(c).at(0).toLatin1();
if((d>=65&& d<=90)||(d>=97&&d<=122))
{
square[i]=d;
ui->MessageBox->setText("Alphabet succesfully entered");
w->setReadOnly(true);
w->setStyleSheet("QLineEdit { background: rgb(0, 255, 255);}");
}
else
{
ui->MessageBox->setText("Enter Alphabets Only");
w->clear();
}
}
You can use the QObject::findChildren to do so. It must be called from the parent widget (your MainWindow). You can from it connect the QLineEdit individually, or change all values at once.
Example:
for (auto lineEdit : this->findChildren<QLineEdit*>()) {
// connect lineEdit or change values
}
Problem starts with:
I have done some coding for L00 (name of my first QLineEdit) … 99 widgets (up to L99).
This means that you designed your application incorrectly.
I'm almost sure that you should use QTableView or QTableWidget with QAbstractTableModel or QStandartItemModel.
Also setStyleSheet should be applied on QApplication or at least on top level widget. This is how stylesheet is supposed to be used.
Related
I have a vector of labels, declared in the MainWindow class:
QVector<QPointer<QLabel>> labels;
And a function:
void MainWindow::testFunc()
{
for(int i = 0; i < 5; ++i) {
labels.push_back(QPointer<QLabel>(new QLabel(this)));
labels.back()->setGeometry(QRect(50 * i, 0, 50, 50));
labels.back()->setText("test");
}
}
I call this function in the class constuctor and everything is fine:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
testFunc();
}
Then I added a button and a connecting:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::testFunc);
}
And after clicking the labels aren't shown. I checked via debugger and in the both ways the labels are created and constructors for them are executed. Also I tried simple pointers, QTimer::singleShot() and QPointer<QLabel> without QVector - the result is the same.
Why the second way does't work? Why I can add a QLabel only in the constuctor?
QMainWindow alwayd should have a centralWidget that contains other chilrens. when using forms, centralWidget is automaticly created. you may manage labels in a horizontal layout and then add them to the centralWidget:
QPointer<QHBoxLayout> hBoxLayout (new QHBoxLayout);
for(int i = 0; i < 5; ++i) {
labels.push_back(QPointer<QLabel>(new QLabel));
labels.back()->setGeometry(QRect(50 * i, 0, 50, 50));
labels.back()->setText("test");
hBoxLayout->addWidget(labels.back().data());
}
ui->centralwidget->setLayout(hBoxLayout);
I want to pass three strings (cellTitle,cellPoem,cellGroup) from mainwindows to another dialog. I know when i initiate the second form the values become zeros. I read somewhere it's possible with slots but i don't know how.
mainwindows.h
public:
QString cellTitle,cellPoem,cellGroup;
mainwindows.cpp
void MainWindow::on_tableView_pressed(const QModelIndex &index)
{
cellText = ui->tableView->model()->data(index).toString();
QSqlQuery * qry2 = new QSqlQuery(mydb);
qry2->prepare("select * from Poems where Title='"+cellText+"'");
qry2->exec();
while(qry2->next()){
cellTitle = qry2->value(1).toString();
cellPoem = qry2->value(2).toString();
cellGroup = qry2->value(3).toString();
ui->textEdit->setText(qry2->value(2).toString());
}
}
void MainWindow::on_btnUpdate_clicked()
{
frmUpdate frmupdate;
frmupdate.setModal(true);
frmupdate.exec();
}
frmupdate.cpp
#include "frmupdate.h"
#include "ui_frmupdate.h"
#include <mainwindow.h>
frmUpdate::frmUpdate(QWidget *parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow mainwindow;
ui->lineEdit->setText(mainwindow.cellTitle);
ui->lineEdit_2->setText(mainwindow.cellGroup);
ui->textEdit->setText(mainwindow.cellPoem);
}
frmUpdate::~frmUpdate()
{
delete ui;
}
void frmUpdate::on_btnUpdate_clicked()
{
}
void frmUpdate::on_pushButton_2_clicked()
{
this->close();
}
frmUpdate::frmUpdate(QWidget *parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow mainwindow;
You here have created a new, temporary MainWindow instance only with default constructor being called. Of course, this new instance is then created with empty default texts:
ui->lineEdit->setText(mainwindow.cellTitle);
ui->lineEdit_2->setText(mainwindow.cellGroup);
ui->textEdit->setText(mainwindow.cellPoem);
}
Easiest now would be passing the original main window as parameter:
frmUpdate::frmUpdate(QWidget* parent, MainWindow* mainWindow) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
}
If the parent is the main window, you can simply cast:
frmUpdate::frmUpdate(QWidget* parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow* mainWindow = qobject_cast<MainWindow*>(parent);
if(mainWindow)
{
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
}
else
{
// appropriate error handling
}
}
You might search the main window from parent as well:
for(;;)
{
MainWindow* mainWindow = qobject_cast<MainWindow*>(parent);
if(mainWindow)
{
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
break;
}
parent = parent->parent();
if(!parent)
{
// appropriate error handling
break;
}
}
All above assuming that MainWindow inherits from QObject...
I am making a login form in qt where input is taken from the numpad. The numpad is created on screen. When I am trying to take input from the numpad,
It takes the input in the both of the lineEdit field. So how can I separate both of these while taking the input from the numpad?
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mainscreen.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->dB1,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB2,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB3,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB4,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB5,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB6,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB7,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB8,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB9,SIGNAL(released()),this,SLOT(display()));
connect(ui->dB0,SIGNAL(released()),this,SLOT(display()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::display()
{
QPushButton *qp=(QPushButton*)sender();
ui->lineEdit->setText(ui->lineEdit->text()+qp->text());
ui->lineEdit_2->setText(ui->lineEdit_2->text()+qp->text());
}
void MainWindow::on_pushButton_clicked()
{
QString username=ui->lineEdit->text();
QString password=ui->lineEdit_2->text();
if(username=="text"&&password=="text")
{
hide();
main_scn=new MainScreen();
main_scn->setWindowFlags(Qt::Window|Qt::FramelessWindowHint);
main_scn->show();
}
}
the UI is here, please check this out
Creating a numpad in that way is inconvenient since it will place the text in both QLineEdit, and usually the username and password are not always the same.
My proposal is to create a Numpad that does not need to be connected by signals, but an event will be sent so that the widget that has the focus.
numpadwidget.h
#ifndef NUMPADWIDGET_H
#define NUMPADWIDGET_H
#include <QApplication>
#include <QGridLayout>
#include <QKeyEvent>
#include <QToolButton>
#include <QWidget>
class NumpadWidget : public QWidget
{
Q_OBJECT
public:
explicit NumpadWidget(QWidget *parent = nullptr) : QWidget(parent)
{
QGridLayout *lay = new QGridLayout(this);
const std::vector<QPair<QString, int>> values{{"1", Qt::Key_1}, {"2", Qt::Key_2}, {"3", Qt::Key_3},
{"4", Qt::Key_4}, {"5", Qt::Key_5}, {"6", Qt::Key_6},
{"7", Qt::Key_7}, {"8", Qt::Key_8}, {"9", Qt::Key_9},
{".", Qt::Key_Colon}, {"0", Qt::Key_0}, {"*", Qt::Key_Asterisk}};
int i = 0;
int j = 0;
for(const QPair<QString, int> & value : values){
QToolButton *button =new QToolButton;
button->setText(value.first);
button->setFixedSize(40,40);
lay->addWidget(button, i, j);
button->setProperty("text", value.first);
button->setProperty("key", value.second);
connect(button, &QToolButton::clicked, this, &NumpadWidget::onClicked);
j++;
if(j % 3 == 0){
j=0;
i++;
}
}
setFixedSize(sizeHint());
}
private slots:
void onClicked()
{
if(QWidget *widget = QApplication::focusWidget()){
QString text = sender()->property("text").toString();
int key = sender()->property("key").toInt();
QKeyEvent * event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, text);
QCoreApplication::postEvent(widget, event);
}
}
};
#endif // NUMPADWIDGET_H
Then the NumpadWidget is promoted so that it can be used in Qt Designer, in the following link it indicates how to do it
The complete project can be found in the following link.
I am trying to learn and build a small minesweeper gui app.Here is how this looks like:
The next thing I want to do is after clicking one button, then the button will be set to hide() and a QLabel will appear in the same place.
My code is like this:
.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setUI();
void clickedBtnInfo();
private:
Ui::MainWindow *ui;
QWidget *centralWidget;
QGridLayout *centralLayout;
QPushButton *btn[81];
QPushButton *btnSender;
QLabel *lbl[81];
QString clickedBtnName;
private slots:
void btnClicked();
};
.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
lbl[81] = new QLabel(centralWidget);
setUI();
for(int i = 0; i < 81; i++) {
connect(btn[i], SIGNAL(clicked(bool)), btn[i], SLOT(hide()));
connect(btn[i], SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
}
centralWidget->setLayout(centralLayout);
}
void MainWindow::setUI()
{
...
centralLayout = new QGridLayout(centralWidget);
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
centralLayout->addWidget(btn[j + i * 9], 0 + i, j);
centralLayout->setSpacing(0);
}
}
...
}
void MainWindow::clickedBtnInfo()
{
btnSender = qobject_cast<QPushButton*>(sender());
clickedBtnName = btnSender->objectName();
}
void MainWindow::btnClicked()
{
clickedBtnInfo();
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(btn[j + i * 9]->objectName() == clickedBtnName) {
centralLayout->addWidget(lbl[j + i * 9], 0 + i, j);
centralLayout->setSpacing(0);
}
}
}
}
When I ran this and clicked one of the buttons, the app just force quit(The program has unexpectedly finished.)
So how can I solve this problem and replace QPushButton with QLabel after clicking? Thanks.
The Problem why your code leads to a crash was correctly pointed out by #G.M. - lbl[81] = new QLabel(centralWidget); will create only 1 label, and place it in the 81st array field. That are 2 errors at once:
If your array is 81 elements long, they are numbered: 0, 1, ..., 79, 80. The last element is 80, because you start counting at 0. So placing something at position 81 is not possible
To actually create 81 new labels, you have to create them in a loop:
Sample code:
for(int i = 0; i < 81; i++) { //goes from 0 to 80
lbl[i] = new QLabel(centralWidget);
lbl[i]->setObjectName(QStringLiteral("Label %1").arg(i));
}
The second line gives each label a custom name. See QString::arg for details.
One more tip: Avoid C-arrays, unless you need high performace/low memory (which is not the case for your example). Instead try to use one of the Qt container classes, e.g. QList or QVector. (You can use std::vector etc. as well, but when working with Qt, I would recommend to use the Qt containers)
For your case, I would recommend QVector, as it performs best with fixed-sized arrays. With both of these changes, update your code to:
class MainWindow : public QMainWindow
{
//...
private:
Ui::MainWindow *ui;
QWidget *centralWidget;
QGridLayout *centralLayout;
QVector<QPushButton> btn;
QPushButton *btnSender;
QVector<QLabel> lbl;
QString clickedBtnName;
};
In your cpp file, update the part where you create the arrays:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
lbl.resize(81);
for(int i = 0; i < lbl.size(); i++) { //goes from 0 to 80
lbl[i] = new QLabel(centralWidget);
lbl[i]->setObjectName(QStringLiteral("Label %1").arg(i));
}
setUI();
//...
}
void MainWindow::setUI()
{
//keep your code, but remember to prepare the btn vector with:
btn.resize(81);
//then you can fill the vector just like you are used to:
btn[0] = ui->btn0;
//...
}
And the rest stays the same, as these classes allow you to keep the standard array access syntax you know.
Each time the "Add Client" button is pressed - a minus button, the name of the client, a counter for the client and a plus button are added in a horizontal line to the gridLayout. I want to update the count (QLabel) when the plus/minus button is pressed.
Here is my code:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QGridLayout>
#include <QLabel>
int row = 0;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QPushButton* minus_button = new QPushButton();
QPushButton* plus_button = new QPushButton();
minus_button->setText("-");
plus_button->setText("+");
QLabel* client_name = new QLabel(ui->lineEdit->text(), this);
QLabel* client_count = new QLabel("", this);
ui->gridLayout->addWidget(minus_button, row, 1, Qt::AlignTop|Qt::AlignHCenter);
ui->gridLayout->addWidget(client_name, row, 2, Qt::AlignTop|Qt::AlignHCenter);
ui->gridLayout->addWidget(client_count, row, 3, Qt::AlignTop|Qt::AlignHCenter);
ui->gridLayout->addWidget(plus_button, row++, 4, Qt::AlignTop|Qt::AlignHCenter);
connect(minus_button, SIGNAL(clicked(bool)), this, SLOT(minusCount()));
connect(plus_button, SIGNAL(clicked(bool)), this, SLOT(plusCount()));
}
void Widget::minusCount(){
//Here I want to somehow reference the client_count label which is in the same row
}
void Widget::plusCount(){
//Here I want to somehow reference the client_count label which is in the same row
}
EDIT: After Kevin's comment, here is the working code for anyone who may need it.
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QGridLayout>
#include <QLabel>
#include <QSignalMapper>
QSignalMapper* m_minusMapper;
QSignalMapper* m_plusMapper;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
m_minusMapper = new QSignalMapper(this);
connect(m_minusMapper, SIGNAL(mapped(QWidget*)), this, SLOT(minusCount(QWidget*)));
m_plusMapper = new QSignalMapper(this);
connect(m_plusMapper, SIGNAL(mapped(QWidget*)), this, SLOT(plusCount(QWidget*)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QPushButton* minus_button = new QPushButton();
minus_button->setObjectName("minus" + QString::number(row));
minus_button->setText("-");
QPushButton* plus_button = new QPushButton();
plus_button->setObjectName("plus" + QString::number(row));
plus_button->setText("+");
QLabel* client_name = new QLabel(ui->lineEdit->text(), this);
QLabel* client_count = new QLabel("0", this);
ui->gridLayout->addWidget(minus_button, row, 1, Qt::AlignVCenter|Qt::AlignHCenter);
ui->gridLayout->addWidget(client_name, row, 2, Qt::AlignVCenter|Qt::AlignHCenter);
ui->gridLayout->addWidget(client_count, row, 3, Qt::AlignVCenter|Qt::AlignHCenter);
ui->gridLayout->addWidget(plus_button, row++, 4, Qt::AlignVCenter|Qt::AlignHCenter);
connect(minus_button, SIGNAL(clicked()), m_minusMapper, SLOT(map()));
connect(plus_button, SIGNAL(clicked()), m_plusMapper, SLOT(map()));
m_minusMapper->setMapping(minus_button, client_count);
m_plusMapper->setMapping(plus_button, client_count);
}
void Widget::minusCount(QWidget *widget)
{
QLabel *client_count = qobject_cast<QLabel*>(widget);
QString initCount = client_count->text();
int newCount = initCount.toInt() - 1;
client_count->setText(QString::number(newCount));
}
void Widget::plusCount(QWidget *widget)
{
QLabel *client_count = qobject_cast<QLabel*>(widget);
QString initCount = client_count->text();
int newCount = initCount.toInt() + 1;
client_count->setText(QString::number(newCount));
}
Kevin's answer in principle is fine, but since we've got 2016 now and MSVC2010, gcc 4.7, and Clang 3.1 (and possibly earlier versions) support lambdas/C++11, I'd like to add a version without QSignalMapper:
static void minusCount(QLabel *label)
{
QString initCount = label->text();
int newCount = initCount.toInt() - 1;
label->setText(QString::number(newCount));
}
static void plusCount(QLabel *label)
{
QString initCount = label->text();
int newCount = initCount.toInt() + 1;
label->setText(QString::number(newCount));
}
void Widget::on_pushButton_clicked()
{
// ... add the labels and buttons, then:
connect(minus_button, &QPushButton::clicked,
client_count, [client_count]() { minusCount(client_count); });
connect(plus_button, &QPushButton::clicked,
client_count, [client_count]() { plusCount(client_count); });
}
Here the client_count label that the button click should change is captured in the lambda, and directly passed to the function handling it.
The minusCount and plusCount also can be static functions then, since they only operate on the label that is passed as an argument, so they are independent from any Widget instance.
The easiest way is to use a QSignalMapper
// in the constructor of your class
m_minusSignalMapper = new QSignalMapper(this);
connect(m_minusSignalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(minusCount(QWidget*)));
m_plusSignalMapper = new QSignalMapper(this);
connect(m_plusSignalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(plusCount(QWidget*)));
// in your button slot you connect to the respective mapper instead
connect(minus_button, SIGNAL(clicked()), m_minusMapper, SLOT(map()));
connect(plus_button, SIGNAL(clicked()), m_plusMapper, SLOT(map()));
// and you set up the mapping
m_minusMapper->setMapping(minus_button, client_count);
m_plusMapper->setMapping(plus_button, client_count);
// in the the two receiver slots, the argument is the label
void Widget::minusCount(QWidget *widget)
{
QLabel *client_count = qobject_cast<QLabel*>(widget);
}