Getting QTableWidgetItem out of cellWidget()'s QCheckBox - qt

I'm storing QCheckBox in QTableWidget, in following way:
QCheckBox *checkBox = new QCheckBox();
QWidget *widget = new QWidget();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0,0,0,0);
widget->setLayout(layout);
tableWidget->setCellWidget(row, 2, widget);
Then, I catch stateChanged() of the checkBox:
connect( checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int)) );
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if( !box ) {
return;
}
}
Now, I can get to QTableWidget – it is box->parent()->parent()->parent(). Object before that, i.e. box->parent()->parent(), is qt_scrollarea_viewport (that's objectName()). I've searched children of the "viewport", and there's 16 QWidgets – the number of rows in my table. However, their children are only QHBoxLayout and QCheckBox. There apparently is no reference to QTableWidgetItem – it looks like if I were in some parallel object hierarchy, and QTableWidgetItem is in other hierarchy. Is that true? How to get the item?

See this question: How to work with signals from QTableWidget cell with cellWidget set
Adapted to you case:
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if (box)
{
int row = box->property("row").toInt();
int column = box->property("column").toInt();
QTableWidgetItem* item = tableWidget->item(row, column);
}
}

Related

Problem adding QPushButtons to my app. When I run the code, only the last button is placed in my window. The previous 8 are being overwritten

This is what I have so far. When I run the app, the last button in the array gets placed which means that the previous 8 are being stepped on.
QWidget *qwid = new QWidget(this);
QGridLayout *gl = new QGridLayout(qwid);
qwid->setLayout(gl);
QTabWidget *qtab = new QTabWidget();
qtab->addTab(qwid, "name");
QStringList buttonLbls({"button1", "button2", "button3:});
QHBoxLayout *hbox = new QHBoxLayout(qwid);
QPushButton *btnCount[3];
for(int i=0; i<3; i++)
{
btnCount[i] = new QPushButton(buttonsLbls[i], qwid);
hbox->addWidget(btnCount[i]);
qwid->setLayout(hbox);
}
You are setting two different layouts for the main widget. Remove the first (gl). Try to set the layout for the main widget and then add buttons:
qwid->setLayout(hbox);
for(int i=0; i<3; i++)
{
btnCount[i] = new QPushButton(buttonsLbls[i], qwid);
hbox->addWidget(btnCount[i]);
}
First you need to decide whether you want to have your buttons in a grid or not.
If you go with gridlayout then you can just add your widgets with the QGridLayout::addWidget and pass the correct row and column where the widget should go inside the grid. You won't need the separate horizontal layout in that case. Finally you set the gridlayout as the layout of your parent widget (qwid).
QWidget* qwid = new QWidget(this);
QGridLayout* gridLayout = new QGridLayout();
QStringList buttonLabels({"button1", "button2", "button3", "button4"});
QHash<QString, QPushButton*> buttons; // For storing button pointer for easy access
int columns = 2;
for (int n = 0; n < buttonLabels.size(); n++)
{
int column = n % columns;
int row = n / columns;
const QString& buttonLabel = buttonLabels.at(n);
QPushButton* button = new QPushButton(buttonLabel);
buttons[buttonLabel] = button;
gridLayout->addWidget(button, row, column);
}
qwid->setLayout(gridLayout);
An alternative is to use combination of horizontal and vertical layout where you create horizontal layout for each row (in a loop), add your widgets to the horizontal layout. Then add each horizontal layout inside a single vertical layout with addLayout function. Finally you set the vertical layout as the layout of your parent widget (qwid).
QWidget* qwid = new QWidget(this);
QVBoxLayout* verticalLayout = new QVBoxLayout();
QStringList buttonLabels({"button1", "button2", "button3", "button4"});
QHash<QString, QPushButton*> buttons; // For storing button pointer for easy access
int columns = 2;
int rows = columns / buttonLabels.size();
int index = 0;
for (int row = 0; row < rows; row++)
{
QHBoxLayout* rowLayout = new QHBoxLayout()
for (int col = 0; col < columns; col++)
{
const QString& buttonLabel = buttonLabels.at(index);
QPushButton* button = new QPushButton(buttonLabel);
buttons[buttonLabel] = button;
rowLayout->addWidget(button);
index++;
}
verticalLayout->addLayout(rowLayout);
}
qwid->setLayout(verticalLayout);
Another alternative is to just use the horizontal (or vertical) layout only and just add the widgets there and set the layout as the layout of your parent widget (qwid).
QWidget* qwid = new QWidget(this);
QHBoxLayout* horizontalLayout = new QHBoxLayout();
QStringList buttonLabels({"button1", "button2", "button3", "button4"});
QList<QPushButton*> buttons; // For storing button pointer for easy access
for (const QString& buttonLabel : buttonLabels)
{
QPushButton* button = new QPushButton(buttonLabel);
buttons << button;
horizontalLayout->addWidget(button);
}
qwid->setLayout(horizontalLayout);
It depends on what you actually want to do with your widgets.

How to move QWidget in QAbstractItemView?

I have a QComboBox, which has many items on it:
combo->addItem("def");
combo->addItem("abc");
Now I would like to add QWidget to one of my item, for example:
QPushButton *button = new QPushButton;
button->setStyleSheet("QPushButton {background:red}");
button->setFixedSize(10,10);
QModelIndex index = combo->model()->index(0,0);
combo->view()->setIndexWidget(index, button);
I set button's size to 10x10 ( of course my QComboBox is bigger ). And I would like to move this button to other place ( picture ).
You can try using layout
QPushButton *button = new QPushButton;
button->setStyleSheet("QPushButton {background:red}");
button->setFixedSize(10,10);
auto widget = new QWidget{this};
auto layout = new QHBoxLayout{widget};
layout->setContentsMargins(0, 0, 0, 0);
layout->addStretch();
layout->addWidget(button);
QModelIndex index = combo->model()->index(0,0);
combo->view()->setIndexWidget(index, widget);

Accessing aspects of QObject stored in QVector

I have a QVector of QObjects QVector<QWidget*> question_vector;. These widgets are questions. (My application is like a questionnaire thing).
When creating a questionnaire, question types are chosen from the selection on a comboBox, and within Questions class, the question is created, and stored in the QVector.
void CreateSurvey::comboBox_selection(const QString &arg1)
{
if(arg1 == "Single Line Text")
{
Question *singleLineText = new Question("Single Line Text");
surveyLayout->addWidget(singleLineText);
question_vector.append(singleLineText);
qDebug() << "Number of items: "<< question_vector.size();
} ...
}
void Question::create_singleLineEdit()
{
QVBoxLayout *vLayout = new QVBoxLayout;
QLabel *titleLabel = new QLabel("Title");
vLayout->addWidget(titleLabel);
QLineEdit *inputText = new QLineEdit;
vLayout->addWidget(inputText);
QLabel *commentsLabel = new QLabel("Comments");
vLayout->addWidget(commentsLabel);
QLineEdit *commentsText = new QLineEdit;
vLayout->addWidget(commentsText);
ui->frame->setLayout(vLayout);
}
This is what it looks like
The SingleLineEdit is the widget, the title, titleEdit, comments, commentsEdit.
How do I access, for example the text from an individual component of the widget, the commentsText QLineEdit?
Cast the element to the a QLineEdit:
QLineEdit *line_edit = dynamic_cast <QLineEdit *> (question_vector[3]);
if (line_edit)
{
QString text = line_edit->text();
}
This is a basic aspect of C++ programming; you probably should do some reading on C++ classes, how to derive them, how to use base class pointers and derived class pointers, and so on.
I think I've managed to solve what I was trying to do (at least partly)
So I had here
void Question::create_singleLineEdit()
{
QVBoxLayout *vLayout = new QVBoxLayout;
QLabel *titleLabel = new QLabel("Title");
vLayout->addWidget(titleLabel);
QLineEdit *inputText = new QLineEdit;
vLayout->addWidget(inputText);
QLabel *commentsLabel = new QLabel("Comments");
vLayout->addWidget(commentsLabel);
QLineEdit *commentsText = new QLineEdit;
vLayout->addWidget(commentsText);
ui->frame->setLayout(vLayout);
}
What I did was changed stuff like QLineEdit *commentsText = new QLineEdit; to
section_commentsText = newLineEdit; - Having QTextEdit *section_commentsText in my question.h.
I was then able to do
Question *object = question_vector[0];
QString text = object->section_commentsText->text();
qDebug() << text;

Synchronize QTableWidget cell with widget in the center of the cell

I use QCheckBox in QTableWidgetCell
QWidget *widget = new QWidget();
QCheckBox *checkBox = new QCheckBox();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(layout);
table->setCellWidget(0, 0, widget);
The result of this code is a cell with checkbox in the center.
I need to make checkbox reaction to mouse moving and clicking in the empty area like when cursor is under checkbox.
If you dont want the fullblown functionality of QCheckBox but just the checkmark, You can use a simple QTableWidgetItem and modify his checkstate.
QTableWidgetItem* item = new QTableWidgetItem();
item->setCheckState(Qt::Unchecked);
table->setItem ( 0, 0, item );
connect(table, SIGNAL(cellClicked(int , int )), this, SLOT(OnClicked( int, int)));
void OnClicked( int row, int column )
{
if(row != checkablelerow && col != checkablelecol )
return; // or do something else
item = table->item(row, column);
item->setCheckState(item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked);
}
Now the whole cell will be checkable. Code may need refinement.
You can override eventFilter method to highlight your checkbox when cursor enters the cell. http://qt-project.org/doc/qt-4.8/qobject.html#eventFilter
bool ExampleDialog::eventFilter(QObject *obj, QEvent *event)
{
if (qobject_cast<QTableWidgetItem*>(object)) {
if (event->type() == QEvent::HoverEnter) {
QCheckBox* qcb = object->findChild<QCheckBox*>();
//here you can do something to highlight your checkbox
return true;
}
else if(event->type() == QEvent::HoverLeave){
QCheckBox* qcb = object->findChild<QCheckBox*>();
//here you have to stop highlighting checkbox
return true;
}
else {
return false;
}
}
}
After overriding, you have to install event filter on your widgets like this
widget->installEventFilter(this); //this points to parent of the widget, the exampleDialog
And use a clicked slot of QTableWidgetItem* to set your checkbox checked.
void QTableWidgetItemClicked( int row, int column )
{
QCheckBox* qcb = QObject::sender()->findChild<QCheckBox*>();
qcb->setChecked(!qcb->isChecked());
}
Remember to connect QTableWidgetItems signals to slots.

QListView and delegate display unintended item

I've a problem with my QListView, it paint an unintended item on the top left of the QListView :
http://s4.postimage.org/64orbk5kd/Screen_Shot_2013_02_14_at_20_23_14.png
I use a QStyledItemDelegate in my QListView :
m_stringList.push_back("FIRST");
m_stringList.push_back("SECOND");
m_stringList.push_back("THIRD");
m_model.setStringList(m_stringList);
ui->processesListView->setFlow(QListView::LeftToRight);
ui->processesListView->setModel(&m_model);
ui->processesListView->setItemDelegate(new ProcessItemDelegate(this, ui->processesListView));
The delegate (ProcessItemDelegate) paint method use a custom QWidget to display the information :
void ProcessItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex &inIndex ) const
{
_listItem->setContent(_listView->model()->data(inIndex).toString());
painter->save();
painter->translate(option.rect.center());
_listItem->render(painter);
painter->restore();
}
The setContent method of the QWidget is very simple :
void ProcessItem::setContent(const QString &s)
{
ui->processId->setText(s);
}
I have another way to add a widget to some list using a QListWidget.
For example knowing that ui->historyView is a QListWidget element and HistoryElementView a subclass of QWidget.
void View::onHistoryChanged(const QList<HistoryElement> &history)
{
clearHistory();
foreach(HistoryElement elt, history)
{
HistoryElementView *historyViewElement = new HistoryElementView(elt.getDateTime("dd/MM/yyyy - hh:mm"), elt.getFilename());
QListWidgetItem *item = new QListWidgetItem();
ui->historyView->addItem(item);
ui->historyView->setItemWidget(item, historyViewElement);
}
}
void View::clearHistory()
{
QListWidgetItem *item;
while (ui->historyView->count() != 0)
{
item = ui->historyView->takeItem(0);
delete item;
}
}
You do not need to delete the widgets inside your QListWidgetItem, it will be handle by Qt.
Once your widgets are inside the list, you can retrieve them using :
// Using index
QListWidgetItem *item = ui->historyView->item(0);
HistoryElementView *elt = qobject_cast<HistoryElementView *>(ui->historyView->itemWidget(item));
// Using position
QListWidgetItem *item = ui->historyView->itemAt(pos);
HistoryElementView *historyElement = qobject_cast<HistoryElementView *>(ui->historyView->itemWidget(item));
Hope it helps.

Resources