Javafx: updating cell using choicebox in the GUI doesn't work - properties

I have a problem in a Tableview created using javafx. I have set the edititable="true" on the fxml file of the tabel, then in the controller I execute
#FXML
private TableColumn<ARule,Object> rankCol;
rankCol.setCellValueFactory(new PropertyValueFactory<ARule, Object>("label")); rankCol.setCellFactory(ChoiceBoxTableCell.forTableColumn(Main.getlabelSample()));
rankCol.setOnEditCommit(e -> {System.out.println("something happens!");});
To create in the column rank, a choicebox to change te value of the property.
The ARule has a property field and the getter and setters:
private SimpleObjectProperty label;
public SimpleObjectProperty labelProperty() {
return label;
}
public void setLabel(Object label) {
this.label.set(label);
}
public Object getLabel(){
return this.label.getValue();
}
The function Main.getlabelSample() retrun this object filled with Strings or Integer
private static final ObservableList<Object> labelSample = FXCollections.observableArrayList();
The problem is that in the interface I can edit the column and it displays the correct value in the labelSample list, the problem is that it doesn't change the value of the ARule object, this is highlighted by the missing call of the setOnEditCommit handler. The value on the GUI is the new one selected but the value saved on the items in the table is the old one.
I have also a separated button to change the value of that column on the selected row and if I trigger that, the values changes for "real" (both on the GUI and on the model).
What could be the error in the code?

The default edit commit behavior of the column is set as the onEditCommit property. If you call
rankCol.setOnEditCommit(...);
then you set this property to something else, i.e. you remove the default behavior.
If you want to add additional behavior to the default, use addEventHandler(...) instead of setOnEditCommit(...):
rankCol.addEventHandler(TableColumn.editCommitEvent(), e -> {
System.out.println("Something happens");
});

Find the answer the line of code:
rankCol.setOnEditCommit(e -> {System.out.println("something happens!");});
for some reason overwrite the default behaviour of updating the cell changing the code into
rankCol.setOnEditCommit(e -> {
e.getTableView().getItems().get(e.getTablePosition().getRow()).setLabel(e.getNewValue());
System.out.println("Something happens!");});
Resolved the problem. At the moment I don't know why this is happening.

Related

Null pointer when adding action listeners in IntelliJ GUI form

I'm using an IntelliJ GUI form to create a toolwindow as part of an IntelliJ plugin. This is some code in the class bound to the form:
private JButton checkNifi;
NifiToolWindow(ToolWindow toolWindow) {
checkNifi.addActionListener(e -> toolWindow.hide(null));
}
I understand that when this action listener is added the button is still null and this is the issue, however even if I do checkNifi = new JButton("Some text");, the null pointer instead gets thrown on this line.
I should add I also have a ToolWindowFactory class which looks like this:
#Override
public void createToolWindowContent(#NotNull Project project, #NotNull com.intellij.openapi.wm.ToolWindow toolWindow) {
NifiToolWindow nifiToolWindow = new NifiToolWindow(toolWindow);
ContentFactory contentFactory = new ContentFactoryImpl();
Content content = contentFactory.createContent(nifiToolWindow.getContent(), "", false);
toolWindow.getContentManager().addContent(content);
}
This is taken from the example here https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/tool_window/src/myToolWindow
Any help or ideas would be great.
I found the solution, I had create custom box ticked in the gui designer, but an empty createGuiComponents() method. Therefore it was null.

gtk#: Tree View object always passed as call-by-reference

It seems as if my arguments in the method call of processing a Tree View is always done as call-by-reference.
I have a visible GTK "Tree View" control on a top level window. The data was written by the respective model.
Now I want to remove some of the columns (based on options set by the user) and pass the manipulated Tree View to an Export-Function.
In order to remove the columns only from the output, not from the GUI itself, I thought of copying the visible Tree View control into a temporary one, manipulating the temportary one and calling the export-functionality on the temporary one.
My problem is: even though I pass my origin, visible Tree View as referenc-by-value (as of my understanding), the origin will be manipulated and the removing of columns will be done on the visual Tree View.
It seem as if my arguments in the method call is always done as call-by-reference.
Code:
"treeview1" is the visual Gtk.Tree View...
I call my Export-function:
...
TreeView treeviewExport = SetExportViewAccordingToCheckboxes(treeview1);
ExportFile(treeviewExport);
...
In the method SetExportViewAccordingToCheckboxes() I just pass the global treeview1 as call-by-value, manipulate it internally and return the manipulated Tree View:
protected static TreeView SetExportViewAccordingToCheckboxes(TreeView tvSource)
{
TreeView tvRet = tvSource;
if (cbName == false)
tvRet.RemoveColumn( ... );
...
return tvRet;
}
But even though I have removed the columns from the internal Tree View "tvRet", my visual control "treeview1" lacks all the columns which were removed from "tvRet"; it looks like "treeview1" was passed as call-by-reference.
Question: why is that?
Note: I also tried with the keyword "in" which made no difference:
protected static TreeView SetExportViewAccordingToCheckboxes(in TreeView p_tvSource)
The problem comes here:
In the method SetExportViewAccordingToCheckboxes() I just pass the
global treeview1 as call-by-value, manipulate it internally and return
the manipulated Tree View:
protected static TreeView SetExportViewAccordingToCheckboxes(TreeView tvSource)
{
TreeView tvRet = tvSource;
if (cbName == false)
tvRet.RemoveColumn( ... );
...
return tvRet;
}
First some background. In C# terminology, value types are those that directly contain a value, while reference types are those that reference the data, instead of holding it directly.
So, int x = 5 means that you are creating the value object 5 of type integer, and storing it in x, while TreeView tree = new TreeView() means that you are creating a reference tree of type TreeView, which points to an object of the same type.
All of this means that you cannot pass an object by value, even if you want to. In the best case, you are passing the reference by value, which has no effect.
So, the next step is to copy the data, and modify the copied object instead of the original one. This is theoretically sound, but the line: TreeView tvRet = tvSource; unfortunately does not achieve that. You are creating a new reference, yes, but that reference points to the same object the original reference points to.
Now, say that we are managing objects of class Point instead of TreeView, with properties x and y.
class Point {
public int X { get; set; }
public int Y { get; set; }
}
You can create a point easily:
Point p1 = new Point { X = 5, Y = 7 };
But this does not copy it:
Point p2 = p1;
This would do:
Point p2 = new Point { X = p1.X, Y = p1.Y };
Now the original problem was that you wanted to pass a few columns to an Export() function. In that case, you only need to pass a vector of the filtered columns to the exporting function, instead of a copy of the TreeView.
void PrepareExporting()
{
var columns = new List<TreeViewColumn>();
foreach(TreeViewColumn col in this.treeView.Columns) {
if ( this.Filter( col ) ) {
columns.add( col );
}
}
this.Export( columns.ToArray() );
}
void Export(TreeViewColumn[] columns)
{
// ...
}
I think that would be easier, since it is not needed to try to achieve a pass-by-reference (impossible), nor copy the tree view.
Hope this helps.

JavaFX Check Cell background of specific Cell (random access)

I just started to develop a JavaFX application. Maybe I didn't get how JavaFX uses the TableView and I should use something different instead.
Currently my TableView displays data in multiple columns an when I double-click a cell the background color changes (by setCellFactory(customFactory)).
Now I want to access different cells of the table by using indices (column,row) and checking the background color.
The cells with a changed background color should be stored after a certain button was clicked.
I would like to get every cell with changed background(get celltext) for each row and store this for later use in a data structure like a Map>.
Would be really nice if somebody can give me a hint. Thank for your Help.
I suppose, you are adding an EventHandler to the TableCell, which is returned by your customFactory. This EventHandler is handling the doubleclick-event and sets the background color, right?
This handler has access to the parameter which is passed to the Callbacks/CustomFactories call-method, which contains the model-bean of the current row. You could set a flag or the columns name in that model-bean when a doubleClickEvent occurs.
Then
after a certain button was clicked
you can get your info, by checking the tables items. The row-index of each item is equivalent to the index of this item in the List of TableView#getItems
Also have a look at http://controlsfx.bitbucket.org/org/controlsfx/control/spreadsheet/SpreadsheetView.html if you need more TableFunctions.
EDITED
This is a code-example:
The Model-Bean used in TableView:
class Model {
private String propertyA;
private String propertyB;
#lombok.Getter
private Set<String> propertiesClicked = new HashSet<>();
The javafx-controls, annotate them with #FXML if you use FXMLs:
private TableView<Model> tableView;
private TableColumn<Model, String> propertyAColumn;
private TableColumn<Model, String> propertyBColumn;
and the the CellFactory. Create a more generic CellFactory if you need it for multiple columns:
propertyAColumn.setCellFactory((value) -> {
TableCell<Model, String> tableCell = new TableCell<Model, String>() {
//Override the Methods which you need
};
tableCell.setOnMouseClicked((mouseEvent) -> {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2 && !tableCell.getStyleClass().contains("buttonClicked")) {
tableCell.getStyleClass().add("buttonClicked");
tableView.getSelectionModel().getSelectedItem().getPropertiesClicked().add("propertyA");
}
}
});
return tableCell;
});

SharePoint 2010: Error Mapping to Picture Hyperlink with SPMetal

Whenever I have a column of type hyperlink with the format set for pictures, I get an error whenever there is actually a value in that column.
The exception it throws is "Specified cast is not valid".
My thought is that the problem is either here (the FieldType being set to Url):
[Microsoft.SharePoint.Linq.ColumnAttribute(Name = "FOO", Storage = "FOO_", FieldType = "Url")]
public string FOO
{
get
{
return this._FOO;
}
set
{
if ((value != this._FOO))
{
this.OnPropertyChanging("FOO", this._FOO);
this._FOO = value;
this.OnPropertyChanged("FOO");
}
}
}
Or here (it being cast to a string):
private string _FOO;
But I'd have no idea what the proper values for either of those fields should be.
Any help would be greatly appreciated.
It works whenever this field does not have data in it and I JUST used SPMetal to generate the class, so I'll get the two most obvious questions out of the way.
Link to the answer:
https://mgreasly.wordpress.com/2012/06/25/spmetal-and-workflow-associations/
Turns out it is a known bug when mapping lists that have associated workflows.
SPMetal assigns it as a nullable integer when it's supposed to be an Object, hence the cast error.
Workaround: manually edit the mappings to make the type it returns an object or ignore the column by using a parameter map.

How to create new instance of a view/viewmodel when navigation occurs with Prism

I am trying to control when a new view is created and when an existing view is shown.
This is a very similar scenario as outlined in the "Navigating to Existing Views" section in the Prism documentation, but I can't get it to work fully:
http://msdn.microsoft.com/en-us/library/gg430861(v=pandp.40).aspx
I am finding I can create the view/view model to begin with ok, but I am then unable to create a new instance of it. I.e. I want more than one instance to exist at once.
Here's an example of the view model:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class DataEntryPageViewModel : INavigationAware, IRegionMemberLifetime
{
private Guid id;
[ImportingConstructor]
public DataEntryPageViewModel()
{
id = Guid.NewGuid();
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// In actual fact there would be more logic here to determine
// whether this should be shown to the user
return false;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
}
public bool KeepAlive
{
// For the purposes of this example we don't want the view or the viewModel
// to be disposed of.
get { return true; }
}
}
I am navigating to this as follows:
m_RegionManager.RequestNavigate(
"MainRegion",
new Uri("/DataEntryPageView", UriKind.Relative));
So the first time I call the above the view is shown.
The next time I call RequestNavigate the IsNavigationTarget is hit and it returns false. What I then want it to do is to create a new instance but that doesn't happen. I know it's not happening because the constructor does not get hit and the UI does not update to show the new instance of the view.
Any ideas how I can make it create a new instance?
Many thanks,
Paul
Edit
I have noticed that the second time I call RequestNavigate (to request another instance of the same view) the callback reports an error "View already exists in region." It therefore seems that I can have multiple instances of different views in a region, but not multiple instances of the same view. My understand of this isn't great though so I could be wrong.
Why are you not creating the view when you want a new one to be created? It looks to me like you are using MEF.
Use the container to resolve a new instance of your view
Add the new instance of the view to the MainRegion
Then call Navigate and handle the appropriate logic in IsNavigationTarget
You should use the [Export] attribute in your view with a contract name: [Export("DataEntryPageView")].
I have now been able to get this to work, it was because I didn't have
[PartCreationPolicy(CreationPolicy.NonShared)]
on the class declaration of the view. I had it on the ViewModel.
So this is now resulting in the behaviour I expected.
Thanks though to Zabavsky and Alan for your suggestions.