Get clicked item from QListWidget and QTableWidget - c++

I need to read an item from both QTableWidged and Q ListWidget as the user clicks on them.
For QListWidget I tried the solution described here, however the used SIGNAL itemClicked never seems to trigger.
For QTableWidget I tried multiple solutions, however they either didn't work or weren't what I need. Is there a simple solution for QTableWidget and am I just overlooking something with the solution provided for QListWidget?
Edit:
My Constructor of my MainWindow.cpp looks like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->TableWidget->verticalHeader()->setVisible(true);
QTableWidget* table = ui->TableWidget;
connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(showBuchungsDetails(parseListWidgetBuchung(QListWidgetItem*))));
QHeaderView *header = qobject_cast<QTableView *>(table)->horizontalHeader();
connect(header, &QHeaderView::sectionClicked, [this](int logicalIndex){
QString text = ui->TableWidget->horizontalHeaderItem(logicalIndex)->text();
ui->lnBuchungsnummer->setText(text);
});
}
And here is my header file for MainWindow:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
#include <QFileDialog>
#include <QListWidget>
#include "TravelAgency.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actionDatei_einlesen_triggered();
void on_actionProgramm_beenden_triggered();
void on_actionBuchungen_anzeigen_triggered();
Customer* parseListWidgetBuchung(QListWidgetItem* item);
Customer* parseTableWidgetBuchung(QString item);
void showBuchungsDetails(Customer* c);
private:
Ui::MainWindow *ui;
TravelAgency travelagency{};
bool inputReady = false;
QStringList m_TableHeader;
};
#endif // MAINWINDOW_H
Edit 2:
I am using Qt Creator 4.8.2

Do not use the SLOT/SIGNAL syntax for C++ signals and slots. This is error prone, since mistakes like this are not caught during compilation. Your code compiles fine but doesn't work.
Use Qt5 connect syntax. In this case, you can use a lambda:
connect(ui->listWidget, &QListWidget::itemClicked, this, [this](QListWidgetItem* item)
{
showBuchungsDetails(parseListWidgetBuchung(item));
});

The connect call is wrong. If you use the SIGNAL - SLOT syntax, the slot must be a single function (it's a "reference" to the function).
You can do something like this:
connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(onItemClicked(QListWidgetItem*)));
And the onItemClicked implementation:
void MainWindow::onItemClicked(QListWidgetItem* item)
{
showBuchungsDetails(parseListWidgetBuchung(item));
}

Thanks for the suggestions, but I managed to sidestep the ´connect´ syntax completely by rightclicking on the widgeds in question on my UI window and use the "Go to slot..." functionality to create
void MainWindow::on_listWidget_itemClicked(QListWidgetItem *item)
{
parseListWidgetBuchung(item);
}
void MainWindow::on_TableWidget_cellClicked(int row, int column)
{
parseTableWidgetBuchung(ui->TableWidget->item(row, 0)->text());
}
which then allowed me to get the respective items. Either way, thanks again for the help!

Related

QPushButton signal

I'm trying to get a QPushButton's action method running doing the following.
My login.h:
//
// Created by simon on 28.04.22.
//
#ifndef RESTCLIENT_LOGIN_H
#define RESTCLIENT_LOGIN_H
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
QT_BEGIN_NAMESPACE
namespace Ui { class Login; }
QT_END_NAMESPACE
class Login : public QWidget {
Q_OBJECT
QPushButton * loginButton;
QLineEdit * passwordInput;
QLineEdit * usernameInput;
QObject::connect(loginButton, &QPushButton::click, this, &buttonPressed);
public slots:
void buttonPressed();
public:
explicit Login(QWidget *parent = nullptr);
~Login() override;
private:
Ui::Login *ui;
};
#endif //RESTCLIENT_LOGIN_H
The corresponding login.cpp:
#include "login.h"
#include "ui_Login.h"
Login::Login(QWidget *parent) :
QWidget(parent), ui(new Ui::Login) {
ui->setupUi(this);
}
Login::~Login() {
delete ui;
}
void Login::buttonPressed() {
//todo process login
}
The build fails, and Clion marks the code line containing the connect method in red. I'm aware that my attempt to connect the signal to my function is wrong, I hope someone can help me.
The issue is that QPushButton::click() is not a signal, it is a function that performs a click.
The signal emitted when clicking the button is: QPushButton::clicked().
And as already mentioned, you should call the QObject::connect() function from inside a function (in the constructor for example). It makes no sense to call it in the class declaration.
The connect call looks mostly fine, except that click is not a signal as Fareanor first noticed in his answer; use the clicked signal from QPushButton's base class QAbstractButton instead. See also QAbstractButton Signals for all available signals.
Additionally, connect needs to be inside of a function, not in the class declaration. The button needs to be initialized for the connection to work, so the constructor of your Login class seems like a logical place for it, for example:
Login::Login(QWidget *parent) :
QWidget(parent), ui(new Ui::Login) {
ui->setupUi(this);
QObject::connect(loginButton, &QPushButton::clicked, this, &buttonPressed);
}
From the code you're showing it seems that loginButton is separate from the other GUI stuff in ui, so you probably also need to create that button first, i.e., adding , loginButton(new QPushButton) after ui(...), or move the loginButton to your .ui file...

Adding many data in QListView without "not responding"

for a project I need to integrate a lot of data in a QListView, I get the data from a QThread and store it in a QMap<QString, QString>, until then I have no problem of crash or freeze. But when in my QThread I browse my QMap to call for each element the function that will add the QString in the QListView, then I have a freeze. I searched a lot but I didn't find or understand how to do it. I add you a part of the simplified code to show you my problem :
exemple.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QListView>
#include <QStandardItemModel>
#include <QDebug>
#include <QThread>
#include "mythread.h"
class exemple : public QMainWindow
{
Q_OBJECT
public:
explicit exemple(QWidget *parent = nullptr);
private:
QPushButton *btn_start;
QListView *lv_file;
QMap<QString, QString> myMap;
MyThread *m_thread;
QStandardItemModel *model;
public slots:
void addFileInformation(QString, QString);
void startShow();
private slots:
void startThread();
};
#endif // MAINWINDOW_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QDebug>
#include <QDirIterator>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent);
void run();
signals:
void addFileInformation(QString, QString);
void startShow();
};
#endif // MYTHREAD_H
exemple.cpp
#include "exemple.h"
exemple::exemple(QWidget *parent) : QMainWindow(parent)
{
setFixedSize(750,750);
btn_start = new QPushButton("start", this);
btn_start->setGeometry(50, 40, 150, 30);
btn_start->setCursor(Qt::PointingHandCursor);
lv_file = new QListView(this);
lv_file->setGeometry(50, 100, 600, 500);
m_thread = new MyThread(this);
model = new QStandardItemModel(this);
lv_file->setModel(model);
connect(btn_start, SIGNAL(clicked()), this, SLOT(startThread()));
connect(m_thread, SIGNAL(addFileInformation(QString, QString)),this, SLOT(addFileInformation(QString, QString)));
connect(m_thread, SIGNAL(startShow()),this, SLOT(startShow()));
}
void exemple::startThread(){
m_thread->start();
}
void exemple::addFileInformation(QString param1, QString param2)
{
myMap.insert(param1, param2);
}
void exemple::startShow(){
for (int i = 0; i < myMap.size(); i++){
model->appendRow(new QStandardItem(myMap.keys()[i]));
}
}
In this example it would be when the thread calls the startShow slot that my freeze appears.
I understand that I'm not in the thread anymore and that's the reason of the freeze but I have the same problem if instead of adding information to a QMap on "exemple" as I do here, the addFileInformation slot of example.cpp displayed directly the information. Like this:
exemple.cpp
void exemple::addFileInformation(QString param1, QString param2)
{
model->appendRow(new QStandardItem(param1));
}
If you have a solution, a track or a link to do this without freezing I'm interested :)
If I'm not clear don't hesitate to ask me to explain it again, thanks to those who will take their time to help me.
If your dataset is large, you probably need to implement your own model that uses the data in the fashion you're storing it. Models in Qt are tricky, but once you've done a few they begin to make sense.
I've got an example on my github: https://github.com/jplflyer/qt-TreeViewDemo. It's probably not perfect. I wrote it while trying to figure out how to write it. This is for QTreeView, but QListView won't be that different.
I also have a generic version here: https://github.com/jplflyer/Git-Dashboard. Look down into the tree for GenericItemModel. It's a template and is kind of cool, actually. It also may not be fully featured, but it might help.
You can try to unset model from view lv_file->setModel(nullptr); to get rid of unnecessary view refreshes (after each row insert), change model and set it back to view.
You must use a signal to send your mapdata to the ui thread and append a row in your thread, not just append a row directly in your thread.
i have review u code carefully,and maybe u should try this way:
void exemple::startShow()
{
QList<QStandardItem*> itemList;
for (int i = 0; i < myMap.size(); i++)
{ itemList<<(new QStandardItem(myMap.keys()[i]));
}
model->appendRow(itemList);
}

Can't bind signal to slot in my Qt application

I'm new to Qt and I have a very simple demo app. It just include a QLineEdit widget and I want to invoke a function test() when I press ctrl+p in the QLineEdit.
Below are the related files.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QShortcut>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QShortcut *s = new QShortcut(QKeySequence("Ctrl+P"), ui->lineEdit);
connect(s, SIGNAL(activated()), ui->lineEdit, SLOT(test()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void test(){
qDebug() << "test() triggered!" << endl;
}
mainwindow.h
#ifndef 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();
void test();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
When I compile the application, I saw below messages in the debug panel and the application didn't respond to ctrl+p.
QObject::connect: No such slot QLineEdit::test() in ..\ShortcutIssueDemo\mainwindow.cpp:13
QObject::connect: (receiver name: 'lineEdit')
What's the problem with it?
You have 2 misconceptions:
The connection indicates the link between the object that emits the signal, the signal, the object to which the slot belongs and the slot. In your case it is obvious that the object to which the slot "slot" belongs is this.
If the old syntax (SIGNAL & SLOT) is to be used then "test" must be declared as slot.
So for the above there are 2 possible solutions:
Change to :
connect(s, SIGNAL(activated()), this, SLOT(test()));
public slots:
void test();
Or use new syntax:
connect(s, &QShortcut::activated, this, &MainWindow::test);
Between both solutions, the second one is better since it will indicate errors in compile-time instead of silent errors in run-time.
By default, the context of the shortcut is Qt::WindowShortcut, that is, it will fire when the key combination is pressed and the window has focus, if only when QLineEdit has focus then you have to change the context to Qt::WidgetShortcut:
s->setContext(Qt::WidgetShortcut);
You have received the error message saying there is no such slot...
Note that u haven't marked test() as slot, hence in <mainwindow.h>, replace
void test();
by
public slots: void test();
And the slot test() belongs to the mainwindow not to s, hence use this instead of s

How to know child Window is destroyed form parent Window

I have a parent-child window in my Qt application. Parent class is a QDialog named A and child class is QMainWindow named B. Now I want that whenever B is closed through the 'X' button a signal is to be emitted which can be caught by a slot in class A through which I want certain functionality to be implemented. Is there a predefined signal in Qt I can use?
I want something like this:
B *b=new B;
//some code
connect(b,SIGNAL(destroyed()),this,&A::doSomething);
B also has a QWidget which I can use to detect the destroyed signal. How do I implement this? Do I need to emit a custom signal from ~B() ?
Edit: I don't want to destroy the object b as this would require a reallocation when I want to recreate the window B from A and I want to keep the parameters of b.
Your solution would only work if you set a Qt::WA_DeleteOnClose attribute to your B widget:
b->setAttribute(Qt::WA_DeleteOnClose);
Another option would be to reimplement close event and emit a custom signal there.
Connect your object like this:
widget = new QWidget();
//widget->show(); //optional using
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButtonNew_clicked()
{
widget = new QWidget();
widget->show();
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::on_pushButtonDel_clicked()
{
delete widget;
}
void MainWindow::widgetDestroy()
{
qDebug()<< "deleted."; //after destroy widget this function calling.
}
.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void widgetDestroy();
void on_pushButtonNew_clicked();
void on_pushButtonDel_clicked();
private:
Ui::MainWindow *ui;
QWidget *widget;
};
#endif // MAINWINDOW_H
.ui :

QErrorMessage keeps on appearing

I count some entries and want to emit a message, when the user has many entries, since it will be confusing.
Nevertheless the other hand the user should have the option to disable this warning.
That's why I wanted to use a QErrorMessage.
But my QErrorMessage kept on appearing even when it should not (/when the checkbox is unchecked).
This is the shortest code I wrote:
void checkNumber(int const &n)
{
if(n > CriticalNumber)
{
QErrorMessage msg(this);
msg.showMessage("too much!");
}
}
Did I forget anything?
The funny thing is, after you once unchecked the checkbox, it is unchecked in every next call...
// edit:
This error happens even when the QErrorMessage is a member of my class and not initialised in every call.
// edit2:
By now I am pretty sure, that this error only occurs, when I use QString::arg. I did not use this in the example code, since I thought this would make no difference. So the example should look like this:
void showError(int const &n, QErrorMessage *msg)
{
msg->showMessage(tr("%1 is too big").arg(n));
}
showError() is called in the previous if-statement.
I solved this problem (specified in edit2).
The problem is, that the QErrorMessage saves all the QStringsthat should not be shown again.
Since my arg() creates nearly every time a new QStringthe QErrorMessageis shown each time it is changed.
Example:
QErrorMessage msg(this);
showError(1, msg);
showError(2, msg);
showError(1, msg);
The first showError(1, msg) will show the QErrorMessage.
If you uncheck the checkbox, showError(2, msg) will be shown (because a different QString is shown), but not showError(1, msg) (since the shown QString is the same as the first one.
I cannot reproduce your problem. What you should to is make checkNumber a member of a class, and do the same for your msg object.
Here is a working example:
mainwinodw.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QErrorMessage>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void showErrorMsg();
private:
Ui::MainWindow *ui;
QErrorMessage msg;
QTimer timer;
};
#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);
connect(&timer, SIGNAL(timeout()), this, SLOT(showErrorMsg()));
timer.start(3000); // we use a timer to show an error message
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showErrorMsg()
{
msg.showMessage("My message");
}