I have a QtableWidget. When an "Add" button is clicked, I added a new row to the table. The cells each row contain some custom widgets.
void addRow() {
tableWidget->insertRow(tableWidget->rowCount());
int itemRow = tableWidget->rowCount() - 1;
// create custom widgets for each column
tableWidget->setCellWidget(itemrow, columnNumber, customWidget);
}
Everything works fine. The only problem is that the last row that is seems to have slightly different size/margin/padding etc. So the widgets in each column are slightly misaligned compared to the previous rows.
When another row is added, what was previously the last row now appears fine. Its always the last row added, that "looks" slightly different.
Is there something I need to do after adding the row?
Related
Hello I'm using a QTableWidget and essentially have code such that the first column will allow the table to grow/shrink dynamically. The last populated row's first cell will have a Plus button to add a new row that can be edited and the Minus button will remove its corresponding button's row. For example, If I click the Plus button 5 times, it will be at the 6th row and the previous 5 rows will all have a Minus buttons to remove their row. If the cell's row has a Minus button on it, the row is implied editable, otherwise not. However, I allow the table to have a default amount of rows, such that it can never visually shrink less than 5, for example, even if it's technically "empty". To edit the row, you need to hit the Plus button which will check if we need to insert a new row, for example if we're at 5 rows and the base row size is 5, then we need a new row and to populate each column's index of the new row.
The main reason for this table is to read and write the table's information to a QSettings and be able to import the past exported information to the same cells and essentially restore the table's state as it appeared last. However, when reading from the QSettings, the table will crash after all cells are populated correctly with the information and I can tell they are correctly populated because the debugger will freeze the GUI and I can visually see and qDebug() how far into the loop of the QSettings array I got to before seg-faulting.
Now when I do everything manually, such as clicking the Plus button, everything is fine and the program performs as expected.
//newRowCount is assumed to be the amount of rows with Minus Buttons currently, only creates a new row if the table needs to expand
void TableTest::enableNewRow(){
newRowCount++;
if(newRowCount > table->rowCount()){
table->insertRow(table->rowCount());
for(int i = 0; i < table->columnSize(); ++i){
QTableWidgetItem* item = new QTableWidgetItem;
item->setFlags(item->flags() ^ Qt::ItemisEditable);
table->setItem(newRowCount, i, item);
//Code to set the previous column's item (newRowCount--) to have an Qt::ItemisEditable flag set to true
...
}
}
//Some button setup to make Plus button and create a new Minus button connect and do their jobs and move the Plus button down into the newly inserted row
...
}
void MainWindow::importFile(){
int settingRows = settings->beginReadArray("Groups");
for(int i = 0; i < settingRows; ++i){
settings->setArrayIndex(i);
//Will only add a new row if needed, check inside above function and all row items will be allocated if made
table->enableRow();
for(int j = 1; j < table->columnCount(); ++j){
table->item(i, j)->setText("testing");
}
}
}
And the program crashes with the following stack trace:
1 QWidget::show()
2 QAbstractItemView::updateEditorGeometries()
3 QAbstractItemView::updateGeometries()
4 QTableView::updateGeometries()
5 QTableView::timerEvent(QTimerEvent *)
6 QObject::event(QEvent *)
7 QWidget::event(QEvent *)
8 QFrame::event(QEvent* )
9 QAbstractScrollArea::event(QEvent* )
10 QAbstractItemView::event(QEvent* )
11-21 ... Not useful information about any of the code
22 QCoreApplication::exec()
23 main
However, it's all byte code and I can't actually inspect which line is crashing the code in any of the traces using the debugger. What I don't understand is that the same process for manually clicking the Plus button is being completed (I connect the click event of the Plus button to the enableRow() function) and when I programmatically call enableRow() from the QSettings loop in importFile() it will crash after it loops through all of the items.
Things to note: setting the base size of the table to the size of the QSettings array I'm reading from (i.e. if I want 10 rows, just setting 10 rows to begin with before setting the item texts will work correctly), however, I want the base size of the table upon creation to be something like 5. It seems once the loop goes beyond the row count I specified from the constructor, then the program will crash, but not at say, index 6, but only after it has completely looped through the table. It does not crash on any line such as QTableWidgetItem::setText or QTableWidget::setCellWidget(). I'm kind of confused and wondering if the table is populating too quickly for the QTableWidget::timerEvent on stack trace line 5. Nothing I do in the loop is any different than what I do when manipulating the table normally.
It turns out that the error was that I was setting the QTableWIdgetItem one row earlier than I should have been. I'm not sure why the table would be able to iterate up until the end of the QSettings loop before crashing, but that was essentially the error. I'm not quite sure why the stack trace was so cryptic.
in my enableRow() function, I actually posted above from memory the correct logic, which differed in my code's logic by 1 index previously for the row value. Why the code did not crash when using it normally with the buttons whose slots called the same function as the import() seems to baffle me, perhaps a case of undefined behavior.
I have a javafx application with a TableView. Only the first column (dataTypeColumn) is editable and it contains a ComboBox for editing. Now the TableView does what it is supposed to do, however there is a combination of weird bugs when i start editing a cell and then scroll it out of view without commiting the edit. I am pretty sure it is because of the way TableView reuses the cells. However I haven't found any way to intervene with it, for example to forbid reuse of cells that are currently editing. Can you help me with that.
Even though I am pretty sure it is because of cell reuse, I will write the whole problem below, in case the source of the problem is a different.
The column in question contains Values of the enum DataType
I have a cell Factory for that column looking like this:
dataTypeColumn.setCellFactory(param -> new ComboBoxTableCell<>(DataType.values()));
The values for the column get read like this:
dataTypeColumn.setCellValueFactory(param -> Bindings.valueAt(configuration, param.getValue()));
In case this is confusing, the items that I give my TableView are Integers (from 0 to n-1), and in the different column CellValueFactories the actual values will be loaded depending on the Integer assoziated with the current column.
So when editing it, it shows a ComboBox with all the Values that DataType can have and let's the user select one. I have a callback on the column that reacts to the Edit commited event and looks like this:
public void editCommited(TableColumn.CellEditEvent<Integer, DataType> event) {
//configuration is an ObservableList containing DataType elements
configuration.set(event.getRowValue(), event.getNewValue());
}
So about the problems that occur. At the beginning all cells in that column have the same value: "nothing selected". It is a special value of the enum reserved for this case, as I didn't find a setPlaceholder function on the ComboBoxTableCell class. When I know start editing one of the cells and then scroll it out of view, one of the next rows will suddendly be in the editing state as well, even though that row has not been touched before. If I scroll further an cell in the editing state will appear every time the previous one scrolls out of view. I can also go back and will find the same cells in the editing state. If I edit the cell that should not be in the editing state, it will not change, but instead the cell that I originally tried to edit will change it's value. This might be due to the underlying ObservableList, that automatically updates the value in the column.
If I start editing a cell that has a different value (from a previous edit), something even more weird happens. When scrolling it out of view again a new row will have a cell in the editing page, however with the default value "nothing selected". If I scroll backwards the cell that i tried to edit originally will no longer be in the editing state however it's value has changed to "nothing selected". As if the new cell that got the editing state somehow commited it's own value.
Please some help with this :)
This indeed seems to be a bug. Rather surprising, if you move the scroll bar with the mouse, the edit is properly canceled, but not, if you use the mouse wheel to scroll.
You can easily create a workaround for this buf however, since you simply have to cancel the edit, when the item is replaced. You could e.g. use this method to create the cellFactory on your own:
public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> comboBoxCellFactory(ObservableList<T> items) {
if (items == null) {
throw new IllegalArgumentException();
}
return column -> new ComboBoxTableCell<S, T>(items) {
#Override
public void updateIndex(int i) {
cancelEdit();
super.updateIndex(i);
}
};
}
If display simple TableView sample, then select first row, then press Ctrl and then Down Arrow button two times, we will see the following picture:
I.e. first row remains selected, while third row get cursor.
How to know this row?
This is the focused row. You can access that row via the focusModel property:
int rowIndex = tableView.getFocusModel().getFocusedIndex();
The TableView.TableViewFocusModel class used for focusModel also supports some additional features like accessing the item for the focused row.
my application needs to allow users to insert rows below the current datagrid row. My solution is to to add a row to the dataproviders collection. This works, but the row does not appear beneath the current row the user clicked on.
The Datagrid has a default sort order (date ASC), which re-orders the data...so this seems to affect the position of the row in the grid.
Any ideas how to fix this?
Two possible answers:
1. define your own sort function that sorts according to item order in dataprovider (i.e. it does nothing), and assign it to the sortFunction property
2. simply comment out the sorting of the data inside the component.
I have a QTableWidget and I can't get anything to show up in it.
The following appears in the constructor of the main window:
ui->tableWidget->setItem(0,0,new QTableWidgetItem("Item1"));
ui->tableWidget->setItem(0,1,new QTableWidgetItem("Item2"));
ui->tableWidget->setItem(0,2,new QTableWidgetItem("Item3"));
When I run the application, the table widget shows up, but the items do not.
I tried adding ui->tableWidget->insertRow(0); before the above code, but it didn't work.
Aha! I figured out what was going on... I needed to tell the control the number of rows it should have:
ui->tableWidget->setRowCount(2);
Example code:
//this will give the present number of rows available.
int insertRow = ui->tableWidget->rowCount();
//insert the row at the bottom of the table widget - using.
ui->tableWidget->insertRow(insertRow);
//After a new row is inserted we can add the table widget items as required.
ui->tableWidget->setItem(insertRow,0,new QTableWidgetItem("Item1"));
ui->tableWidget->setItem(insertRow,1,new QTableWidgetItem("Item2"));
ui->tableWidget->setItem(insertRow,2,new QTableWidgetItem("Item3"));