QListView with QStandardItemModel does not show selection highlight through code - qt

I have a QListView that is populated with either a QStandardItemModel or a QStringListModel (based on simplicity of contents... number of columns).
On load, or switching between widgets, I search for the item that should be selected, and try to highlight it.
if (first)
{
m_myListView.setModel(m_standardItemModel);
QList<QStandardItem*> lst = m_standardItemModel->findItems(m_value1, Qt::MatchExactly, 1);
if(!lst.isEmpty())
{
QModelIndex index = lst.at(0)->index();
qDebug() << index.row(); // tells me correct row
//m_myListView.setCurrentIndex(index); // no change if I use
m_myListView.selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
m_myListView.scrollTo(index);
}
}
else
{
m_myListView.setModel(m_stringListModel);
int i = m_stringListModel->stringList().indexOf(m_value2);
if (i >= 0)
{
QModelIndex index = m_stringListModel->index(i);
m_myListView.selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
m_myListView.scrollTo(index);
}
}
The m_stringListModel version correctly highlights (and scrolls to item).
The m_standardItemModel version does not highlight row, and does not scroll to item. But in the uses afterwards, it correctly provides the data for selected index:
QModelIndexList indexList = m_myListView.selectionModel()->selectedIndexes();
if (!indexList.isEmpty())
{
QModelIndex index = indexList.first();
if (index.isValid())
{
row = index.row();
data1 = m_standardItemModel->index(row, 1).data().toString();
...
So... it seems that the selection works, but if it does, why do I not see a highlight ? (and the scrollTo() )
Note - the code is pretty giant but I verified for the possibility of reloading the model and possibly losing the selection - and besides, the QStringListModel version works correctly.
Is that a typical behavior of QStandardItemModel, or is there something I must do, like setting a BackgroundRole type data ?
How can I highlight the selection of the list view with the QStandardItemModel applied ?

I see your code, probably you want to select the first element of your model? Let's try:
void MyClass::selectFirstElement() {
const QModelIndex firsIndex = _myModel->index(0,0);
if (index.isValid())
ui->listView->setCurrentIndex(firstIndex);
ui->listView->scrollTo(firstIndex);
}
}
Could you share the m_standardItemModel implementation? Also configure your list correctly:
ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->listView->setSelectionBehavior(QAbstractItemView::SelectRows); // Or Columns
Check if your QStandarItem has the selection flag enable. See http://doc.qt.io/qt-4.8/qt.html#ItemFlag-enum for more info.
Finally, you could ensure that the index is stored in the correct model by getting the index in the same row & column directly from the model, something like this:
QModelIndex index = lst.at(0)->index();
index = _model->index(index.row(), index.column());
Sorry, for my poor english :S

Because the item found is different than the display item, the list view is unable to select it...
2 solutions: either create a different QModelIndex from the one found, pointing to the display column, or select an entire row containing the desired index:
m_myListView.selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);

Related

X++ assign Enum Value to a table column

I am trying to pull the Enum chosen from a dialog and assign the label to a table's column.
For example: Dialog opens and allows you to choose from:
Surface
OutOfSpec
Other
These are 0,1,2 respectively.
The user chooses OutOfSpec (the label for this is Out Of Spec), I want to put this enum's Name, or the label, into a table. The column I'm inserting into is set to be a str.
Here's the code I've tried, without success:
SysDictEnum dictEnum = new SysDictEnum(enumNum(SDILF_ScrapReasons));
reason = dialog.addField(enumStr(SDILF_ScrapReasons),"Scrap Reason");
dialog.run();
if (!dialog.closedOk())
{
info(reason.value());
return;
}
ttsBegin;
// For now, this will strip off the order ID from the summary fields.
// No longer removing the Order ID
batchAttr = PdsBatchAttributes::find(itemId, invDim.inventBatchId, "OrderId");
orders = SDILF_BreakdownOrders::find(batchAttr.PdsBatchAttribValue, true);
if (orders)
{
orders.BoxProduced -= 1;
orders.update();
}
// Adding a batch attribute that will include the reason for scrapping
select forUpdate batchAttr;
batchAttr.PdsBatchAttribId = "ScrapReason";
//batchAttr.PdsBatchAttribValue = any2str(dictEnum.index2Value(reason.value()));
batchAttr.PdsBatchAttribValue = enum2str(reason.value());
batchAttr.InventBatchId = invDim.inventBatchId;
batchAttr.ItemId = itemId;
batchAttr.insert();
Obviously this is not the whole code, but it should be enough to give the issue that I'm trying to solve.
I'm sure there is a way to get the int value and use that to assign the label, I've just not been able to figure it out yet.
EDIT
To add some more information about what I am trying to accomplish. We make our finished goods, sometimes they are out of spec or damaged when this happens we then have to scrap that finished good. When we do this we want to keep track of why it is being scrapped, but we don't want just a bunch of random reasons. I used an enum to limit the reasons. When the operator clicks the button to scrap something they will get a dialog screen pop-up that allows them to select a reason for scrapping. The code will then, eventually, put that assigned reason on that finished items batch attributes so that we can track it later in a report and have a list of all the finished goods that were scrapped and why they were scrapped.
I'm not entirely sure of your question, but I think you're just missing one of the index2[...] calls or you're not getting the return value from your dialog correctly. Just create the below as a new job, run it, make a selection of Open Order and click ok.
I don't know the difference between index2Label and index2Name.
static void Job67(Args _args)
{
Dialog dialog = new dialog();
SysDictEnum dictEnum = new SysDictEnum(enumNum(SalesStatus));
DialogField reason;
SalesStatus salesStatusUserSelection;
str label, name, symbol;
int value;
reason = dialog.addField(enumStr(SalesStatus), "SalesStatus");
dialog.run();
if (dialog.closedOk())
{
salesStatusUserSelection = reason.value();
// Label
label = dictEnum.index2Label(salesStatusUserSelection);
// Name
name = dictEnum.index2Name(salesStatusUserSelection);
// Symbol
symbol = dictEnum.index2Symbol(salesStatusUserSelection);
// Value
value = dictEnum.index2Value(salesStatusUserSelection);
info(strFmt("Label: %1; Name: %2; Symbol: %3; Value: %4", label, name, symbol, value));
}
}

D365 New Button creates price line with empty line

After adding logic about creating price for object in grid it's always created "one line more" which is empty.
So, if there is need to be created two lines, it will be created 3 lines and that one addition will be empty.
Is there something what I missing in code?
[Control("CommandButton")]
class AreaActionPaneNew
{
void clicked()
{
PMCParameters contractParameters = PMCParameters::find();
PMETmpRentalObjectArea groupedAreaList; // Group by area_type and cost_type
PMERentalObjectPrice priceList;
date workingDate = currWorkingDate.dateValue();
;
super();
// Get grouped area values. Values are summed up by area_type and ancost_type
groupedAreaList = PMERentalObjectAreaCl::getRentalAreaPrCostType(pmeRentalobject.RentalObjectId, userSetting.validFrom(), userSetting.validTo() , workingDate);
ttsbegin;
while select groupedAreaList
{
select forupdate firstonly priceList
where priceList.RentalObjectId == pmeRentalObject.RentalObjectId &&
priceList.RentalCostType == groupedAreaList.RentalCostTypeId &&
priceList.AreaType == groupedAreaList.Areatype && priceList.ValidFrom == pmeRentalObject.ValidFrom;
if (!priceList)
priceList.initValue();
priceList.RentalObjectId = pmeRentalObject.RentalObjectId;
priceList.RentalCostType = groupedAreaList.RentalCostTypeId;
priceList.ValidFrom = pmeRentalobject.ValidFrom;
priceList.AreaType = groupedAreaList.Areatype;
priceList.Amount = groupedAreaList.Price;
priceList.Area = groupedAreaList.AreaValue;
priceList.Quantity = groupedAreaList.RentalQty;
if (!priceList)
priceList.Period = contractParameters.ReportPeriod;
if (priceList)
priceList.update();
else
priceList.insert();
}
ttscommit;
pmeRentalObjectPrice_ds.research();
}
}
The code looks like it only updates/inserts without creating a blank line.
From your attribute, you are using a Command Button (see here), which may have an associated command, such as New, which effectively pushes Ctrl+N, and would explain why you have a blank line.
The simplest way to check is just create a regular Button and override the clicked method, then copy/paste your code and push both buttons and see if they have different behavior.
Check the Command property on the button and see if there's something there. Try commenting out the super(); call.
You should perhaps consider just a Button or a Menu Item Button with an associated object.

QTableWidget cast loses selectedItems

I am adding QTableWidgets to a layout (called tableArea). I have a function that I want to be able to go through all the selected items in all tables I have added to my layout:
for (int i=0; i <ui->tableArea->count(); i++)
{
QTableWidget *tableI = (QTableWidget*)ui->tableArea->itemAt(i)->widget();
int rowCount = tableI->rowCount(); // just to test if correct info
QList<QTableWidgetItem*> list = tableI->selectedItems(); // This is empty!!
}
The function iterates through correct tables, and it even knows the right row count for each table, but it doesn't seem to know which items are selected in the table. When I select items, this function doesn't seem to recognize that there is something selected. I imagine this has to do with the cast. Any idea? Thanks in advance!

How to simply delete row in QFormLayout programatically

I have this code:
myEdit = QLineEdit()
myQFormLayout.addRow("myLabelText", myEdit)
Now I have to remove the row by reference to myEdit only:
myQformLayout.removeRow(myEdit)
But there is no API for that. I can use .takeAt(), but how can I get the argument? How do I find the label index, or the index of myEdit?
You can just schedule the widget and its label (if it has one) for deletion, and let the form adjust itself accordingly. The label for the widget can be retrieved using labelForField.
Python Qt code:
label = myQformLayout.labelForField(myEdit)
if label is not None:
label.deleteLater()
myEdit.deleteLater()
my solution...
in header file:
QPointer<QFormLayout> propertiesLayout;
in cpp file:
// Remove existing info before re-populating.
while ( propertiesLayout->count() != 0) // Check this first as warning issued if no items when calling takeAt(0).
{
QLayoutItem *forDeletion = propertiesLayout->takeAt(0);
delete forDeletion->widget();
delete forDeletion;
}
This is actually a very good point... there is no explicit reverse function for addRow().
To remove a row you can do the following:
QLineEdit *myEdit;
int row;
ItemRole role;
//find the row
myQFormLayout->getWidgetPosition( myEdit, &row, &role);
//stop if not found
if(row == -1) return;
ItemRole otheritemrole;
if( role == QFormLayout::FieldRole){
otheritemrole = QFormLayout::LabelRole;
}
else if( role == QFormLayout::LabelRole){
otheritemrole = QFormLayout::FieldRole;
}
//get the item corresponding to the widget. this need to be freed
QLayoutItem* editItem = myQFormLayout->itemAt ( int row, role );
QLayoutItem* otherItem = 0;
//get the item corresponding to the other item. this need to be freed too
//only valid if the widget doesn't span the whole row
if( role != QFormLayout::SpanningRole){
otherItem = myQFormLayout->itemAt( int row, role );
}
//remove the item from the layout
myQFormLayout->removeItem(editItem);
delete editItem;
//eventually remove the other item
if( role != QFormLayout::SpanningRole){
myQFormLayout->removeItem(otherItem);
delete otherItem
}
Note that I retrieve all the items before removing them. That's because I don't know if their role will change when an item is removed. This behavior is not specified so I am
playing safe. In qt designer, when you remove an item from a form, the other item on
the row take all the space (which means his role changes...).
Maybe there is a function somewhere and not only I reinvented the wheel but I made a broken one...

How to get the QWebFrame for an iframe/frame QWebElement?

I have simple Qt GUI application which uses QtWebkit. I am loading complex page with a lot of nested IFRAME-tags. And I want to traverse complete DOM tree (like Chrome browser does in debug-panel) including content of iframes.
My code is:
QWebElement doc = ui->webView->page()->mainFrame()->documentElement();
QWebElement iframe = doc.findFirst("iframe[id=someid]");
QWebFrame *webFrame = ....? // how to get the QWebFrame for an iframe/frame QWebElement?
Note:
I can traverse over all frames (including nested):
void MainWindow::renderFramesTree(QWebFrame *frame, int indent)
{
QString s;
s.fill(' ', indent * 4);
ui->textLog->appendPlainText(s + " " + frame->frameName());
foreach (QWebFrame *child, frame->childFrames())
renderFramesTree(child, indent + 1);
}
But my question is not about that. I need to get corresponding QWebFrame* of iframe-QWebElement.
Thanx!
Each QWebFrame has QList<QWebFrame *> QWebFrame::childFrames () const method. Each frame has also QString QWebFrame::frameName () const. Combining both may let you find what you need.
QWebFrame * frameImLookingFor = NULL;
foreach(QWebFrame * frame, ui->webView->page()->mainFrame()->childFrames())
{
if (frame->frameName() == QLatin1String("appFrame"))
{
frameImLookingFor = frame;
break;
}
}
if (frameImLookingFor)
{
// do what you need
}
run selector on current frame
if it returns something that's good we found that our webframe is on the current frame, lets call this element X :
now get all frame elements using selector "iframe,frame" from current page
loop trough all those elements and try to match them with X frame
this way you'll be able to find exact INDEX of the X frame in document
finally you are now able to focus on child frame with that INDEX
else this means that selector is not found in this frame
loop trough all child frames and repeat the whole process for each child frame

Resources