I have a TableView that displays the information contained in a QSortFilterProxyModel (whose model is a QAbstractTableModel)
Is there any way to fix/freeze in the TableView's top all rows with a specific property set to true, while maintaining filter and sorting for the other rows?
To put a specific row always on the tableview's top, I added the following logic to the QSortFilterProxyModel's lessThan method:
// Get left and right row
int leftRow = left.row();
int rightRow = right.row();
// Get specific data from left row
QModelIndex leftIndex = sourceModel()->index(leftRow, SPECIFIC_DATA_INDEX);
QString leftProperty = sourceModel()->data(leftIndex).toString();
// Get specific data from right row
QModelIndex rightIndex = sourceModel()->index(rightRow, SPECIFIC_DATA_INDEX);
QString rightProperty = sourceModel()->data(rightIndex).toString();
if(leftProperty .compare("Invalid") == 0) // put left on top if it has a specific property
if(sortOrder() == Qt::AscendingOrder) {
return true;
} else {
return false;
}
} else if(rightProperty .compare("Invalid") == 0) { // put right on top if it has a specific property
if(sortOrder() == Qt::AscendingOrder) {
return false;
} else {
return true;
}
}
Related
I am trying to add a new row to my QFormLayout after I have loaded two QLineEdits from a file, which works, but when I run my code it doesnt add anything, ot atleast anything that I can see. And I am also not able to add any wigets using QLayout::addWidget(QWidget* widget) anymore, which I used to be able to.
Thanks
The code, where it doesnt work:
void Kegelbuch::load(QString path, QString tab) {
//Load json file
Datastream* loadStream = new Datastream;
QJsonObject data = loadStream->loadData(path);
//Declaring all important Variables
QJsonArray keglerFullName;
QJsonArray keglerShortName;
QFormLayout* formLayout = (QFormLayout*)ui.keglerTab->layout();
int defaultRows = 2, width = 155;
//Retriev arrays from file
if (data.contains("KeglerFullName") && data["KeglerFullName"].isArray()) {
keglerFullName = data["KeglerFullName"].toArray();
}
if (data.contains("KeglerShortName") && data["KeglerShortName"].isArray()) {
keglerShortName = data["KeglerShortName"].toArray();
}
//Correctly add QLineEdits to the FormLayout
for (auto names : boost::combine(keglerFullName, keglerShortName)) {
QLineEdit fullNameEdit;
QLineEdit shortNameEdit;
QJsonValue fullNameValue, shortNameValue;
boost::tie(fullNameValue, shortNameValue) = names;
if (fullNameValue.isString()) {
fullNameEdit.setText(fullNameValue.toString());
fullNameEdit.setObjectName("fullName");
fullNameEdit.setMinimumWidth(width);
}
if (shortNameValue.isString()) {
shortNameEdit.setText(shortNameValue.toString());
shortNameEdit.setMaximumWidth(width);
shortNameEdit.setObjectName("shortName");
}
/*
if (keglerFullName.at(1).isString()) {
fullNameEdit->setText(keglerFullName.at(1).toString());
fullNameEdit->setObjectName("fullName");
fullNameEdit->setMinimumWidth(width);
}
if (keglerShortName.at(1).isString()) {
shortNameEdit->setText(keglerShortName.at(1).toString());
shortNameEdit->setMaximumWidth(width);
shortNameEdit->setObjectName("shortName");
}
*/
formLayout->addRow(&fullNameEdit, &shortNameEdit);
}
}
I'm currently using TAB to navigate to next cell. selectNext() or selectRightCell() works fine when I'm using SelectionMode.SINGLE.
However, when using SelectionMode.MULTIPLE, its selecting multiple cells as I TAB.
I'm using a TableView. I need SelectionMode.MULTIPLE for the copy & paste function.
Is there a way to make it work in SelectionMode.MULTIPLE?
fixedTable.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()){
case TAB:
if (event.isShiftDown()) {
fixedTable.getSelectionModel().selectPrevious();
} else {
fixedTable.getSelectionModel().selectNext();
}
event.consume();
break;
case ENTER:
return;
case C:
if(event.isControlDown()){
copySelectionToClipboard(fixedTable) ;
}
event.consume();
break;
case V:
if(event.isControlDown()){
pasteFromClipboard(fixedTable);
}
event.consume();
break;
default:
if (fixedTable.getEditingCell() == null) {
if (event.getCode().isLetterKey() || event.getCode().isDigitKey()) {
TablePosition focusedCellPosition = fixedTable.getFocusModel().getFocusedCell();
fixedTable.edit(focusedCellPosition.getRow(), focusedCellPosition.getTableColumn());
}
}
break;
}
}
});
You will need to handle the selection on your own. The reason is because the methods selectPrevious() and selectNext() tries to select the previous ( or the next ) without removing the current selected row ( when you set the selection mode to be SelectionMode.MULTIPLE) , also you can't use them and just remove the previous selecting by just calling clearSelection() because this will set the selected index to -1 and then the methods selectPrevious() and selectNext() will select the last or the first row only.
Here is how you could implement the selection on your own :
// the rest of your switch statement
...
case TAB:
// Find the current selected row
int currentSelection = table.getSelectionModel().getSelectedIndex();
// remove the previous selection
table.getSelectionModel().clearSelection();
if (event.isShiftDown()) {
currentSelection--;
} else {
currentSelection++;
}
// find the size of our table
int size = table.getItems().size() - 1;
// we was on the first element and we try to go back
if(currentSelection < 0){
// either do nothing or select the last entry
table.getSelectionModel().select(size);
}else if(currentSelection > size) {
// we are at the last index, do nothing or go to 0
table.getSelectionModel().select(0);
}else {
// we are between (0,size)
table.getSelectionModel().select(currentSelection);
}
event.consume();
break;
...
I have a custom QTreeWidget class with the dropEvent() method overridden.
Here is the method:
void QCustomTreeWidget::dropEvent(QDropEvent * event)
{
QModelIndex droppedIndex = indexAt(event->pos());
if (!droppedIndex.isValid())
return;
// other logic
QTreeWidget::dropEvent(event);
}
How can I determine if the item will be inserted above, inside or below the item on which it is dropped?
You need to use the DropIndicatorPosition. With a switch statement, you can easily achieve what you want.
bool bAbove = false; // boolean for the case when you are above an item
QModelIndex dropIndex = indexAt(event->pos());
DropIndicatorPosition dropIndicator = dropIndicatorPosition();
if (!dropIndex.parent().isValid() && dropIndex.row() != -1)
{
switch (dropIndicator)
{
case QAbstractItemView::AboveItem:
// manage a boolean for the case when you are above an item
bAbove = true;
break;
case QAbstractItemView::BelowItem:
// something when being below an item
break;
case QAbstractItemView::OnItem:
// you're on an item, maybe add the current one as a child
break;
case QAbstractItemView::OnViewport:
// you are not on your tree
break;
}
if(bAbove) // you are above an item
{
// manage this case
}
}
I have a qtablewidget with one column with a widget and others with data. The only column with widget is shown and all other columns are hidden.
foreach (BillHeader *billHeader, billHeaderList)
{
m_pBillTable->insertRow(i);
itemWidget = new LookupItem;
itemWidget->setImage(1);
...
m_pBillTable->setCellWidget(i, 0, itemWidget);
tableItem = new QTableWidgetItem(billHeader->billNumber);
tableItem->setTextAlignment(Qt::AlignCenter);
m_pBillTable->setItem(i, 1, tableItem);
...
m_pBillTable->hideColumn(1);
...
I have a signal slot connected as below:
connect(m_pOkButton, SIGNAL(clicked()), this, SLOT(handleOkClick()));
when ok button click i try to get the selected item and get data from the widget set to it
void OrderLookup::handleOkClick()
{
qDebug()<<Q_FUNC_INFO<<"Invoked";
QList<QTableWidgetItem*> itemList = m_pBillTable->selectedItems();
qDebug()<<Q_FUNC_INFO<<itemList.count();
if (!itemList.isEmpty())
{
int row = itemList.at(0)->row();
qDebug()<<Q_FUNC_INFO<<row;
LookupItem *item = (LookupItem*)m_pBillTable->cellWidget(row, 0);
if (NULL != item)
{
QString billNumber = item->getBillNumber();
emit orderLookupComplete(billNumber);
accept();
}
}
qDebug()<<Q_FUNC_INFO<<"Exits";
}
But i am getting the list count as zero.
The row is getting selected and gets highlighted.
I’ve set some properties to table widget as below:
m_pBillTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_pBillTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pBillTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_pBillTable->setFocusPolicy(Qt::NoFocus);
Please can someone help me to know why list count is empty..
The issue got solved ..
QItemSelectionModel *itemModel = m_pBillTable->selectionModel();
QModelIndexList indexList = itemModel->selectedRows();
qDebug()<<Q_FUNC_INFO<<"IndexList Count"<<indexList.count();
if (!indexList.isEmpty())
{
int row = indexList.at(0).row();
I have a QTableWidget and 1 column has only checkboxes, so for those items I have these flags:
/* create prototype for checkbox item */
checkItem = new QTableWidgetItem();
Qt::ItemFlags flags = checkItem->flags();
flags &= ~Qt::ItemIsEditable;
flags &= ~Qt::ItemIsDropEnabled;
flags &= ~Qt::ItemIsDragEnabled;
flags |= Qt::ItemIsUserCheckable;
checkItem->setFlags(flags);
/**/
Ok that works... almost. I can't drop anything in those items, that's good. But now there can be dropped in between 2 cells, so there is a new row created.
How can I prevent that?
In the other columns where the cells are drop-enabled, I can only drop in the cells and not in between and that is good. Why is this behavior changed when the item is not drop-enabled?
A fast hack using an event filter (could need some tweaks):
What you do this is ignore any drop on the checkbox column. So it should be enough to disable row creation.
bool yourWidget::eventFilter(QObject *a_object, QEvent *a_event)
{
bool result = false;
if ((a_object == table->viewport()) && (a_event->type() == QEvent::Drop))
{
QDropEvent *p_drop_event = static_cast<QDropEvent *>(a_event);
QPoint pos = p_drop_event->pos();
QModelIndex new_index = table->indexAt(pos);
if (new_index.column() == YOUR COLUMN HERE)
{
// Ignore drop event
p_drop_event->setDropAction(Qt::IgnoreAction);
p_drop_event->accept();
return true;
}
else
{
// Allow drop
return false;
}
}
return QObject::eventFilter(a_object, a_event);
}
Info about eventFilters:
Event Filters