I am trying to use a QAction to turn a specific column of a QTableView into from the current format xxx:xxx into another format (xxx,xxx) and reverse.
I prepared a small minimal application that carries exactly the problem I have. The application is formed by:
1) A Main window that carries a QTableView with:
Id | name | age | salary | coordinate
Also the printscreen of the GUI is showed here for completeness:
Additionally the print screen of what I am trying t achieve is also shown below, notice that as soon as I click on the "coordinate" column it lights up and with right click I try to change the format from xxx:xxx to (xxx,xxx) but is not working:
I am trying to change the last column "coordinate" from format xxx:xxx into format (xxx,xxx) and reverse. As you click on any cell of the last column the entire column "coordinate" will be selectable.
What I tried so far:
I tried to change the format by following this source, which was useful but didn't totally address the problem.
Additionally I have implemented part of this solution that was trying to force decimal numbers into cells. However in my case I don't have a QStyledItemDelegate
but just a QAction
.
Also this was the closest help I could find. This example proposes a QStyledItemDelegate
too but it is not what I am trying to achieve.
Also I wrote a QPoint Widget::parseCoordStringForTheTable(QString input)
that accepts particular formats but I am not sure how to handle this exception.
This is a complete MCVE so it needs to solely be copied and paste and it should work right away:
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQueryModel>
namespace Ui {
class Widget;
}
class QSqlQueryModel;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_add_clicked();
void on_close_clicked();
void on_modify_clicked();
void currentColumnChanged(const QModelIndex &mi);
void autoSelectMagicColumn();
private:
Ui::Widget *ui;
QSqlDatabase mDatabase;
QSqlQueryModel *mModel;
QAction *mTurnIntoExcelData;
QPoint parseCoordStringForTheTable(QString input);
const int magicColumnIndex = 4;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QtSql/QSqlQueryModel>
#include <QSqlError>
#include <QSqlQuery>
#include <QMessageBox>
#include <QInputDialog>
#include <QTimer>
#include <QAction>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
mTurnIntoExcelData = new QAction(QIcon(":"), tr("Turn into Excel format"), this);
ui->tableView->setContextMenuPolicy(Qt::ActionsContextMenu);
ui->tableView->addActions({mTurnIntoExcelData});
connect(mTurnIntoExcelData, &QAction::triggered, [&]() {
int row = -1, column = -1;
QString reference;
QString type;
QModelIndex index;
QPoint data;
for(int i = 0; i < ui->tableView->model()->columnCount(); i++)
{
if(ui->tableView->model()->headerData(i, Qt::Horizontal).toString() == "coordinate") {
column = i;
type = "coordinate";
data.setX(parseCoordStringForTheTable(index.sibling(row,4).data().toString()).x());
data.setY(parseCoordStringForTheTable(index.sibling(row,4).data().toString()).y());
//mModel->submitAll();
ui->tableView->show();
}
}
QModelIndexList selection = ui->tableView->selectionModel()->selectedColumns();
if (selection.count() > 0) {
QModelIndex index = selection.at(0);
row = index.row();
}
if(row < 0 || column < 0)
{
QMessageBox::warning(this, "Warning", "DoubleCheck - Didnt work");
}
else {
reference = ui->tableView->model()->data(ui->tableView->model()->index(row,column)).toString();
if(reference == "No Coordinates Present")
return;
}
});
mDatabase = QSqlDatabase::addDatabase("QSQLITE");
mDatabase.setDatabaseName("/path/to/Desktop/tmp/StackOverflow.db");
if(!mDatabase.open()) {
QMessageBox::critical(this, "Error", mDatabase.lastError().text());
return;
}
QSqlQuery qry;
if (!qry.exec("CREATE TABLE IF NOT EXISTS persona " \
"(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," \
"name TEXT NOT NULL," \
"age INTEGER NOT NULL," \
"salary DOUBLE NOT NULL, "
"coordinate TEXT NOT NULL)")) {
QMessageBox::critical(this, "Error", qry.lastError().text());
return;
}
mModel = new QSqlQueryModel(this);
mModel->setQuery("SELECT * FROM persona");
ui->tableView->setModel(mModel);
connect(ui->tableView->selectionModel(), SIGNAL(currentColumnChanged(const QModelIndex &, const QModelIndex &)),
this, SLOT(currentColumnChanged(const QModelIndex &)));
}
Widget::~Widget()
{delete ui;}
void Widget::on_add_clicked()
{
QSqlQuery qry;
if (!qry.exec(QString("INSERT INTO persona (name,age,salary,coordinate)"\
"VALUES ('%1',%2,%3,%4)").
arg(ui->name->text()).
arg(ui->age->value()).
arg(ui->salary->value()).
arg(ui->coordinate->text()))) {
QMessageBox::critical(this, "Error", qry.lastError().text());
return;
}
mModel->setQuery("SELECT * FROM persona");
ui->tableView->setModel(mModel);
}
void Widget::on_close_clicked()
{close();}
void Widget::on_modify_clicked()
{
auto uploadInt = [&](QWidget *parent, const QString &title, const QString &msg, int valor) {
bool ok;
int res = QInputDialog::getInt(parent, title, msg, valor,
-2147483647, 2147483647, 1, &ok);
if(ok) { return res; }
return valor;
};
auto uploadName = [&](QWidget *parent, const QString &name) {
bool ok;
auto res = QInputDialog::getText(parent, "Name", "Name Input",
QLineEdit::Normal, name, &ok);
if(ok) { return res; }
return name;
};
auto uploadSalary = [&](QWidget *parent, double salary) {
bool ok;
double res = QInputDialog::getDouble(parent, "Salary", "Salary Input", salary,
-2147483647, 2147483647, 3, &ok);
if(ok) { return res; }
return salary;
};
auto uploadCoord = [&](QWidget *parent, int coord) {
bool ok;
int res = QInputDialog::getInt(parent, "Coordinate", "Input Coordinate", coord,
-2147483647, 2147483647, 1, &ok);
if(ok) { return res; }
return coord;
};
int col = ui->tableView->currentIndex().column();
int row = ui->tableView->currentIndex().row();
QString sql;
if(col == 0) {
int id = mModel->index(row, col).data().toInt();
sql = QString("UPDATE persona SET id = %1 WHERE id = %2").
arg(uploadInt(this, "Id", "Id Input", id)).arg(id);
} else if (col == 1) {
auto name = mModel->index(row, col).data().toString();
sql = QString("UPDATE persona SET name = '%1' WHERE name LIKE '%2'").
arg(uploadName(this, name)).arg(name);
} else if (col == 2) {
int age = mModel->index(row, col).data().toInt();
sql = QString("UPDATE persona SET age = %1 WHERE age = %2").
arg(uploadInt(this, "Age", "Age Input", age)).arg(age);
} else if (col == 3) {
double salary = mModel->index(row, col).data().toDouble();
sql = QString("UPDATE persona SET salary = %1 WHERE salary = %2").
arg(uploadSalary(this, salary)).arg(salary);
} else if (col == 4) {
int coordinate = mModel->index(row, col).data().toInt();
sql = QString("UPDATE persona SET coordinate = %1 WHERE salary = %2").
arg(uploadCoord(this, coordinate)).arg(coordinate);
}
QSqlQuery qry;
qry.exec(sql);
mModel->setQuery("SELECT * FROM persona");
}
void Widget::currentColumnChanged(const QModelIndex &mi) {
const int col = mi.column();
if (col == magicColumnIndex) {
QTimer::singleShot(100, this, SLOT(autoSelectMagicColumn()));
}
}
void Widget::autoSelectMagicColumn()
{
if (ui->tableView->selectionModel()->currentIndex().column() == magicColumnIndex) {
ui->tableView->selectColumn(magicColumnIndex);
}
}
QPoint Widget::parseCoordStringForTheTable(QString input)
{
QPoint output;
if(input.contains('(')) {
output.setX(input.remove('(').remove(')').remove(',').split(" ")[0].toInt());
output.setY(input.remove('(').remove(')').remove(',').split(" ")[1].toInt());
} else {
output.setX(input.split(":")[0].toInt());
output.setY(input.split(":")[1].toInt());
}
return output;
}
Expected Result: change format of one specific column passing from current format xxx:xxx into format (xxx,xxx) and reverse as soon as I clic k on the "coordinate" column
Actual: Not working because nothing happens.
So to recap quickly: the image shown below is what I am trying to achieve, the last column will become entirely selectable as soon as the user clicks in any cell of that specific column, and with the right click I am attempting to change the entire format of the column from xxx:xxx, to (xxx,xxx):
Any possible insights will be useful, thanks.