I have written some code, where if I log in as a customer it should hide column customer (value of that column is 1). I need to pass parameter to the signals. I have used my customerLogin is isSa. How to pass these parameters to signals and slots?
Main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
initialize();
SafeOTPWindow w;
Login login;
login.connect(&login, SIGNAL(loggedIn()), &w, SLOT(show()) );
login.connect(&login, SIGNAL(loginCancelled() ), &w, SLOT(close()) );
login.show();
a.exec();
}
Login.h:
#ifndef LOGIN_H
#define LOGIN_H
#include <QDialog>
namespace Ui {
class Login;
}
class Login : public QDialog
{
Q_OBJECT
public:
explicit Login(QWidget *parent = 0);
~Login();
bool isSa;
signals:
void loggedIn();
void loginCancelled();
private slots:
void on_buttonBox_accepted();
void on_buttonBox_rejected();
private:
Ui::Login *ui;
};
#endif // LOGIN_H
And here is my another file where I need to hide the column (Customer), OtpWindow.cpp:
void SafeOTPWindow::initLogTable()
{
QList<OtpLog> logs;
int ret = otpRepo.fetchOtpLogs(logs);
if( ret != errorCodes::SUCCESS )
{
QMessageBox msgBox(QMessageBox::Critical, QString("SafeOTP"),
QString("OTPLogs could not be fetched"),QMessageBox::Ok, this);
msgBox.exec();
QLOG_ERROR() << "fetchLogs error " << ret;
return;
}
QStandardItemModel *model = new QStandardItemModel(0,5,this); //5 columns
model->setHorizontalHeaderItem(0, new QStandardItem(QString("Date")));
model->setHorizontalHeaderItem(1, new QStandardItem(QString("Customer")));
model->setHorizontalHeaderItem(2, new QStandardItem(QString("Server")));
model->setHorizontalHeaderItem(3, new QStandardItem(QString("Authorized by")));
model->setHorizontalHeaderItem(4, new QStandardItem(QString("Description")));
for(QList<OtpLog>::Iterator lIt = logs.begin(); lIt != logs.end(); lIt++)
{
OtpLog& log = *lIt;
QList<QStandardItem*> row;
row.push_back(new QStandardItem(log.when.toString("dd MMM yyyy, hh:mm")));
row.push_back(new QStandardItem(QString(log.customer)));
row.push_back(new QStandardItem(QString(log.server)));
row.push_back(new QStandardItem(QString(log.author)));
row.push_back(new QStandardItem(QString(log.reason)));
model->appendRow(row);
}
// set the data model
ui->tblLog->setModel(model);
//Set the column to hide
ui->tblLog->setColumnHidden(1,true);
// set the column widths
int tw = ui->tblLog->width() - 5;
int w = tw / 6;
for(int i=0; i<4;i++)
{
ui->tblLog->setColumnWidth(i,w);
tw -= w;
}
ui->tblLog->setColumnWidth(4,tw);
}
For the slot/signal example, you need to connect two objects having the same parameters. so let me modify a bit your example:
Let's say you have:
signals:
void loginStatusChanged(bool isLoggedIn);
In your Login method you will have something like:
bool status = checkLogin();
emit loginStatusChanged(status);
And then you should have a dedicated slot in SafeOTPWindow doing something like that:
void SafeOTPWindow::UpdateTableAfterLogin(bool isLoggedIn)
{
ui->tblLog->setColumnHidden(1,isLoggedIn);
}
and you connect as usual:
connect(&login, SIGNAL(loginStatusChanged()), &w, SLOT(UpdateTableAfterLogin(bool)) );
Related
I have built a QTcpServer program that gets an XML-string sent to it by a QTcpSocket program.
I can confirm that the connection between these two programs can be established as before I wrote the script to convert the XML-string back into normal data, I could (with a few changes to the layout) display the same XML-string on the server program.
This leads me to believe that my error lies somewhere in the QDom parser, or the updateRow function.
Below is the code for the server:
//mainwindow.h
#include <QMainWindow>
#include <QTableView>
#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);
void Add_to_CV(QString C, QString Con, int Pn, int Bh, int Bb, int Bl, int Bw);
void Add_to_CV(QString C, QString Con, int Pn, int Ch, int Cd, int Cw);
public slots:
void updateRow(QStandardItem *item);
private:
QPushButton *SServer;
QTableView *ContainerView;
int Pallet_Number;
QStandardItemModel *HMod;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
};
#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),
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");
HMod = new QStandardItemModel;
HMod->setHorizontalHeaderLabels(HeaderRow);
resize(800,300);
connect(SServer, &QPushButton::clicked, this, &MainWindow::startServer);
connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::handleConnection);
connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::handleConnection);
connect(HMod, SIGNAL(itemchanged(QStandardItem*)), this, SLOT(updateRow(QStandardItem*)));
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->clearSpans(); //clear table to prepare for new XMLString
QByteArray buffer = tcpSocket->readAll();
QString FromContainer = QString::fromUtf8(buffer);
ReadXML(FromContainer);
}
void MainWindow::ReadXML(QString XMLString)
{
QDomDocument xRead;
xRead.setContent(XMLString);
QDomElement root = xRead.documentElement();
if(root.tagName() == "Pallets")
{
QDomElement Pallet = root.firstChildElement();
int PNum;
bool ok;
PNum = Pallet.attribute("Number").toInt(&ok);
while(!Pallet.isNull())
{
bool ok;
QDomElement Box_Cyl = Pallet.firstChildElement();
while(!Box_Cyl.isNull())
{
int CHei, CLen, CBre, CWei;
QString Container, CCode;
Container = Box_Cyl.tagName();
if(Box_Cyl.tagName() == "Box")
{
QDomElement Code = Box_Cyl.firstChildElement();
CCode = Code.text();
QDomElement Height = Code.nextSiblingElement();
CHei = Height.text().toInt(&ok);
QDomElement Length = Code.nextSiblingElement();
CLen = Length.text().toInt(&ok);
QDomElement Breadth = Code.nextSiblingElement();
CBre = Breadth.text().toInt(&ok);
QDomElement Weight = Code.nextSiblingElement();
CWei = Weight.text().toInt(&ok);
Add_to_CV(CCode, Container, PNum, CHei, CBre, CLen, CWei);
}else if(Box_Cyl.tagName() == "Cylinder")
{
QDomElement Code = Box_Cyl.firstChildElement();
CCode = Code.text();
QDomElement Height = Code.nextSiblingElement();
CHei = Height.text().toInt(&ok);
QDomElement Diameter = Code.nextSiblingElement();
CBre = Diameter.text().toInt(&ok);
QDomElement Weight = Code.nextSiblingElement();
CWei = Weight.text().toInt(&ok);
Add_to_CV(CCode, Container, PNum, CHei, CBre, CWei);
}
Box_Cyl = Box_Cyl.nextSiblingElement();
}
}
Pallet = Pallet.nextSiblingElement();
}
}
void MainWindow::Add_to_CV(QString C, QString Con, int Pn, int Bh, int Bb, int Bl, int Bw)
{
QList<QStandardItem*> row;
QStandardItem *Pallet_Num_Item = new QStandardItem(Pn);
QStandardItem *Container_Type = new QStandardItem(Con);
QStandardItem *Box_Code = new QStandardItem(C);
QStandardItem *Box_Height = new QStandardItem(Bh);
QStandardItem *Box_Breadth = new QStandardItem(Bb);
QStandardItem *Box_Length = new QStandardItem(Bl);
QStandardItem *Box_Weight = new QStandardItem(Bw);
row << Pallet_Num_Item << Container_Type << Box_Code << Box_Height << Box_Breadth << Box_Length << Box_Weight;
HMod->appendRow(row);
}
void MainWindow::Add_to_CV(QString C, QString Con, int Pn, int Ch, int Cd, int Cw)
{
QList<QStandardItem*> row;
QStandardItem *Pallet_Num_Item = new QStandardItem(Pn);
QStandardItem *Container_Type = new QStandardItem(Con);
QStandardItem *Cylinder_Code = new QStandardItem(C);
QStandardItem *Cylinder_Height = new QStandardItem(Ch);
QStandardItem *Cylinder_Diameter = new QStandardItem(Cd);
QStandardItem *Cylinder_Blank = new QStandardItem(); //Cylinder does not have a Length
QStandardItem *Cylinder_Weight = new QStandardItem(Cw);
row <<Pallet_Num_Item << Container_Type << Cylinder_Code << Cylinder_Height << Cylinder_Diameter << Cylinder_Blank << Cylinder_Weight;
HMod->appendRow(row);
}
void MainWindow::updateRow(QStandardItem *item)
{
QColor colour = Qt::white;
int row = item->row();
if (HMod->item(row, 2)->data(Qt::DisplayRole).toFloat() >= 200)
colour = Qt::red;
for (int col=0; col<4; col++)
HMod->item(row, col)->setBackground(colour);
}
The XML string I am currently trying to send into this program is identical to the string that is shown in the following image:
I suspect that the problem lies with my QDom xml parsing. If so, could anyone kindly let me know what I need to do to fix it please.
I have created a simple app for monitoring the connected devices. This app shows the connection status of 25 client devices.
This app implements a TCP server and listens at port 7777 and as many as 25 clients can be connected to this application. If no data is received from a client for 30 seconds, the app marks the device as "Offline".
For this purpose, QTimer for each connected device is started for 30 sec when some client connects and the payload is received. Each timer is connected to a common SLOT refreshOfflineDevices() Soon as any timer timeout occurs, refreshOfflineDevices() is called and the non-running timers corresponding to the device are marked as "Offline" in the GUI.
The app works fine and the GUI is updated instantly when the connected device count is not more than 4 or 5. As the connected devices rise, (greater than 8 or 9) the lag in the GUI update becomes obvious.
After some desk research, I assume that the parallel timers would need to be moved to a thread to avoid GUI lags. For that, I created a CyclicWorker class for separating the QTimer but not sure how this will work in this case
I need help with moving and managing all timekeeping events to a thread. Also, I need advise on my assumption of GUI lag correctness
my app GUI
monitor.h
#ifndef CENTRALMONITOR_H
#define CENTRALMONITOR_H
#include <QtCore>
#include <QMainWindow>
#include "ui_device_display.h"
#include "tcp_server.h"
#include "cyclic_worker.h"
#define MAX_DEVICES (25)
#define DEVICE_KEEP_ALIVE_MS (30*1000) // keeps track of the connection before marking "Offline"
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
Ui::MainWindow *ui;
TCPServer *ptr_server = nullptr;
QTimer *ptr_deviceTimer[MAX_DEVICES] = {nullptr};
void GUI_update(const int device_number, const QString device_status);
CyclicWorker timerThread;
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
UIDeviceDisplay *ptr_devices[MAX_DEVICES] = {nullptr};
public slots:
void parseJSON(QString response);
void refreshOfflineDevices();
};
#endif // CENTRALMONITOR_H
monitor.cpp
#include "monitor.h"
#include "ui_monitor.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
system("clear");
ui->setupUi(this);
// MyServer instance (TCPServer contains TCPClient instance).
ptr_server = new TCPServer();
connect(ptr_server, SIGNAL(uiPayloadReady(QString)), this, SLOT(parseJSON(QString)));
// draw (MAX_DEVICES) (initialize as offline)
for(int i=0 ; i<5 ; i++) // 5 rows
{
for(int j=0 ; j<5 ; j++) // 5 columns
{
ptr_devices[i*5 + j] = new UIDeviceDisplay(this, j, i);
ptr_devices[i*5 + j]->show();
QString text_device_number = QString("").append(QString::number( i*5 + j + 1) );
ptr_devices[i*5 + j]->ptr_label_device_number->setText(text_device_number);
}
}
// connect keep alive timers to use later
for(int device_idx=0; device_idx<MAX_DEVICES; device_idx++)
{
ptr_deviceTimer[device_idx] = new QTimer();
connect(ptr_deviceTimer[device_idx], SIGNAL(timeout()), this, SLOT(refreshOfflineDevices()));
this->ptr_deviceTimer[device_idx]->setSingleShot(true);
ptr_deviceTimer[device_idx]->setTimerType(Qt::PreciseTimer);
}
timerThread.start();
timerThread.threadFlag = 1;
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
#brief This slot is emitted by ptr_socket readReady() signal by the TCP client handler
#param The received payload for updating GUI
*/
void MainWindow::parseJSON(const QString response)
{
const QJsonDocument jsonDocument = QJsonDocument::fromJson(response.toUtf8());
const QJsonObject jsonObjectRecords = jsonDocument.object();
const int device_number = jsonObjectRecords.value("device_number").toInt();
const QString device_status = jsonObjectRecords.value("device_status").toString();
// start time keeper for current device.
ptr_deviceTimer[device_number-1]->start(DEVICE_KEEP_ALIVE_MS);
GUI_update(device_number, device_status);
}
/*
#brief This method updates the GUI with provided params.
#param GUI update params
*/
void MainWindow::GUI_update(const int device_number, const QString device_status)
{
const int device_idx = device_number-1;
// update device label.
ptr_devices[device_idx]->ptr_label_device_status->setText(device_status);
// refresh online devices label.
int onlineCount =0;
for(int device_idx=0; device_idx<MAX_DEVICES; device_idx++)
{
if( ptr_deviceTimer[device_idx]->isActive() )
onlineCount++;
}
ui->label_online_devices->setText(QString("Online devices: %1").arg(onlineCount));
}
/*
#brief This method is called upon every device_timer expiration. It updates GUI for all the devices that are offline
*/
void MainWindow::refreshOfflineDevices()
{
for(int device_number=1; device_number<=MAX_DEVICES; device_number++)
{
// if device timer is not running, the device is offline
if( !ptr_deviceTimer[device_number-1]->isActive() )
{
GUI_update(device_number, "Offline");
}
}
}
cyclic_worker.h
#include <QDebug>
#include <QThread>
class CyclicWorker : public QThread
{
Q_OBJECT
public:
bool threadFlag; // variable used to control thread execution
CyclicWorker();
void run();
void quit();
private:
};
cyclic_worker.cpp
#include "cyclic_worker.h"
CyclicWorker::CyclicWorker()
{
qDebug() << "\nCyclicWorker object created";
threadFlag = false;
}
/*----------------------------------------------------------------------------
* void run()
*
* Return value : none
*
* Description : this function runs after thread start
*----------------------------------------------------------------------------*/
void CyclicWorker::run()
{
qDebug("Thread invoked . . .");
while(threadFlag)
{
}
}
/*----------------------------------------------------------------------------
* void quit()
*
* Return value : none
*
* Description : this function stops the running thread
*----------------------------------------------------------------------------*/
void CyclicWorker::quit()
{
qDebug() << "Thread stopped . . .";
}
ui_device_display.h
#ifndef UI_DEVICE_DISPLAY_H
#define UI_DEVICE_DISPLAY_H
#include <QtWidgets>
#define X_PADDING (30) // this is the base container widget co-ordinates
#define Y_PADDING (110)
class UIDeviceDisplay : public QFrame
{
Q_OBJECT
public:
UIDeviceDisplay(QWidget *parent = nullptr, int x=0, int y=0);
QLabel *ptr_label_device_number = nullptr;
QLabel *ptr_label_device_status = nullptr;
static const int frameWidth = 240;
static const int frameHeight = 190;
static const int deviceLabelWidth = 70;
static const int deviceLabelHeight = 50;
static const int statusLabelWidth = 150;
static const int statusLabelHeight = 30;
};
#endif
ui_device_display.cpp
#include "ui_device_display.h"
UIDeviceDisplay::UIDeviceDisplay(QWidget *parent, int x, int y) : QFrame(parent)
{
//QFrame containing all the elements.
this->setGeometry(QRect( X_PADDING + frameWidth*x, Y_PADDING + frameHeight*y, frameWidth, frameHeight));
this->hide();
//QLabel for bed number.
ptr_label_device_number = new QLabel(this);
ptr_label_device_number->setGeometry(QRect((frameWidth/2)-(deviceLabelWidth/2), 20, deviceLabelWidth, deviceLabelHeight));
ptr_label_device_number->setAlignment(Qt::AlignCenter);
//QLabel that displays the device status.
ptr_label_device_status = new QLabel(this);
ptr_label_device_status->setText("Offline");
ptr_label_device_status->setGeometry(QRect(45, 90, statusLabelWidth, statusLabelHeight));
ptr_label_device_status->setAlignment(Qt::AlignCenter);
}
tcp_server.h
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QAbstractSocket>
#include "tcp_client_handler.h"
class TCPServer : public QTcpServer
{
Q_OBJECT
public:
explicit TCPServer(QObject *parent=0);
protected:
void incomingConnection(int handle);
signals:
void uiPayloadReady(QString uiPayload);
public slots:
void payloadReady(QString payload);
};
#endif
tcp_server.cpp
#include "tcp_server.h"
TCPServer::TCPServer(QObject *parent) :
QTcpServer(parent)
{
if(listen(QHostAddress::Any,7777))
qDebug("DEBUG: Server listening at 7777");
else
qDebug("DEBUG: Could not start server");
}
void TCPServer::incomingConnection(int handle)
{
TCPClientHandler *ptr_client = new TCPClientHandler(this);
ptr_client->SetSocket(handle);
connect(ptr_client, SIGNAL(payloadReady(QString)), this, SLOT(payloadReady(QString)));
}
void TCPServer::payloadReady(QString payload)
{
emit uiPayloadReady(payload);
}
tcp_client_handler.h
#ifndef TCP_CLIENT_HANDLER_H
#define TCP_CLIENT_HANDLER_H
#include <QObject>
#include <QTcpSocket>
#include <QDebug>
class TCPClientHandler : public QObject
{
Q_OBJECT
public:
explicit TCPClientHandler(QObject *parent = nullptr);
void SetSocket(int Descriptor);
QTcpSocket *ptr_socket = nullptr;
signals:
void payloadReady(QString payload);
public slots:
void connected();
void disconnected();
void readReady();
private:
};
#endif
tcp_client_handler.cpp
#include "tcp_client_handler.h"
TCPClientHandler::TCPClientHandler(QObject *parent) : QObject(parent)
{
}
void TCPClientHandler::SetSocket(int Descriptor)
{
ptr_socket = new QTcpSocket(this);
connect(ptr_socket, SIGNAL(connected()), this, SLOT(connected()));
connect(ptr_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(ptr_socket, SIGNAL(readyRead()), this, SLOT(readReady()));
ptr_socket->setSocketDescriptor(Descriptor);
}
void TCPClientHandler::connected()
{
//qDebug("DEBUG: client connect event");
}
void TCPClientHandler::disconnected()
{
//qDebug("DEBUG: client disconnect event");
}
void TCPClientHandler::readReady()
{
const QByteArray byteArrayResponse = ptr_socket->readAll();
const QString stringResponse = QString(byteArrayResponse);
//qDebug() << "DEBUG: " << stringResponse;
emit payloadReady(stringResponse);
}
main.cpp
#include "monitor.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
w.show();
return a.exec();
}
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.
I'm new to programming. Would like to know how to print the output data from the code below (C++) using the Qt. I need an answer to appear in the QTextEdit window.
for (int x=0; x<10; x++);
Here's how you might capture the qDebug messages in a QAbstractItemModel or QTextDocument. Both of those classes are models, their associated views are QListView (or any other view), and QTextEdit (preferably QPlainTextEdit or QTextBrowser), respectively.
// https://github.com/KubaO/stackoverflown/tree/master/questions/qdebug-window-output-52061269
#include <QtWidgets>
struct LogToModelData {
bool installed;
QtMessageHandler previous = {};
QList<QPointer<QObject>> models;
};
Q_GLOBAL_STATIC(LogToModelData, logToModelData)
void logToModelHandler(QtMsgType type, const QMessageLogContext &context,
const QString &msg) {
for (auto m : qAsConst(logToModelData->models)) {
if (auto model = qobject_cast<QAbstractItemModel *>(m)) {
auto row = model->rowCount();
model->insertRow(row);
model->setData(model->index(row, 0), msg);
} else if (auto doc = qobject_cast<QTextDocument *>(m)) {
QTextCursor cur(doc);
cur.movePosition(QTextCursor::End);
if (cur.position() != 0) cur.insertBlock();
cur.insertText(msg);
}
}
if (logToModelData->previous) logToModelData->previous(type, context, msg);
}
void logToModel(QObject *model) {
logToModelData->models.append(QPointer<QObject>(model));
if (!logToModelData->installed) {
logToModelData->previous = qInstallMessageHandler(logToModelHandler);
logToModelData->installed = true;
}
}
void rescrollToBottom(QAbstractScrollArea *view) {
static const char kViewAtBottom[] = "viewAtBottom";
auto *scrollBar = view->verticalScrollBar();
Q_ASSERT(scrollBar);
auto rescroller = [scrollBar]() mutable {
if (scrollBar->property(kViewAtBottom).isNull())
scrollBar->setProperty(kViewAtBottom, true);
auto const atBottom = scrollBar->property(kViewAtBottom).toBool();
if (atBottom) scrollBar->setValue(scrollBar->maximum());
};
QObject::connect(scrollBar, &QAbstractSlider::rangeChanged, view, rescroller,
Qt::QueuedConnection);
QObject::connect(scrollBar, &QAbstractSlider::valueChanged, view, [scrollBar] {
auto const atBottom = scrollBar->value() == scrollBar->maximum();
scrollBar->setProperty(kViewAtBottom, atBottom);
});
}
int main(int argc, char *argv[]) {
QApplication app{argc, argv};
QWidget ui;
QVBoxLayout layout{&ui};
QListView view;
QTextBrowser browser;
layout.addWidget(new QLabel(QLatin1String(view.metaObject()->className())));
layout.addWidget(&view);
layout.addWidget(new QLabel(QLatin1String(browser.metaObject()->className())));
layout.addWidget(&browser);
QStringListModel model;
view.setModel(&model);
logToModel(view.model());
logToModel(browser.document());
rescrollToBottom(&view);
rescrollToBottom(&browser);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [] {
static int n;
qDebug() << "Tick" << ++n;
});
timer.start(500);
ui.show();
return app.exec();
}
Also note that the separate declaration of the loop induction variable i is a very much obsolete C-ism - the last time you had to write code like that was two decades ago.
I have a project that I am working on, that will hopefully result in C++ code with a QML UI as a console, communicating with other consoles and equipment.
My test setup is based on a RaspBerry Pi running UDP comms (works fine into a normal Qt application).
I have tried to port to Qt Quick, and use a simple QML UI, but if I declare the subclass early in my "main.cpp" it doesn't connect properly.
If I declare it in the main.cpp "main" function, then I have scope issues with the subclass functions that I want to use to transfer data.
Open to suggestions / critique......and I am 100% sure that there is a "proper" way of doing this, so if anyone wants to point me at it......I will be enraptured!
Qt version is Qt5.3.
import QtQuick 2.2
import QtQuick.Controls 1.1
Rectangle {
width: 440; height: 150
color: "orange"
Column {
anchors.fill: parent; spacing: 20
Text {
text: rootItem.theChange
font.pointSize: 12; anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// signalgrab.h
#ifndef SIGNALGRAB_H
#define SIGNALGRAB_H
#include <QObject>
#include <QUdpSocket>
#include <QString>
class SignalGrab : public QObject
{
Q_OBJECT
public:
explicit SignalGrab(QObject *parent = 0);
int SendValue();
void setupUDP();
signals:
public slots:
void readyRead();
private:
QUdpSocket *socket;
QHostAddress groupAddress;
};
#endif // SIGNALGRAB_H
// signalgrab.cpp
#include "signalgrab.h"
int i3 = 0;
SignalGrab::SignalGrab(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
socket->bind(QHostAddress("0.0.0.0"), 45454);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
qDebug() << "Socket connected ok!";
}
void SignalGrab::readyRead()
{
// when data comes in
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
std::string s1 (buffer);
std::string s2 = s1.substr(26,sizeof(s1));
i3 = atoi(s2.data());
SendValue();
}
int SignalGrab::SendValue()
{
qDebug() << "sending i3 as: "<< i3;
return i3;
}
// main.cpp
#include <QtGui>
#include <QApplication>
#include <QQmlContext>
#include <QQuickView>
#include <QString>
#include "signalgrab.h"
int y=13;
// ///////////////////////////////////
//SignalGrab nc;
// ///////////////////////////////////
class Object : public QObject
{
Q_OBJECT
Q_PROPERTY(QString theChange READ getTheChange NOTIFY changeOfStatus)
public:
Object()
{
changeMe = false;
myTimer = new QTimer(this);
myTimer->start(5000);
connect(myTimer, SIGNAL(timeout()), this, SLOT(testSlot()));
}
QString getTheChange()
{
if (theValue == 0)
{
return "The Acid QML Test";
}
if (theValue == 1)
{
y = (fetchValue());
qDebug() << "New y!" << y;
return QString("Returning %1").arg(y);
}
return "nothing has happened yet";
}
int fetchValue()
{
// return (nc::SendValue());
return y;
}
Q_INVOKABLE void someFunction(int i)
{
if ( i == 0) {
theValue = 0;
}
if (i == 1) {
theValue = 1;
}
emit changeOfStatus(i);
}
signals:
void changeOfStatus(int i) ;
public slots:
void testSlot()
{
if (changeMe)
{
someFunction(0);
} else {
someFunction(1);
}
changeMe = !changeMe;
}
private:
bool changeMe;
int theValue;
QTimer *myTimer;
};
#include "main.moc"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Object myObj;
// //////////////////////////////
SignalGrab nc; //added
// //////////////////////////////
nc.SendValue();
QQuickView view;
view.rootContext()->setContextProperty("rootItem", (QObject *)&myObj);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}