how to get row number after comboBox item in QTableWidget in qt - c++

I would like to get a number of a QTableWidget row after selecting some topic in comboBox how it is possible to get the row, thanks.
void MainWindow::metto_stringa(int i)
{
QWidget *w = qobject_cast<QWidget *>(sender()->parent());
if(w)
{
int row = ui->tableWidget->indexAt(w->pos()).row();
ui->lineEdit->setText(QString::number( row ));
}
// ui->lineEdit->setText(QString::number( i ));
}
else if(i == 3)
{
// ui->tableWidget->setCellWidget(ui->tableWidget->rowCount(), i, "");
QString s = "Normal";
QComboBox *combo = new QComboBox;
combo->addItem("Below normal");
combo->addItem("Normal");
combo->addItem("Above normal");
combo->addItem("High");
combo->addItem("Real time");
connect(combo,SIGNAL(currentIndexChanged(int)),this,
SLOT(metto_stringa(int)));
ui->tableWidget->setCellWidget(ui->tableWidget->rowCount()-1, i,combo);
/* ui->tableWidget->setCellWidget(i,4,combo);
QTableWidgetItem*item = new QTableWidgetItem(s);
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
ui->tableWidget->setItem(ui->tableWidget->rowCount()-1, i,
item);*/
continue;
}

In this case you should not use the parent of the QComboBox, you must use the same sender()
void MainWindow::metto_stringa(int index)
{
QWidget *w = qobject_cast<QWidget *>(sender());
if(w)
{
int row = ui->tableWidget->indexAt(w->pos()).row();
ui->lineEdit->setText(QString::number(row));
}
}
In the question I answered before I commented that you must access the widget that you use in the setCellWidget() function, in the previous case the widget had the following form:
QWidget <--- QPushButton
parent() sender()
ie you owe to that widget so we take advantage of sender() and parent() in the previous case. In the current case QComboBox is added directly.

Related

Auto-resizing QStackedWidget

I have a class StackedWidget which inherits from QStackedWidget. The standard behaviour of QStackedWidget is that it adopts the size of its biggest element. What I want to do is force it to resize to its current element. I have already tried a couple of solutions found here and none of them work including e.g. setting size policies or calling hide() on all the widgets that go out of sight.
I think problem may reside in two possibilities:
1. Something is terribly wrong with StackedWidget. 2. The problem of resizing does not pertain directly to StackedWidget but to some layout or another widget that StackedWidget is nested in.
Concerning the first possibility, here I provide the StackedWidget class.
Please take a look at what my StackedWidget's declaration looks like:
class StackedWidget : public QStackedWidget
{
Q_OBJECT
private:
QComboBox* widgetChooser = nullptr;
public:
StackedWidget(QWidget* parent) : QStackedWidget(parent) {}
void setWidgetChooser(QComboBox* widgetChooser);
void addWidget(QWidget* widget);
private:
void makeConnection();
signals:
public slots:
void setCurrentIndex(const int& index);
};
Here goes the definition:
void StackedWidget::setWidgetChooser(QComboBox* widgetChooser)
{
if (widgetChooser == nullptr) throw RuntimeError("widgetChooser is nullptr");
this->widgetChooser = widgetChooser;
makeConnection();
}
void StackedWidget::addWidget(QWidget* widget)
{
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QStackedWidget::addWidget(widget);
}
void StackedWidget::makeConnection()
{
connect(widgetChooser, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentIndex(int)));
}
void StackedWidget::setCurrentIndex(const int& index)
{
qDebug() << "Index changed to " << index;
QWidget* pWidget = widget(index);
Q_ASSERT(pWidget);
QStackedWidget::setCurrentWidget(pWidget);
pWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pWidget->adjustSize();
adjustSize();
}
Concering the second possibility, here goes how I use StackedWidget.
void SchemaWidget::TempBuildAlt(const SchemaElement* son, QVBoxLayout* parentLayout)
{
if (auto schemaAlternative = dynamic_cast<const SchemaAlternatives*>(son))
{
QComboBox* widgetBox = BuildWidgetChooserBox(schemaAlternative);
StackedWidget* stackedWidget = BuildStackedWidget(schemaAlternative);
stackedWidget->setWidgetChooser(widgetBox);
QHBoxLayout* boxLayout = new QHBoxLayout;
boxLayout->addWidget(new QLabel(schemaAlternative->Name, this));
boxLayout->addWidget(widgetBox);
QVBoxLayout* layout = new QVBoxLayout;
layout->addLayout(boxLayout);
layout->addWidget(stackedWidget);
parentLayout->addLayout(layout);
} else throw RuntimeError("Cannot cast son to SchemaAlternatives.");
}
QComboBox* SchemaWidget::BuildWidgetChooserBox(const SchemaAlternatives* schema)
{
QComboBox* alternativesBox = new QComboBox(this);
QStringListModel* listModel = new QStringListModel(this);
QStringList list;
for (int i = 1; i <= schema->Sons.High(); ++i)
{
if (const SchemaTree* son = dynamic_cast<const SchemaTree*>(schema->Sons(i).Get()))
{
list << son->Name;
}
else throw RuntimeError("Son cannot be cast to SchemaTree.");
}
listModel->setStringList(list);
alternativesBox->setModel(listModel);
return alternativesBox;
}
StackedWidget* SchemaWidget::BuildStackedWidget(const SchemaAlternatives* schema)
{
StackedWidget* stackedWidget = new StackedWidget(this);
for (int i = 1; i <= schema->Sons.High(); ++i)
{
if (const SchemaTree* alternativeSon = dynamic_cast<const SchemaTree*>(schema->Sons(i).Get()))
{
QWidget* widget = new QWidget(this);
QVBoxLayout* widgetLayout = new QVBoxLayout;
BuildWidget(alternativeSon, widgetLayout);
widget->setLayout(widgetLayout);
stackedWidget->addWidget(widget);
}
else throw RuntimeError("Son could not be cast to SchemaTree.");
}
return stackedWidget;
}
I want to say thanks in advance to anyone who will be willing to spend some time on my problem. I do appreciate it. Thanks. You're great.

Drag and drop listwidget items with a combobox inside

I have two listwidgets in icon mode list1 is a list of 100 widget items (each Widget item is an icon packed with a combobox with 3-4 items inside) .
Those combobox items are data of the icon this will never change ,they are packed with the Widget item ,listwidget2 is empty and I just want to be able to drag the widget item(icon and combobox with items) from 1 and make a favorite list with some widgets of list1, nothing will change to combobox items or the widget items of list1 they will have always the same data,
the problem is that each time I drag the widget only the icon is copied to the other listwidget.
QDir dir ("icons");
QFileInfoList list = dir.entryInfoList(QDir::AllEntries |
QDir::Dirs|QDir::NoDotAndDotDot);
for(int i=0 ; i < list.length() ; i++){
dir_names.push_back(list.at(i).baseName());
/*Setting the icon*/
QIcon icon;
icon.addFile(list.at(i).absoluteFilePath(), QSize(), QIcon::Normal,
QIcon::Off);
QListWidgetItem *iconItem = new QListWidgetItem(ui->listWidget);
iconItem->setIcon(icon);
QComboBox *box = new QComboBox;
QListWidgetItem *textItem = ui->listWidget->item(i);
ui->listWidget->setItemWidget( textItem,box);
box->setFixedHeight(18);
box->addItem(list.at(i).baseName());
}
If you want the combobox to be moved you must overwrite the dropEvent method so you must create a class that inherits from QListWidget, get the widget and copy the necessary data. If you want to use it in Qt Designer you must promote it.
listwidget.h
#ifndef LISTWIDGET_H
#define LISTWIDGET_H
#include <QListWidget>
class ListWidget : public QListWidget
{
Q_OBJECT
public:
ListWidget(QWidget * parent = 0);
void dropEvent(QDropEvent * event);
protected:
void mouseMoveEvent(QMouseEvent * event);
};
#endif // LISTWIDGET_H
listwidget.cpp
#include "listwidget.h"
#include <QDropEvent>
#include <QComboBox>
ListWidget::ListWidget(QWidget *parent):QListWidget(parent)
{
setDragEnabled(true);
setAcceptDrops(true);
setDropIndicatorShown(true);
setDefaultDropAction(Qt::MoveAction);
}
void ListWidget::dropEvent(QDropEvent *event)
{
if(event->dropAction() == Qt::MoveAction && event->source()){
ListWidget *listWidget = qobject_cast<ListWidget *>(event->source());
if(!listWidget)
return;
QList<QPersistentModelIndex> pIndexes;
for(QModelIndex index: listWidget->selectedIndexes()){
pIndexes << QPersistentModelIndex(index);
}
std::sort(pIndexes.begin(), pIndexes.end());
QListWidgetItem *item = itemAt(event->pos());
int rowStart = item? row(item) : count();
for(QPersistentModelIndex pindex: pIndexes){
int r = QModelIndex(pindex).row();
QComboBox *input = qobject_cast<QComboBox *>(listWidget->itemWidget(listWidget->item(r)));
QComboBox *output;
if(input){
// move data to QComboBox
output = new QComboBox;
for(int i=0; i<input->count(); i++){
output->addItem(input->itemText(i));
output->setCurrentText(input->currentText());
}
}
QListWidgetItem *it = listWidget->takeItem(r);
insertItem(rowStart, it);
if(input)
setItemWidget(it, output);
}
setState(QAbstractItemView::NoState);
}
}
void ListWidget::mouseMoveEvent(QMouseEvent *event)
{
setState(QAbstractItemView::DraggingState);
QListWidget::mouseMoveEvent(event);
}
In the following link there is an example.

How to show the row where QPushButton is clicked in QTableWidget

I would like to delete row where QPushButton is clicked how it is possible to I think it is reasonable to use slots but how to do it don't know , if you have any ideas how to get a row of selected button please share, thanks.
It is my table
It is a code where i add rows to my QTableWidget
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(int i = 0; i<20;i++)
ui->tableWidget->insertRow(ui->tableWidget->rowCount());
QVector<QString>vec;
vec<<"first"<<"sec"<<"third"<<"for"<<"fif"<<"first"<<"sec"
<<"third"<<"for"<<"fif";
vec<<"first"<<"sec"<<"third"<<"for"<<"fif"<<"first"<<"sec"
<<"third"<<"for"<<"fif";
for(int i = 0; i<ui->tableWidget->rowCount();i++)
{
for(int j = 0; j<ui->tableWidget->columnCount();j++)
{
if(j == 0)
{
QWidget* pWidget = new QWidget();
QPushButton* btn_edit = new QPushButton();
btn_edit->setText("Remove");
QHBoxLayout* pLayout = new QHBoxLayout(pWidget);
pLayout->addWidget(btn_edit);
pLayout->setAlignment(Qt::AlignCenter);
pLayout->setContentsMargins(0, 0, 0, 0);
pWidget->setLayout(pLayout);
ui->tableWidget->setCellWidget(i, j, pWidget);
continue;
}
QTableWidgetItem*item = new QTableWidgetItem(vec[i]);
item->setFlags(item->flags() ^ Qt::ItemIsEditable);
ui->tableWidget->setItem(i, j, item);
}
}
}
This task can be solved using the removeRow() method but before we must get the row. First of all we will connect all the buttons to a slot inside the loop as shown below:
*.h
private slots:
void onClicked();
*.cpp
[...]
QPushButton* btn_edit = new QPushButton();
btn_edit->setText("Remove");
connect(btn_edit, &QPushButton::clicked, this, &MainWindow::onClicked);
[...]
In the slot we can get the button that emits the signal through the sender() method, then we get QWidget parent (created with the name pWidget), this is the widget that is added to the QTableWidget and its position is relative to it, then we use the method indexAt() to get the QModelIndex associated with the cell, and this has the information of the row through the method row(). All of the above is implemented in the following lines:
void MainWindow::onClicked()
{
QWidget *w = qobject_cast<QWidget *>(sender()->parent());
if(w){
int row = ui->tableWidget->indexAt(w->pos()).row();
ui->tableWidget->removeRow(row);
ui->tableWidget->setCurrentCell(0, 0);
}
}
Note: The setCurrentCell() method is used to set the focus since the last cell that has it has been deleted.
The complete example can be found in the following link.
When you are creating QPushButton just add :
btn_delete = new QPushButton("Remove", ui->tableWidget);
btn_delete->setObjectName(QString("%1").arg(ui->tableWidget->rowCount()));
connect(btn_delete, SIGNAL(clicked()), this, SLOT(CellButtonDeleteClicked()));
And create function CellButtonDeleteClicked()
void CellButtonDeleteClicked()
{
// by this line I can get the sender of signal
QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
int row = pb->objectName().toInt();
ui->tableWidget->removeRow(row);
}

How can i add new row to the existing QTablewidget

Problem in getting mouseEvent on QTableWidget, this code is to create a window with tabelwidget and mouseclickevent, when i click right button of mouse then i got two action event options named "add" and "delete",
i want to add new rows with 3 columns when i click "add" event function, and delete the last row when i click on "delete" event function,
(sorry for my english), any help is appreciated.
#include "notepad.h"
#include <QMessageBox>
#include <QTableView>
#include <QMouseEvent>
Notepad::Notepad()
{
test() ;
add_action = new QAction(tr("Add cell"), this);
add_action->setIcon(QIcon("add.jpg"));
Delete_action = new QAction(tr("Delete cell"), this);
Delete_action->setIcon(QIcon("delete.jpg"));
connect(Delete_action, SIGNAL(triggered()), this, SLOT(Delete()));
connect(add_action, SIGNAL(triggered()), this, SLOT(add()));
centralWidget()->setAttribute(Qt::WA_TransparentForMouseEvents);
centralWidget()->setAttribute(Qt::WA_MouseTracking,true);
setMouseTracking(true);
}
void Notepad::test()
{
QTableWidget* table = new QTableWidget();
QTableWidgetItem* tableItem = new QTableWidgetItem();
table->setRowCount(1);
table->setColumnCount(3);
table->setItem(0,0,new QTableWidgetItem());
table->setItem(0,1,new QTableWidgetItem());
table->setItem(0,2,new QTableWidgetItem());
table->setMouseTracking(true);
table->viewport()->setMouseTracking(true);
table->installEventFilter(this);
table->viewport()->installEventFilter(this);
table->setSelectionBehavior(QAbstractItemView::SelectRows);
table->setSelectionMode(QAbstractItemView::SingleSelection);
tableItem->setFlags(tableItem->flags() ^ Qt::ItemIsEditable);
table->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
setCentralWidget(table);
}
void Notepad::mouseReleaseEvent (QMouseEvent * event )
{
QMessageBox* msgBox;
if(event->button() == Qt::RightButton)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
QMenu *menu = new QMenu(this);
menu->addAction(add_action);
menu->addAction(Delete_action);
menu->exec(mouseEvent->globalPos());
}
}
void Notepad::add()
{
QTableWidget* table = new QTableWidget();
test();
table->setColumnCount(3);*/
int newRow = table->rowCount();
int newcol = table->columnCount();
qDebug() << newRow;
for (int row ; row < newRow+1 ; ++row)
{
QWidget *parent;
QStyleOptionViewItem option;
for (int column = 0; column < 3; ++column)
{
table->insertRow( table->rowCount());
table->insertColumn( newcol );
}
}
setCentralWidget(table);
centralWidget()->setAttribute(Qt::WA_TransparentForMouseEvents);
setMouseTracking(true);
}
void Notepad::Delete()
{
QTableWidget* table = new QTableWidget();
add();
int row=table->rowCount();
if (int i= row){
table->removeRow(i);
}
setCentralWidget(table);
centralWidget()->setAttribute(Qt::WA_TransparentForMouseEvents);
setMouseTracking(true);
}
You have 2 questions in one: how to create a context menu and how to add a row.
How to create a context menu.
Step 1: create a menu once. In constructor, for example.
// _menu is a class member.
_menu = new QMenu(this);
_menu->addAction(add_action);
_menu->addAction(Delete_action);
Step 2: show it in corresponding event:
void Notepad::contextMenuEvent(QContextMenuEvent *event)
{
_menu->exec(event->globalPos());
}
How to add a row.
At first, you need a table as a class member. Why do you create a new instance every time? They are different objects! You create a new table widget on each add call!
At second, you need to increase rows count and to fill a new row:
void Notepad::add()
{
const int newIndex = _table->rowCount();
_table->setRowCount(newIndex + 1);
// Fill data in row with index newIndex.
...
}

Qt couting checked buttons made dynamically

I am trying to count how many buttons have been checked
void pracownik2::on_pushButton_4_clicked()
{
this->setWindowTitle("EKRAN");
QWidget *centralWidget = new QWidget;
int licznik=1;
QString licz;
QString kolumny = ui->lineEdit->text();
QString wiersze = ui->lineEdit_2->text();
QPushButton *button[wiersze.toInt()][kolumny.toInt()];
QGridLayout *controlsLayout = new QGridLayout;
for(int i=0;i<wiersze.toInt();i++)
{
for(int j=0;j<kolumny.toInt();j++)
{
licz = QString::number(licznik);
licznik++;
button[i][j] = new QPushButton(licz);
button[i][j]->setCheckable(1);
controlsLayout->addWidget(button[i][j], i, j);
}
}
QPushButton *okej = new QPushButton("Zatwierdź");
QPushButton *anul = new QPushButton("Anuluj");
controlsLayout->addWidget(okej, wiersze.toInt(), 0);
controlsLayout->addWidget(anul, wiersze.toInt(), 1);
controlsLayout->setHorizontalSpacing(0);
controlsLayout->setVerticalSpacing(0);
centralWidget->setLayout(controlsLayout);
setCentralWidget(centralWidget);
for(int i=0;i<wiersze.toInt();i++)
{
for(int j=0;j<kolumny.toInt();j++)
{
connect(button[i][j],SIGNAL(toggled(bool)),this,SLOT(tescik()));
}
}
connect(anul,SIGNAL(clicked()),this,SLOT(close()));
connect(okej,SIGNAL(clicked()),this,SLOT(okay2()));
}
void pracownik2::tescik()
{
miejsca++;
}
void pracownik2::okay2()
{
QString m=QString::number(miejsca);
QMessageBox::information(this,"elo","wybranych miejsc: " + m);
}
If i check buttons number 1,2,3 and press okay button it shows that 3 buttons have been checked BUT if I check button number 1 and uncheck it and press okay it shows that 2 buttons have been checked. How to make my variable increment only if I check button, not also when I uncheck it?
I'm sorry for the code edit, just couldn't make it look better
The signal toggled has a boolean parameter, add it to your slot, and adjust count according to it. Change connect:
connect(button[i][j],SIGNAL(toggled(bool)),this,SLOT(tescik(bool)));
And change slot:
void pracownik2::tescik(bool t) {
if (t) miejsca++;
else miejsca--;
}