Connecting radio buttons to QSqlTableModel via QDataWidgetMapper in Qt - c++

I would like to map a radio buttons to a QDataWidgetMapper as per this forum thread. I am not sure though how to hook up the delegate mentioned. Could anyone explain this?
I already have .ui files that contain the radio buttons, among QLineEdits etc. Those are already hooked via a QDataWidgetMapper to a QSqlTableModel. Can I use the solution mentioned in the url above to add the existing radio buttons in the .ui field to the button group, and get the state into the DB?
My radio buttons are actually binary selections, so storing boolean values in the db would be sufficient. I do not want to use a checkbox because radio buttons make the selection more easily comprehensible to the user, in this case.
So far I have added includes to the example .h file
#include <QWidget>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QAbstractButton>
and created the .cpp file.
#include "buttongroup.h"
ButtonGroup::ButtonGroup(QWidget *parent) :
QWidget(parent)
{
m_buttonGroup=new QButtonGroup(this);
m_layout=new QVBoxLayout(this);
connect(m_buttonGroup,SIGNAL(buttonClicked(int)),this,SIGNAL(buttonClicked(int)));
setLayout(m_layout);
}
int ButtonGroup::getCheckedId()
{
int id=m_buttonGroup->id(m_buttonGroup->checkedButton());
return id;
}
void ButtonGroup::checkId(int id)
{
m_buttonGroup->button(id)->setChecked(true);
}
void ButtonGroup::addButton(QAbstractButton *button, int id)
{
m_buttonGroup->addButton(button,id);
m_layout->addWidget(button);
//connect(button,SIGNAL(clicked()),this,SIGNAL(buttonClicked()));
}

The delegate needs to be connected to the mapper.
I have created a sample project that works at http://scanrobot.fi/wp-content/uploads/2015/06/qradiobutton-qsqltablemodel.zip
Also at: https://github.com/savolai/qt_qradiobutton_qdatawidgetmapper_example
Here is the essence of what I needed to understand in practice:
QDataWidgetMapper* mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->toLast();
QRadioButton *b1=new QRadioButton("a",this);
QRadioButton *b2=new QRadioButton("b",this);
RadioButtonDelegate *delegate=new RadioButtonDelegate(this);
ButtonGroup *group=new ButtonGroup(this);
mapper->addMapping(group,model->fieldIndex("radio"));
// set the delegate as the item delegate of mapper
mapper->setItemDelegate(delegate);
// connect value change in group to delegate so it can send appropriate signals
connect(group,SIGNAL(buttonClicked(int)),delegate,SLOT(commitMyData()));
group->addButton(b1,1);
group->addButton(b2,0);
Source for buttongroup.cpp:
#include "buttongroup.h"
ButtonGroup::ButtonGroup(QWidget *parent) :
QWidget(parent)
{
m_buttonGroup=new QButtonGroup(this);
connect(m_buttonGroup,SIGNAL(buttonClicked(int)),this,SIGNAL(buttonClicked(int)));
}
int ButtonGroup::getCheckedId()
{
int id=m_buttonGroup->id(m_buttonGroup->checkedButton());
return id;
}
void ButtonGroup::checkId(int id)
{
m_buttonGroup->button(id)->setChecked(true);
}
void ButtonGroup::addButton(QAbstractButton *button, int id)
{
m_buttonGroup->addButton(button,id);
}
buttongroup.h (nothing very new here compared to the original url):
#ifndef BUTTONGROUP_H
#define BUTTONGROUP_H
#include <QWidget>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QAbstractButton>
#include <QRadioButton>
class ButtonGroup : public QWidget
{
Q_OBJECT
public:
explicit ButtonGroup(QWidget *parent = 0);
Q_PROPERTY(int checkedId READ getCheckedId WRITE checkId USER true)
int getCheckedId();
void checkId(int id);
void addButton(QAbstractButton *button, int id);
signals:
void buttonClicked(int);
private:
QButtonGroup *m_buttonGroup;
QVBoxLayout *m_layout;
};
#endif // BUTTONGROUP_H
radiobuttondelegate.h (nothing very new here either):
#ifndef RADIOBUTTONDELEGATE_H
#define RADIOBUTTONDELEGATE_H
#include <QItemDelegate>
class RadioButtonDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit RadioButtonDelegate(QObject *parent = 0);
signals:
public slots:
void commitMyData();
};
#endif // RADIOBUTTONDELEGATE_H
radiobuttondelegate.cpp (or here):
#include "radiobuttondelegate.h"
#include <QDebug>
RadioButtonDelegate::RadioButtonDelegate(QObject *parent) :
QItemDelegate(parent)
{
}
void RadioButtonDelegate::commitMyData() {
QWidget *obj = qobject_cast<QWidget*>(sender());
emit commitData(obj);
emit closeEditor(obj);
qDebug() << "commitMyData";
}

Related

Send Variable values from QDialog to QMainwindow function

My UI MainWindow has a QListWidget and , upon clicking of its items ,a corresponding QDialog box must pop up , which prompts the user to enter some values in QDialog box, The values entered into line_edits of QDialog box must stored into a QString variable and this variable should be accessed/used in a function of MainWindow,
for Example: I have a QListWidget, with 3 items "New York","Glasgow","Mumbai", and when i double click item named "New York", a pop-up shows up asking me this
and after i enter 3 and Hilton , the item in QListWidget which was initially "New York" must be changed to
"New York -3 , The safehouse is in Hilton"
my code for MainWindow.cpp is
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore>
#include <QtGui>
#include <sstream>
#include <QtWidgets/qmessagebox.h>
#include <QtWidgets/qlistwidget.h>
using namespace std;
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->My_listwidget->addItem("New York");
ui->My_listwidget->addItem("Glasgow");
ui->My_listwidget->addItem("Mumbai");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_My_listwidget_itemDoubleClicked(QListWidgetItem* item)
{
QString test = item->text();
std::string test_s = test.toStdString();
if (test_s.find("New York") != std::string::npos) // check if item contains text "New York"
{
WinApp winApp;
winApp.setModal(true); //Displaying the window here
winApp.exec();
}
if (test_s.find("Glasgow") != std::string::npos)
{
// show another dialog box asking some questions
}
if (test_s.find("Mumbai") != std::string::npos)
{
// show another dialog box asking some questions
}
}
My code for mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets/QMainWindow>
#include "ExecutionContext.h"
#include <QtWidgets/qlistwidget.h>
//#include "secdialog.h"
#include <qregexp.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT //Used to handle events
public:
MainWindow(QWidget* parent = 0);
~MainWindow(); //Destructor used to free resources
private slots:
void on_xml_scripts_textbox_itemDoubleClicked(QListWidgetItem* item);
Ui::MainWindow* ui; // pointing to UI class
private:
};
#endif // MAINWINDOW_H
my code for WinApp.h , winapp is the name of my dialog
#include <QtWidgets/qdialog.h>
#include "ui_WinApp.h"
class WinApp : public QDialog, public Ui::WinApp
{
Q_OBJECT
public:
WinApp(QWidget *parent = Q_NULLPTR);
~WinApp();
private slots:
private:
Ui::WinApp ui;
};
WinApp.cpp
#include "WinApp.h"
WinApp::WinApp(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
}
WinApp::~WinApp()
{
}
you need to add in the WinApp dialog class the test getter, it should be something like:
QString getFavouriteHotel() const {
return ui.<favourite-hotel-label>.text()
}
In the MainWindow after the line winApp.exec(); I suggest adding an if to check if the user accepted or declined the dialog (docs). If the user accepted the dialog then you can retrieve the text with the getters you just added.
Tips: avoid using exec, as said in the docs use the open
-- UPDATE -- QDialog accept --
Always check the docs
connect(&WinApp, &QDialog::finished, this, [this](int result) {
if(result == QDialog::Accepted){
// do aswomness
return
}
});
Have the function initiating the QDialog object pass the QString argument in the constructor and override accept().
#include <QtWidgets/qdialog.h>
#include "ui_WinApp.h"
class WinApp : public QDialog, public Ui::WinApp
{
Q_OBJECT
public:
WinApp(QString& stringToModify, QWidget *parent = Q_NULLPTR);
~WinApp();
private slots:
void accept() override;
private:
Ui::WinApp ui;
};
and define the acccept() slot which will get the QString from lineEdit and update the stringToModify with it.
void WinApp::accept(){
//do stuff with QString
this->close();
}

QComboBox with click to lineEdit

I wish derived class from QComboBox with following additional feature:
When user clicks to QLiineEdit of this combo box, the effect have to be the same as click to arrow on the right side of combo box (showPopup() method).
My attemption is:
File lineedit.h
#ifndef LINEEDIT_H
#define LINEEDIT_H
#include <QLineEdit>
class LineEdit : public QLineEdit {
Q_OBJECT
public:
LineEdit(QWidget *parent = nullptr);
signals:
void pressed();
protected:
void mousePressEvent(QMouseEvent *event) override;
};
#endif // LINEEDIT_H
File lineedit.cpp
#include "lineedit.h"
#include <QMouseEvent>
LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) {}
void LineEdit::mousePressEvent(QMouseEvent *event) {
QLineEdit::mousePressEvent(event);
emit pressed();
event->accept();
}
File combobox.h
#ifndef COMBOBOX_H
#define COMBOBOX_H
#include <QComboBox>
class ComboBox : public QComboBox {
Q_OBJECT
public:
ComboBox(QWidget *parent = nullptr);
private slots:
void lineEditPressed();
};
#endif // COMBOBOX_H
File combobox.cpp
#include "combobox.h"
#include "lineedit.h"
ComboBox::ComboBox(QWidget *parent) : QComboBox(parent) {
setLineEdit(new LineEdit);
connect(lineEdit(), SIGNAL(pressed()), this, SLOT(lineEditPressed()));
}
void ComboBox::lineEditPressed() { showPopup(); }
But, when I press lineEdit, it shows popup, but after releasing mouse button it vanishes.
Please, revise the documentation of the event handler. As you show pop-up menu in this function, then the release event will conflict hastily. I can't predict your implementation of showPopup(), but please don't create a pop-up menu inside it. You may show, hide, assign, but NEVER create.

Add QMap items in a QListWidget and select the item as active

I'm a newbee on QT and I'm trying to create a kalk.
It's possible to insert on a QListWidget a QMap object?
I'll explain:
I have this MainWindow
with at the bottom a QListWidget, what I want to do is to add in the List all the QMap object that I create in on the costructor and the object that I create when I'll add an attack.
baseWindow.h
#ifndef BASEWINDOW_H
#define BASEWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QGridLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QTextEdit>
#include <QListWidget>
#include <QPushButton>
class baseWindow : public QWidget
{
Q_OBJECT
public:
explicit baseWindow(QWidget *parent = 0);
public slots:
void changeKalkClicked();
void addClicked();
void clearClicked();
void deleteClicked();
void itemSelected();
private:
QPushButton* addButton;
QPushButton* clearButton;
QPushButton* deleteButton;
QLineEdit* displayBA;
QMap<QString,BaseAttack> storedBA;
QListWidget* list;
};
basewindow.cpp
baseWindow::baseWindow(QWidget *parent) : QWidget(parent)
{ //Omitted the button/layout/LineEdit creation
list = new QListWidget;
storedBA.insert(tr("Empty"),BaseAttack());
storedBA.insert(tr("First"),BaseAttack());
QListWidgetItem* prova = new QListWidgetItem;
prova->setText(tr("Try"));
list->addItem(prova);
}
It's possible? I need to create a connect from the QMap to the QListWidget?
The solution is simple, you just have to use the text of the item pressed, and we get the BaseAttack using the QMap, but to work in a simple way the BaseAttack class must have a copy constructor.
*.h
private slots:
void onItemClicked(QListWidgetItem *item);
*.cpp
storedBA.insert(tr("Empty"), BaseAttack());
storedBA.insert(tr("First"), BaseAttack());
QMapIterator<QString, BaseAttack> i(storedBA);
while (i.hasNext()) {
i.next();
list->addItem(i.key());
}
connect(list, &QListWidget::itemClicked, this, &baseWindow::onItemClicked);
}
void baseWindow::onItemClicked(QListWidgetItem *item)
{
BaseAttack ba = storedBA[item->text()];
}

Selection bar with a ruler using Qt

I am trying to make a ruler in Qt. I am developing an application which requires a line edit in which the user can select any part of the string. When the selection is done, the start and end co-ordinates of the selection are passed to the backend.
The ruler which is shown with the line edit has a precision of one character or blank space in the string.
I have built a similar widget using Java and ExtJS some time ago. I am trying to simulate the same with Qt for quite some time now but not succeeding in doing so.
Please take a look at the image to understand what it looks like. I want to know whether it is possible or not in Qt. If it is possible what widget should I use to achieve it?
I am not 100% sure I understand your question correctly.
You can write a class inheriting from QLineEdit to emit signals when its selection has changed.
Below is a simple example of such a class: it takes the native signal selectionChanged and has two new signals which emit information about the changed text just to show what could be possible. I also include a simple dialog class to show how to use this (even if it's just a crude way).
lineedit.h
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class LineEdit: public QLineEdit
{
Q_OBJECT
public:
LineEdit(QWidget *parent = 0): QLineEdit(parent)
{
connect(this, SIGNAL(selectionChanged()), this, SLOT(textSelectionChanged() ));
}
public slots:
void textSelectionChanged() {
emit selectionChanged(this->selectedText());
emit selectionChanged(this->selectionStart(), this->selectedText().length() );
}
signals:
void selectionChanged(const QString&);
void selectionChanged(int , int );
};
#endif
dialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include <QDialog>
#include <QtCore>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0) : QDialog(parent) {}
public slots:
void textChanged(const QString &string) {
qDebug() << string;
}
void textChanged(int start, int length) {
qDebug() << "Start"<< start << ", length: " << length;
}
};
#endif
main.cc (for completeness)
#include <QApplication>
#include "dialog.h"
#include "lineedit.h"
#include <QHBoxLayout>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Dialog dialog;
QHBoxLayout *layout = new QHBoxLayout(&dialog);
LineEdit lineedit;
layout->addWidget(&lineedit);
QObject::connect(&lineedit,SIGNAL(selectionChanged(QString)), &dialog, SLOT(textChanged(QString)));
QObject::connect(&lineedit,SIGNAL(selectionChanged(int,int)), &dialog, SLOT(textChanged(int,int)));
dialog.show();
return app.exec();
}
Let me know if this helps.

Qt connection QTableWidget and QGLWidget

I am new in Qt and i stacked in a task. I created a QGLWidget and i try to connect it with a QTablewidget. I want to take a variable from QTableWidget which i want to use in order to plot in the QGLWidget. The problem is that there are two classes, one for QGLWidget and one for ui (QDialog where QTableWidget is included) and i don't know how to take input from QTableWidget. Can i use signal and slot or i could have access in ui from QGLWidget and how can i do it? I would appreciate any thoughts.
You can do this without signal and slot. Use setter, you can set different types of variables and use it inside GLWidget:
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
#include <QDebug>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
void setValue(int i);
signals:
public slots:
private:
int member;
};
#endif // GLWIDGET_H
Cpp:
#include "glwidget.h"
GLWidget::GLWidget(QWidget *parent) :
QGLWidget
(parent)
{
}
void GLWidget::setValue(int i)
{
member = i;
qDebug() << i;
}
Usage:
void MainWindow::on_tableWidget_clicked(const QModelIndex &index)
{
GLWidget *wgt = new GLWidget;
wgt->setValue(index.data().toInt());
wgt->show();
}