QListView does not display model data - qt

I have a dialog with several widgets, including two list views, say lv1 and lv2.
For each QListView, the class for the dialog has a private variable that is a pointer to the associated data model. Say these variables are called m1 and m2:
MyListModel* m1;
MyListModel* m2;
The class MyListModel for these two associated data models inherits from QAbstractListModel, and redefines methods data and rowCount. Stepping in the debugger shows that these methods are called and return the expected values.
The constructor for the dialog includes the following four instructions :
m1 = new MyListModel(...);
m2 = new MyListModel(...);
ui->lv1->setModel(m1);
ui->lv2->setModel(m2);
Nothing is displayed in the list views when the dialog opens (other widgets are properly filled, though) .
What could be wrong?
I tried setting a QStringListModel as a model for one of the list view. Again, the list view displayed no contents.
What could be wrong?

Related

JavaFX Observable where the value can be swapped

I am writing a small experimental desktop application. Basically it has the options to display a list of recipes and detailed information about a single recipe.
To accomplish that i implemented a class called RecipeContext that stores a ObservableList<Recipe> that i bind to a TableView, so the view gets automatically updated if i add to, or remove from the collection.
I want something similar for the single recipe, an Observable where i simply have to change the contained recipe and have the view automatically update to display the new recipe information.
To make this a bit more clear, i want something like this:
SingleObservable<Recipe> detailedRecipe = new SingleObservable<>(new Recipe("A"));
detailedInformationController.bindRecipeObservable(detailedRecipe);
// Recipe A is displayed
detailedRecipe.set(new Recipe("B"));
// View is notified about the change and displays Recipe B
Is there a class that does that?
SimpleObjectProperty will do what you want.
SimpleObjectProperty<Recipe> detailedRecipe = new SimpleObjectProperty<>(new Recipe("A"));
...
detailedRecipe.set(new Recipe("B"));
http://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/SimpleObjectProperty.html

How to forward signals in a QAbstractItemModel wrapper model

I intend to create my own item model, derived from QAbstractItemModel. The model does not contain data but wraps some data repository. That repository emits signals after item(s) are insert, removed, renamed, etc.
Whenever something changes in the repository, my item model needs to forward those signals.
However the repository has standalone signals like void itemRemoved(int index); while QAbstractItemModel has begin/end pairs of protected functions (and signals) like beginInsertRows() and endInsertRows().
How should I handle this? E.g. I could connect a slot like the following to the repository's itemRemoved() signal:
void RepositoryItemRemoved(int i)
{
beginInsertRows(QModelIndex(), i, i);
endInsertRows();
}
Based on the above example: Is it valid to call beginInsertRows() / endInsertRows() sequently after a row has been inserted in the repository?
I've had a similar scenario, where the data is in a different object, and the model is just a wrapper, and only created if that data set is displayed in a view. I used a pointer to the model object in the data object, checking if it is null on insert operations, and if not call beginInsertRows() and endInsertRows() through it. Naturally, since those are protected, the data class would have to be declared a friend to the model class.
The documentation stresses that it is important to call beginInsertRows() before any data is inserted:
When reimplementing insertRows() in a subclass, you must call this
function before inserting data into the model's underlying data store...
...Otherwise, the views may end up in an invalid state.
You should test with a view, or alternatively, examine the actual implementation in the source.
I've had somewhat similar scenario as well, only in my case the Qt model wrapped the underlying model a little more literally: the underlying model contained sufficiently more data than the view had to know about. So I let the Qt model to contain its own list of small pieces of each underlying model's data item for the view/delegate to deal with. So the slots processing the updates from the underlying model looked like this:
void RepositoryItemRemoved(int i)
{
beginRemoveRows(QModelIndex(), i, i);
removeModelItem(i);
endRemoveRows();
}
Such design solved the problem of view's invalid state although it may be impractical for the use cases in which letting the Qt model contain its own items list would mean duplicating the sufficient amount of data being worked with.

How to insert QPushButton into TableView and make it view/display?

Sorry to have to go this way, but this question is already available and I could ask there, but no no, need a reputation of 50 first. This give me 1.
From one of the answers:
QPushButton* viewButton = new QPushButton("View");
tableView->setIndexWidget(model->index(counter,2), viewButton);
I've tried that but the button doesn't display at all in, the code works but nothing shows in the cell. Have looked at the spinbox sample and tried a pushbutton delegate -no success
I'm using a QStandardItemModel to hold the data, add the model to a QSortFilterProxyModel (for filtering purpose) that is set to tableView->setModel. Display data is no problem though not the button.
The index argument in setIndexWidget(QModelIndex const& index, QWidget*) should belong to the same model, which is set in the view. What is your variable "model" refers to? To the data holder model(which is not the model set as view's model!!!) or to the proxy-model?
A safe approach would be to call:
tableView->setIndexWidget(tableView->model()->index(counter,2), viewButton);

using lambdas or QSignalMapping to pass a custom class value into custom SLOT

I am using Qt5.
I have a loop which generates multiple (number specified by the user) plots by using QCustomPlot (http://www.qcustomplot.com/) each shown in their own dialog. I want the user to be able to save one of the plots, so in each dialog there is a menu bar with an Action "Save as PDF".
I have a List of the plots (QList< QCustomPlot*> >) which each plot is added to when it is created in the loop. My issue is how to select from the list which plot should be saved when the user triggers the action. Here's the main code:
while(currentPlotNum<NumPlots){
//code for generating plots
QAction *saveAsPdfAction = new QAction("Save As PDF",plotDialog);
QFileDialog *saveAsPdfDialog = new QFileDialog(plotDialog);
saveAsPdfDialog->setFileMode(QFileDialog::AnyFile);
saveAsPdfDialog->setNameFilter("PDF Files (*.pdf)");
QObject::connect(saveAsPdfAction,SIGNAL(triggered()),saveAsPdfDialog,SLOT(exec()));
QSignalMapper *signalMapper = new QSignalMapper(saveAsPdfDialog);
QObject::connect(saveAsPdfAction,SIGNAL(triggered()),signalMapper,SLOT(map()));
signalMapper->setMapping(saveAsPdfAction,currentPlotNum);
QObject::connect(signalMapper,SIGNAL(mapped(int)),this,SLOT(setWorkingPlot(int)));
QObject::connect(saveAsPdfDialog,SIGNAL(fileSelected(QString)),this,SLOT(saveToPDF(QString)));
currentPlotNum++;
}
then here are the two SLOTS:
void samplePlots::setWorkingPlot(int value){
workingPlot = value;
}
void samplePlots::saveToPDF(QString PdfFileName){
plotList[workingPlot]->savePdf(PdfFileName,false,600,600);
}
I run the application and generate say 3 plots, when I click the button to save one of the plots, the plot that actually gets saved is seemingly a random choice of one of the 3, rather than the plot in the dialog which i click the button in.
Ideally I would have been able to pass the QCustomPlot* itself through the SignalMaper, but it doesn't seem as though I can do that. I also tried to have the Slot as a lambda (following the syntax here http://www.artandlogic.com/blog/2013/09/qt-5-and-c11-lambdas-are-your-friend/ but I couldn't get it to work.
If anyone has Ideas of how to fix my problem that would be great.
Connect each 'saveToPdf buttons' triggered(bool) signal to a custom signal of your derived displaying QDialog (lets call it saveRequested()).
store in the dialog the index of the displaying plot as well and save your QSignalMapper (not needed).
then connect your main class where your list is stored to that saveRequested() signal, cast the QObject::sender() to your Dialog and access the plot in the list.
cheers

Multilevel Master/Detail Databinding with EMF and RCP

I made a model with EMF, representing the settings of a device, and a RCP GUI. In the GUI I have a list to select different devices of the type of the model (Master).
The model has a List of Objects of a small class which should be displayed in a table (Detail).
The tableItems itself need to be edited so I have a small GUI part with checkboxes etc. to change the settings. Here the tableitem is master and all fields shown in the GUI are details.
Observable for the List of devices:
IObservableValue selection = ViewersObservables.observeSingleSelection(availableDevicesList);
Table:
IObservableList list = EMFObservables.observeDetailList(Realm.getDefault(), selection,DevicePackage.Literals.LIST);
TableViewer tableViewer = new TableViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION);
tableViewer.setInput(list);
IObservableValue tableSelection = ViewersObservables.observeSingleSelection(tableViewer);
Editing:
Spinner field1 = new Spinner(parent, SWT.BORDER);
dbc.bindValue(SWTObservables.observeSelection(field1), EMFObservables.observeDetailValue(Realm.getDefault(), tableSelection, DevicePackage.Literals.Value1));
When changing the device selection the tableitems get replaced. But the tableSelection seems to have a problem with this. Sometimes it still contains values of a a tableitem from a different device and sometimes it just contains null.
I also have a button which gets enabled/disabled according the validation status of all fields. When the tableSelection puts null into these fields the validation does not work and the button is disabled until a entry in the table is selected.
I tried to manually set the selection empty with a listener on the list and:
tableViewer.setSelection(StructuredSelection.EMPTY, true);
but this does not do the full job. At least all "old" values are replaced but the null problem still occurs.
All I need is to set the tableSelection to an empty state as after the launch of the application, when no tableitem was selected yet.
I found the solution by myself. The problem was actually the spinner itself. It threw a nullpointer when the selection was empty and there was no value.
I solved it by giving it a custom converter (from int to int...) where I return a default value if the source is null.
Now the validation works fine and my button's enable state is set correct.

Resources