QTableWidget edit only one column and leave the rest non-editable - qt

In QT 4.7, I am trying to make one QTableWidgetItem in a QTableWidget Editable and the rest all columns should be read only for me. I am having problems here.
I have checked a number of samples through google and stackoverflow but failed to achieve this. Some of the options I tried are,
I create rows by calling insertRow(rownumber) for adding rows.
Trial 1: I do the following while inserting a row dynamically
Enable Edit triggers in the UI Dialog
Add columns using the following code for disabling edit
QTableWidgetItem qit("");
qit.setflags(qit.flags() & ~Qt::ItemIsEditable)
qtable.setitem(row,column, &qit);
And for others columns I don't set the flags
This above approach did not work. I am able edit all columns (even the one I negated the editable option)
Trial 2:
Do all the above with just qtable.setEditTriggers(Qt::NoEditTriggers) and then set the columns editable wherever required.
But this option renders all columns non-editable.
But I don't see anyone complaining like this in any forums. So I must be making some stupid mistake.
Have someone come across such an issue, if yes please help by answering.

Working example of QTableWidget
First item in added row is editable, second one is not editable.
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Prepare layout
QMainWindow *window = new QMainWindow;
QTableWidget *tablewidget = new QTableWidget;
window->setCentralWidget(tablewidget);
// Add data
tablewidget->insertRow(0);
tablewidget->insertColumn(0);
tablewidget->insertColumn(1);
QTableWidgetItem *item;
item = new QTableWidgetItem("editable");
tablewidget->setItem(0,0,item);
item = new QTableWidgetItem("non editable");
item->setFlags(item->flags() & ~Qt::ItemIsEditable); // non editable
tablewidget->setItem(0,1,item);
window->show();
return a.exec();
}

Related

Reading QTableView row contents with the same order as are seen NOT stored

We have a QTableView which are filled with some arbitrary data. User can reorder rows of the table by make verticalHeader moveable. Here is a sample code:
#include <QApplication>
#include <QTableWidget>
#include <QDebug>
#include <QVBoxLayout>
#include <QPushButton>
#include <QHeaderView>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QWidget base;
QTableWidget* tablWid = new QTableWidget(&base);
tablWid->verticalHeader()->setSectionsMovable(true);
tablWid->verticalHeader()->setDragEnabled(true);
//////////////////////////////////////////////////////////////////////////
// Fill the model with some data
tablWid->model()->insertColumn(0);
tablWid->model()->insertRows(0,10);
for (int i = 0; i < 10; ++i)
tablWid->model()->setData(tablWid->model()->index(i, 0), "Item " + QString::number(i));
//////////////////////////////////////////////////////////////////////////
QPushButton* dumpButton = new QPushButton("Dump Model", &base);
QObject::connect(dumpButton, &QPushButton::clicked, [tablWid]()->void {
for (int j = 0; j < tablWid->model()->rowCount();++j){
qDebug() << tablWid->model()->index(j, 0).data().toString();
}
});
QVBoxLayout* baseLay = new QVBoxLayout(&base);
baseLay->addWidget(tablWid);
baseLay->addWidget(dumpButton);
base.show();
return a.exec();
}
We want to read cell contents in the same order as are seen in the QTableView (as seen in the view NOT stored in the model). Currently by calling model->data() we access the cell contents as are stored in the model NOT as seen in the view (ordered are changed by vertical section moves).
How is it possible to read cell contents such this way?
So if I understood it correctly you want to reorder the columns by moving the headers and then want to know how the view looks like.
I believe ( 90% certain ) when you reorder the headers it does not trigger any change in the model! and then if you just start printing the data of the model you will only see the data in the order how it was initially before you swapper/reordered some column with the header.
But you can maintain your own little data structure maintaining the order of the headers and when you will reorder a header the slot columnMoved() will be invooked at that point of time you can utilize the method columnViewportPosition to figure out the positions of all the columns and update your small data structure storing the order of the columns.
So while printing the data you should always assume that headers are in the order as in your own data structure.
Hope that will do what you are looking for!

Is there any way to disable QListWidgetItem in my QListWidget?

I am using QListWidgetItem to add Items in my QListWidget.
In some situations, I want some rows of my QListWidget become non selectable. (I mean I want some QListWidgetItem to be non selectable)
Is ther any way to do this?
PS: I tried
listWidgetItem->setFlags(Qt::NoItemFlags)
listWidgetItem->setSelected(false);
but they don't disable the selection of items.
Edit:
QStringList _strListClients = _strClients.split(",",QString::KeepEmptyParts,Qt::CaseInsensitive);
for(int i = 0; i < _strListClients.count(); i++)//Add Client's Check Boxes
{
QListWidgetItem* _listWidgetItem = new QListWidgetItem(_strListClients[i], listWidgetClients);
listWidgetClients->addItem(_listWidgetItem);
if(_strListClients[i] == "Unknown"){
_listWidgetItem->setSelected(false);
_listWidgetItem->setTextColor(Qt::red);
_listWidgetItem->setFlags(_listWidgetItem->flags() & ~Qt::ItemIsSelectable);
}
}
Just remove the Qt::ItemIsSelectable flag from each item:
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
Or remove Qt::ItemIsEnabled if you want to remove all interaction with the item.
E.g.
#include <QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QListWidget widget;
for (int i = 0; i < 100; ++i) {
QListWidgetItem *item = new QListWidgetItem(QStringLiteral("Item %1").arg(i));
if (i % 2 == 0) // disable one every two
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
widget.addItem(item);
}
widget.show();
return app.exec();
}
You can try the following:
1) Override the clicked/selection event (sorry I don't remember the exact name.
Doing so you can have some sort of flag/bool value on the item, and if is set as not being selectable you just return.
2) Rather then override you just connect to the signal and perform the above check and if you don't want to select that item you un-select it afterwards.
A bit of a work around but I don't know if there is a built in way to do so.
Checking the documentation I did not see a disable method on the item itself.
If you go down the road of list view you should have more control on that, also on the display, so you might be able to displayed it greyed etc. A view is a bit more work though.
M.

QTableWidget memory leak or not?

Suppose I have a 2D array full of data say 10 x 10. The contents, as well as a number of rows, can change any time.
Now I want to display this data in a QTableWidget.
I use a timer with time out 1sec to refresh the table contents. In the timeout slot if I use
void slot_timeOut()
{
//Iterate over the rows
//and for each cell do something like
ui->tw_data->setItem(row, 0, new TableWidgetItem(data[row][0]);
ui->tw_data->setItem(row, 0, new TableWidgetItem(data[row][1]);
//...
ui->tw_data->setItem(row, 0, new TableWidgetItem(data[row][9]);
}
the use out new TableWidgetItem worries me. I have no reference to it and I never delete it.
Over a period of time is this a memory leak, or is this managed by Qt, pls help...
There is no leak, as
The table takes ownership of the item.
(From QTableWidget::setItem()).
Ownership here means that the QTableWidget will take care of deleting the item when its not longer needed, or the QTableWidget itself is destroyed. Ownership is usually documented in the Qt documentation (if not, I'd consider that a Qt bug).
Once setItem() returns from being called on the same cell, the previously set QTableWidgetItem will be deleted:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QTableWidget widget(2, 1);
QTableWidgetItem* foo = new QTableWidgetItem("Foo");
widget.setItem(0, 0, foo);
qDebug() << foo->text(); //works
widget.setItem(0, 0, new QTableWidgetItem("Bar")); //replaces foo with bar and deletes foo
qDebug() << foo->text(); // Undefined (usually, crash)
widget.show();
return app.exec();
}
If you're on Linux, you can also verify the behavior by running above code (without the second qDebug()) in valgrind with --leak-check=full.
From the Qt documentation:
void QTableWidget::setItem ( int row, int column, QTableWidgetItem *
item ) Sets the item for the given row and column to item. The table
takes ownership of the item.
This indicates that Qt will manage the memory for the object as necessary.
It will delete properly when the you add Q-objects to the cells.
I was pushing thousands of C-strings in cells and watched my memory blow up.
Made my "raw text data" a QString and my problem was solved.
Such problem takes place to be: Qt does not really clear the memory allocated through QTableWidgetItem.
for( int row = 0; row < 35; row++)
{
for(int i = 0; i < 9; i++)
{
QTableWidgetItem* item = new QTableWidgetItem();
item->setText(QString::number(i));
ui->tableWidget->setItem(row, i, item);
}
}
This code gives 116 bytes of leakage.
We found this solution: Instead of QTableWidgetItem, you can use QLineEdit:
QLineEdit* tableline = new QLineEdit();
m_qtablewidget->setCellWidget(row, column, tableline);
p.s. To search for leaks used Dr.memory

Qt How to check state checkbox in QtableWidget

Recently I found the way that checkbox places in the middle of QtableWidget item.
However, I do not know how to check state whether or not button is clicked.
Could you tell me how to check button state?
here is what Ive found code:
QWidget *pWidget = new QWidget();
QCheckBox *pCheckBox = new QCheckBox();
QHBoxLayout *pLayout = new QHBoxLayout(pWidget);
pCheckBox->setCheckState(Qt::Checked);
pLayout->addWidget(pCheckBox);
pLayout->setAlignment(Qt::AlignCenter);
pLayout->setContentsMargins(0,0,0,0);
pWidget->setLayout(pLayout);
ui->tableWidget2->setCellWidget(2,2, pWidget);
Although this is very late you can solve it like this:
auto field = ui->tableWidget2->cellWidget(2, 2, pWidget);
std::cout << qobject_cast<QCheckBox*>(field)->isChecked() << std::endl;
This works for other types as well (QComboBox etc.). Although it would probably be better to just use the checkbox functionality that QTableWidgetItem already has.
This example might not work if you are using a tristate checkbox in which case you should call: checkState() and compare it to Qt::CheckState. If qobject_cast<T> does not work out you can use a reinterpret_cast<T>.
I assume you created your checkboxes in the QWidgetTable like this:
int row...;int column...;
...
QTableWidgetItem *checkBoxItem = new QTableWidgetItem();
checkBoxItem->setCheckState(Qt::Unchecked);
ui->Table->setItem(row, column, checkBoxItem);
You can check the status of the item that corresponds to your widget in another function like this:
void MainWindow::on_Table_cellClicked(int row, int column)
{
QTableWidgetItem *checkBoxState = ui->Table->item(row, column);
if(ui->Table->item(row,column)->checkState())
{
checkBoxState->setCheckState(Qt::Unchecked);
ui->Table->setItem(row, column, checkBoxState);
}
else
{
checkBoxState->setCheckState(Qt::Checked);
ui->Table->setItem(row, column, checkBoxState);
}
}

QStandardItemModel inside Qtableview

I am using QStandardItemModel inside QTableView. Here i have two button & Qtableview inside my mainwindow.
I need only 4 columns inside this. And rows will vary. The two Buttons will be used to add/delete a row (test case).
setHorizontalHeaderItem is not showing all the text(means all text is not visible). Example if i put 'Text for the Employee Name' it is not fully visible ?
How to make QStandardItemModel occupy full QTableview (width). At present it is showing at top left corner ?
How to achieve it?
Code :
model= new QStandardItemModel(4, 4);
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 4; ++column) {
QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
model->setItem(row, column, item);
}
}
model->setHorizontalHeaderItem(0, new QStandardItem(tr("Time")));
model->setHorizontalHeaderItem(1, new QStandardItem(tr("Text for the Employee Name")));
model->setHorizontalHeaderItem(2, new QStandardItem(tr("Text for the Employee Address")));
model->setHorizontalHeaderItem(3, new QStandardItem(tr("Text for the Employee Date of Birth")));
model->setVerticalHeaderItem(0, new QStandardItem(tr("Test-Case-----1")));
tableView->horizontalHeader()->setStretchLastSection(true);
or
tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
As the question is already accepted for the answer, my answer may help someone, as the above accepted answer didn't help me.
QStandardItemModel *model = new QStandardItemModel(2,3,this);
//----------
ui->tableView->setModel(model);
ui->tableView->resizeColumnsToContents();
I know the answer comes a bit late, but I was just needing to do the same, and figured out a different solution.
To achieve your goal in Qt 4, you need to adjust the settings of the header of your QTableView. To do so, first retrieve the header:
QHeaderView *header = ui->tableView->horizontalHeader();
Next, adjust the resize mode of the individual columns by calling QHeaderView::setResizeMode (the second flavor, which accepts logicalIndex):
header->setResizeMode(0, QHeaderView::ResizeToContents);
header->setResizeMode(1, QHeaderView::ResizeToContents);
header->setResizeMode(2, QHeaderView::ResizeToContents);
header->setResizeMode(3, QHeaderView::Stretch);
In the above example, I chose to stretch column 3, but you may choose any of the columns to be in "stretch" mode.
In Qt 5, the call you want is QHeaderView::setSectionResizeMode().
Hope this helps you or anybody else seeking a solution to this problem.

Resources