Undo for individual cells of QTableWidget in Qt? - c++

I have a QTableWidget in my Main Window class.
I am unable to find a functionality which will undo the text change for the specified cell.
What I want to do is:
void myCellUndoFunc(int row, int col)
{
table->item(row, col)->undo(); //table is my QTableWidget
}
The problem is that there is no such undo().
So my question is, can there be a workaround for this problem using maybe some foo-doo combination of SIGNAL's & SLOT's?
Thanks!
PS: Please do not suggest to use Model/View framework because I have used QTableWidget extensively in my application. Sorry for the same.

Maybe you should use the
void QTableWidgetItem::setData ( int role, const QVariant & value ) [virtual]
using the Qt::UserRole you are able to specify the last value. In your method u can access the previously set value with the data()-Method. The only thing you have to do is always keep the old value up-to-date.
Before you set the new value of the QTableWidgetItem
tw->setData(Qt::UserRole, tw->text())
and on undo u could than retrieve the data with
tw->setText(tw->data(Qt::UserRole).toString())
where "tw" is the current QTableWidgetItem using the contextmenu-event, the clicked-event or whatever u want. You could also subclass the QTableWidgetItem and handle this whole thing internally in your class, creating an undo()-method, storing the old value, etc.

Related

Making only one column of QTreeWidget editable // troubleshooting

Mind that this question isn't a duplicate of question Making only one column of a QTreeWidgetItem editable, as it's proposed solution doesn't work.
Hello, so I just want to make only ONE column of my treeWidget editable.
propertyItems.push_back(new QTreeWidgetItem); //gets filled by the while-loop
propertyItems[propertyItems.size()-1]->setText(0, prop.name); //sets the text of the item
propertyItems[propertyItems.size()-1]->setText(1, prop.value);//set the text of the other item
propertyItems[propertyItems.size()-1]->setFlags(Qt::ItemIsEditable);
ui->treeWidget_3->insertTopLevelItem(ui->treeWidget_3->topLevelItemCount(), propertyItems[propertyItems.size()-1]); //appends the items
counter ++;
and
void MainWindow::onTreeWidget3ItemDoubleClicked()
{
if (ui->treeWidget_3->currentColumn() == 2) {
ui->treeWidget_3->editItem(ui->treeWidget_3->currentItem(), ui->treeWidget_3->currentColumn());
}
}
is my approach. ontreeWidget3ItemDoubleClicked is connected with treeWidget::doubleClicked, treeWidget_3 has NO edit-triggers
BUT: when I execute the programm, the QTreeView is just grayed out.
That said, I also tried
propertyItems[propertyItems.size()-1]->setFlags(propertyItems[propertyItem.size()].flags | Qt::ItemIsEditable);
The treeWidget_3 isn't grayed off anymore, but it is still uneditable...
How can I fix this?
BTW: I am a newb to Qt so I might have forgotten something crucial. Sorry in this case.
As mentioned in the documentation:
The QTreeWidgetItem class provides an item for use with the QTreeWidget convenience class.
It means that it won't work for all use cases. The solution is to create your own model and overload the flags(const QModelIndex& index) method returning the appropriate values (basically Qt:: ItemIsEnabled for read-only columns and Qt:: ItemIsEnabled | Qt::ItemIsEditable for the editable one). You can get the column from index.column().
Qt provides an example to start with trees and models.

How do I get the new index of a moved column in a wxGrid?

I'm using wxWidgets 3.1.0 and I'm developing a Windows app in C++.
I'm using the base wxGrid and I've enabled column re-ordering via dragging them with the mouse (EnableDragColMove(true)). My problem now is that I need to get the moved column's new position/index after the column has been dragged to its new position.
Unfortunately, I could not find a way to do that from the available APIs.
I've tried catching the wxGridEvent wxEVT_GRID_COL_MOVE then using GetCol() and GetColPos() to check the column's new index:
gridDataList->Bind(wxEVT_GRID_COL_MOVE, &FormData::OnList_ColumnMove, this);
...
void FormData::OnList_ColumnMove(wxGridEvent& event)
{
int movedCol = event.GetCol();
int movedColPos = gridDataList->GetColPos(movedCol );
...
}
But it seems the event is triggered BEFORE the column is actually moved, so GetColPos() will still return the current column index, NOT the new index.
There seems to be no event to catch AFTER the column is moved.
My current solutions/workarounds are to:
Manually handle the column movement after catching the wxEVT_GRID_COL_MOVE event (as suggested in the wxWidgets docs) so that I can properly track the before and after index of the moved column.
Manually trigger a callback or a timer event after the column moves to its new position, similar to a wxPython workaround suggested in another SO post.
Though, I would like to know if there is a cleaner, less complicated way without resorting to the workarounds above.
Any suggestions are appreciated.
Yes, this wxEVT_GRID_COL_MOVE is generated before moving the column because it can be vetoed, preventing the move from happening. And it's true that it would be convenient if it carried the new column position, but unfortunately currently it doesn't (it would be simple to fix this and any patches doing this would be welcome!).
The standard workaround of using CallAfter() to execute your code at later time should work just fine without changing wxWidgets however. I.e., assuming you use C++11, you should be able to just write
void FormData::OnList_ColumnMove(wxGridEvent& event)
{
const int movedCol = event.GetCol();
CallAfter([movedCol]() {
int movedColPos = gridDataList->GetColPos(movedCol);
...
});
}

Replace QWidget with a new QWidget

This questions to me reeks of maybe a lack of understanding of C++, as the possibilities I've considered for my problem all seem to make no sense on why this could be occuring. Feedback appreciated.
I'm using the form designer to create a form class with a table in it. I'm trying to replace the table with another table generated in a helper class. I'm only doing this so I can (hopefully) maintain the nice grid layout I've designed, and through pointer manipulation, get the replacement I desire. Here's some code snippets from the table form constructor and relevant calls :
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
....
setup();
void setup(){
tableData = Utilities::createTable(this->file, tableDelim);
//createTable returns QTableWidget*
... other assignments, and label text updates, which seem to all work
}
My understanding is that tableData is a pointer, and if printed, will give the address of the QTableWidget from the layout. So then if I create a QTableWidget* and then assign tableData to that, tableData should now point to the new widget. Instead, I see only a blank screen.
I tried checking what the tableData pointer is before I assign it to the new QTableWidget*, and after. The second pointer shown is what is generated by createTable() :
QTableWidget(0x101272d40, name = "tableData") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
It seems the pointer is being reassigned, but the table drawn isn't the right one.
What gives?
My understanding is that you want to design the table layout in designer but fill in the data from an external source.
I would suggest, to just use the QTableWidget that is created in setupUi() and modify Utilities::createTable() such that it becomes Utilities::populateTable(QTableWidget & table, <all the other parameters you need>). (Or use QTableWidget * if you prefer - however I like putting the non-zero assertion responsibility on the caller...)
Apart from that, I agree with Sebastian Lange.
You are right with your assumption. You do set a variable to be a pointer to a object and next you set the variable to be a pointer to another object. You never change any objects, just your variable which is not used to display anything.
You would need to do something like:
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
parentLayout = tableData->parent()->layout(); //Get the parent widget to add another table.
parentLayout->removeWidget(tableData);
delete tableData;
parentLayout->addWidget(createTable());
You need to use pTheContainerOfTheOriginalTableWidget->addWidget(tableData); See here: http://qt-project.org/forums/viewthread/16547
Be sure you remove the original tableWidget so you don't have two (I assume you don't want two).
If I understand you correctly we have such situation.
call of setupUi (which generated by qt tootls),
there there is something like this(pseudo code):
oldTablePtr = new QTableWidget(parent);
someLayout->addWidget(oldTablePtr);
So parent and layout hold value of oldTablePtr.
And if you set variable oldTablePtr nothing changed.
parent send QPaintEvent to oldTablePtr.
So you need call delete oldTablePtr, that remove this widget from list of childs of parent, and move newTablePtr to the same layout.
There's no need to replace it in code, you can do it in Qt Designer. Just place QTableWidget on form, then rightclick it and choose Promote widget in menu, then you will need just enter your classname.
Currently I don't have Qt Designer near me, so edits will be appreciated.

wxGrid shows the old value instead of new value after user edits a cell

I created the wxGrid in editablemode. I registered the following event handler.
class ReadWriteGrid : public wxGrid
{
public:
ReadWriteGrid(wxWindow *parent, wxWindowID ID,
const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize,
long style=262144, const wxString &name=wxGridNameStr)
: wxGrid(parent, ID, pos, size, style, name)
{
SetEditable();
}
};
EVT_GRID_CELL_CHANGE(IndexTableFrame::OnEditField)
Now when user changes the cell value my function gets called but after it completes. The cell value changes back to its old value.
void IndexTableFrame::OnEditField(wxGridEvent& event)
{
int RowNumber;
int ColNumber;
wxString type;
wxGridCellEditor *m_Editor;
wxString NewValue;
RowNumber = event.GetRow();
ColNumber = event.GetCol();
m_Editor = m_grid->GetDefaultEditorForCell(RowNumber,ColNumber);
NewValue = m_Editor->GetValue();
m_Editor->Destroy();
m_grid->SetCellValue(NewValue,RowNumber,ColNumber);
event.skip();
}
This is the first time I am using WxWidget. I am not sure how to avoid the cell from changing back to its old value.
You are working too hard! Relax and let wxGrid take the strain.
The simplest thing to do is to do nothing. wxGrid will accept user edits in cells and display the changes without you having to do anything. When the user is finished, he can click a button SAVE, where you can implement code to read the values from the cells and use them for whatever you need.
In many applications, one has to do processing on the cell value on the fly as the user changes it, (for example to update other on-screen controls on the fly based on the new cell values; or to send data via a serial port to another device immediately as the cells are changed).
Requiring the user to click a separate "save button" as suggested above is not a solution that will be acceptable to users in many use cases.
I can confirm the observations by the original poster: If you create a wxGrid and attach either wxEVT_GRID_CELL_CHANGED, wxEVT_GRID_CELL_CHANGING, or wxEVT_GRID_EDITOR_HIDDEN events to it, a call to grid->GetCellValue(row,col); returns the old value. The event parameter to the handler function also does not contain the new text. It looks like a "feature" of wxGrid.
You should create your own class inherited from wxGridTableBase.
Then you should attach your grid table object to the wxGrid, using it's SetTable method.
wxGrid object will use your table's methods (GetValue, SetValue) to retrieve and store data.
There's a grid sample shipped with wxWidgets, that will help you understand how does wxGrid work.

Addressing QTableWidget Columns

I am a student programmer and have been building a GUI in Qt for my company. I am writing a member function SetData to basically act as an intermediary between my Ui elements and member variables. In this particular Ui I am using a QTableWidge. I can't seem to find out exactly how to set each column to a variable.
For instance if I have the column Name in my QTableWidget, and Name is the first column I can't access it using the traditional array parameters. The documentation from Qt is really hazey as to how to address this.. It could also be that I am still too amateur to understand how to use the class's member functions to achieve the results I want here.
To clarify I am trying to define a data type for an entire column. For instance my first column; Name, would be a variable that I have created which is a QString data type. and SetData would pass it to eventually a QVector or QList. Here is the code I have typed up so far to kinda give an Idea of what I thought I could do.
void InjectionDialog::setData(InjectionData &setDataStruct)
{
/*The following setData functions assists in creating a new instance of
the Injection dialog with whatever values are passed to setDataStruct*/
QString str;//created str to make datatype conversion
ui->lineEditFluidVelocity->setText(str.setNum(setDataStruct.lineEditFluidVelocity));
ui->lineEditFluidMassFlow->setText(str.setNum(setDataStruct.lineEditFluidMassFlow));
ui->lineEditFluidArea->setText(str.setNum(setDataStruct.lineEditFluidArea));
ui->lineEditFluidTemperature->setText(str.setNum(setDataStruct.lineEditFluidTemperture));
ui->lineEditFluidPressure->setText(str.setNum(setDataStruct.lineEditPressure));
ui->lineEditParticleManual->setText(str.setNum(setDataStruct.lineEditManualParticlesPerCell));
ui->lineEditParticleVelocity->setText(str.setNum(setDataStruct.lineEditParitcleVelocity));
ui->lineEditParticleMassFlow->setText(str.setNum(setDataStruct.lineEditParticleMassFlow));
ui->lineEditParticleArea->setText(str.setNum(setDataStruct.lineEditParticleArea));
ui->lineEditParticleTemperature->setText(str.setNum(setDataStruct.lineEditParticleTemperture));
ui->tableWidgetInjectionLocations //this is where I got stuck
}
I know that QTreeView has the option to set items by delegating columns but I need these fields to be able to be edited. I could be going about this all wrong in handling my QTableWidget; if so I appreciate any advice in how to appropriately handle this Widget.
After some research and trial and error through QTableWidgetItem; I found what I was looking for. As I said earlier I needed to write a setData function to provide a way to set each cell to some specified data using QTableWidget. QTableWidget uses setItem to set each item to a QTableWidgetItem. Knowing this I just filled in the purpose. Here's what I did; This is right after my main code.
for(int i=0; i<setDataStruct.qTableWidegetlocations.size(); i++)
{
QTableWidgetItem *qTableWidgetItemInjectionName = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsInjectionName);
ui->tableWidgetInjectionLocations->setItem(i,0, qTableWidgetItemInjectionName);
QTableWidgetItem *qTableWidgetItemInjectionOnOff= new QTableWidgetItem((setDataStruct.qTableWidegetlocations[i].locationsInjectionOnOff));
ui->tableWidgetInjectionLocations->setItem(i,1, qTableWidgetItemInjectionOnOff);
QTableWidgetItem *qTableWidgetItemInjectionX = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsX);
ui->tableWidgetInjectionLocations->setItem(i,2, qTableWidgetItemInjectionX);
QTableWidgetItem *qTableWidgetItemInjectionY = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsY);
ui->tableWidgetInjectionLocations->setItem(i,3, qTableWidgetItemInjectionY);
QTableWidgetItem *qTableWidgetItemInjectionZ = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsZ);
ui->tableWidgetInjectionLocations->setItem(i,4,qTableWidgetItemInjectionZ);
QTableWidgetItem *qTableWidgetItemInjectionnx = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsnx);
ui->tableWidgetInjectionLocations->setItem(i,5,qTableWidgetItemInjectionnx);
QTableWidgetItem *qTableWidgetItemInjectionny = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsny);
ui->tableWidgetInjectionLocations->setItem(i,6,qTableWidgetItemInjectionny);
QTableWidgetItem *qTableWidgetItemInjectionnz = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsnz);
ui->tableWidgetInjectionLocations->setItem(i,7,qTableWidgetItemInjectionnz);
QTableWidgetItem *qTableWidgetItemInjectionTemperature = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsTemperature);
ui->tableWidgetInjectionLocations->setItem(i,8,qTableWidgetItemInjectionTemperature);
QTableWidgetItem *qTableWidgetItemInjectionWeight = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsWeight);
}
Thanks For Reading