Scenario:
I have a parent window called EditClientDeatils.fxml and have a TableView on this. I am editing these row result by creating another window named UserDetails.fxml and populating the row data to this FXML fields, now after editing from my second window , If I save I need to update the parent table with latest data.I tried something like below and not refreshing the table at all. But when I debugged my table list is updated with latest Data and not showing that in Window.
So How can I update my table view from different controller ?
In Child Window I am loading the parent like this.
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("EditClientDetails.fxml"));
EditClientDetailsController fooController = (EditClientDetailsController) fxmlLoader.getController();
try {
fxmlLoader.load();
} catch (IOException ex) {
Logger.getLogger(NewUserController.class.getName()).log(Level.SEVERE, null, ex);
}
And in my parent class initialize method having below code:
#Override
public void initialize(URL url, ResourceBundle rb) {
fNameCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientFirstName"));
lNameCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientLastName"));
addressCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientAddress"));
mobileCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientMobileNumber"));
emailCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientEmailID"));
catagoryCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("clientTypeCode"));
genderCol.setCellValueFactory(
new PropertyValueFactory<AtUser, String>("gender"));
editSaveAction.setSortable(false);
editSaveAction.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<AtUser, Boolean>,
ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<AtUser, Boolean> p) {
return new SimpleBooleanProperty(p.getValue() != null);
}
});
editSaveAction.setCellFactory(
new Callback<TableColumn<AtUser, Boolean>, TableCell<AtUser, Boolean>>() {
#Override
public TableCell<AtUser, Boolean> call(TableColumn<AtUser, Boolean> p) {
return new ClientButtonCell(customerTable);
}
});
// Add filtered data to the table
customerTable.setItems(filteredData);
// Listen for text changes in the filter text field
filterField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
updateFilteredData();
}
});
}
When I am debugging
customerTable.setItems(filteredData);
this filteredData is containing my required data but not coming on Window.
please point out if I missed anything.
I had the same issue, and found this work arround it, to force it to refresh.
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
After modifing the table items list.
Related
My CardView duplicate elements upon data change, the vardView is within a tab, and the way i declared that tab fragment as following;
in the onCreateView, i declared all the necessary firebase links and value events listeners to retrieve the required data related to the elements displayed on the cards.
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if(snapshot !=null){
for (DataSnapshot child: snapshot.getChildren()) {
Log.i("MyTag", child.getValue().toString());
imagesfeedsList.add(child.child("address").getValue(String.class));
authorfeedsList.add(child.child("author").getValue(String.class));
ratingfeedsList.add(child.child("rating").getValue(String.class));
locationfeedsList.add(child.child("location").getValue(String.class));
publicIDfeedsList.add(child.child("public_id").getValue(String.class));
}
Log.i("MyTag_imagesDirFinal", imagesfeedsList.toString());
mImages = imagesfeedsList.toArray(new String[imagesfeedsList.size()]);
author = authorfeedsList.toArray(new String[authorfeedsList.size()]);
ratingV = ratingfeedsList.toArray(new String[ratingfeedsList.size()]);
locationV = locationfeedsList.toArray(new String[locationfeedsList.size()]);
publicID = publicIDfeedsList.toArray(new String[publicIDfeedsList.size()]);
numbOfAdrs = Long.valueOf(imagesfeedsList.size());
LENGTH = Integer.valueOf(String.valueOf(numbOfAdrs));
}
right after the snippet the adapter setup;
ContentAdapter adapter = new ContentAdapter(recyclerView.getContext());
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
return recyclerView;
}
Then comes the view holder with a RecycleView, declaring the cardView elements. One of the elements is a ratingBar, and here where the ratingbar Listener is to submit the user rating on a specific picture.
after that the content adapter;
public static class ContentAdapter extends RecyclerView.Adapter<ViewHolder> {
// Set numbers of List in RecyclerView.
private Context mContext;
public ContentAdapter(Context context) {
this.mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()), parent);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.authorName.setText(author[position]);
holder.ratingValue.setText(ratingV[position]);
holder.locationValue.setText(locationV[position]);
Picasso.with(mContext).load(mImages[position]).into(holder.picture);
#Override
public int getItemCount() {
return LENGTH;
}
}
My problem is whenever the user submits a rating or even when the data related to any of the elements on anycard changes, the view gets duplicated ( i mean by the view, the cards ), a repetition of the cards, with the new data chnages displayed ?
i a not sure what is in my above code structure causing this and how to fix this repetitions, i mean i need the cards to be updated with the new data but not duplicated?
All right, so the problem was that every time the data changes, in the onCreate the imagesFeedList, ratingFeedList, etc does not get rid of the old information stored in it from the initial build, so when the refresh happens triggered by onDataChange, the new information gets added to the previous information, which cause the view to repeat the cards, thus just at the beginning of onDataChange and before storing any information in the several feedLists, it must be cleared;
imagesfeedsList.clear();
authorfeedsList.clear();
ratingfeedsList.clear();
locationfeedsList.clear();
publicIDfeedsList.clear();
and by that i made sure the view does not repeat build up based on old information.
I have defined a CheckBoc TableColumn as
#FXML private TableColumn<Batch, Boolean> sltd;
And have defined the CellValueFactory & CellFactory
sltd.setCellValueFactory(new PropertyValueFactory<Batch, Boolean>("pr"));
sltd.setCellFactory(CheckBoxTableCell.forTableColumn(sltd));
My problem is i am not able to capture the edit column event for the checkbox. I use the following code:
sltd.setOnEditStart(new EventHandler<TableColumn.CellEditEvent<Batch, Boolean>>() {
#Override
public void handle(TableColumn.CellEditEvent<Batch, Boolean> t) {
//System.out.println("CheckBox clicked.");
}
});
I don't think the check boxes in the CheckBoxTableCell invoke the startEdit(...) method on the table.
The only thing that can happen in an edit is that the boolean property of one of the items in the table changes from true to false, or vice versa. So you can check for this just by listening directly to those boolean properties.
If you want a single listener that will catch changes to any of the properties, you can create an observableList with an "extractor" and register a list change listener with the list. This looks like:
ObservableList<Batch> items = FXCollections.observableArrayList(new Callback<Batch, Observable[]>() {
#Override
public Observable[] call(Batch batch) {
return new Observable[] { batch.prProperty() } ;
}
}
// populate items
table.setItems(items);
items.addListener(new ListChangeListener<Batch>() {
#Override
public void onChanged(Change<? extends Batch> change) {
while (change.hasNext()) {
if (change.wasUpdated()) {
System.out.println("Item at "+change.getFrom()+" changed value");
}
}
}
});
I developed RssFeed Application using LWUIT j2me(java) for 2 xml files, now I want to show those 2 xml files on LWUIT Tabs.
That means, when my application runs, default tab will be displayed (on that tab my first Rss xml file Titles should be displayed), and when the user click on tab2 my second Rss xml titles should be displayed.
I am able to display the same titles of one rss files on both the tabs, how to control my flow to achieve my task?
Here my code:
public class XMLMidlet extends MIDlet implements ActionListener {
public XMLMidlet() {
Display.init(this);
news = new Vector();
m_backCommand = new Command("Back");
cmdExit = new Command("EXIT");
cmdDetails = new Command("Details");
}
public void startApp() {
//RssFeed URL's
String urls[] = {"http://topnews-23.rss",
"http://topstory-12.rss"};
for(int i=0;i<urls.length;i++){
ParseThread myThread = new ParseThread(this,urls[i]);
//this will start the second thread
myThread.getXMLFeed(urls[i]);
}
}
//method called by the parsing thread
public void addNews(News newsItem,String url) {
try{
news.addElement(newsItem);
form1 = new Form();
myNewsList = new List(newsVector);
newsList =new List(newsVector);
myNewsList.setRenderer(new NewsListCellRenderer());
newsList.setRenderer(new NewsListCellRenderer());
tabs=new Tabs(Component.TOP);
tabs.addTab("TopNews", myNewsList);
tabs.addTab("Topstory",newsList);
form1.addComponent(tabs);
form1.show();
}
catch(Exception e){
e.printStackTrace();
}
}
You should move below code
myNewsList = new List(newsVector);
newsList =new List(newsVector);
myNewsList.setRenderer(new NewsListCellRenderer());
newsList.setRenderer(new NewsListCellRenderer());
tabs=new Tabs(Component.TOP);
form1 = new Form();
tabs=new Tabs(Component.TOP);
tabs.addTab("TopNews", myNewsList);
tabs.addTab("Topstory",newsList);
from addNews method to constructor XMLMidlet. addNews method should use url parameter to differ for which list the newsItem is directed.
Update
Below is how I think you should implement addNews method:
public void addNews(News newsItem, String url) {
if (url.endsWith("topnews-20.rss")) {
myNewsList.addElement(newsItem);
} else if (url.endsWith("topstory-25.rss")) {
newsList.addElement(newsItem);
}
}
serRenderer does not need to be called from addNews and form1.show() should be moved to startApp.
As I'm learning the new world of JavaFX2 I stumbled on another annoying problem. I'm developing a program with multiple scenes (~10 scenes). For that I created a small class like this:
public class SceneSelector {
...
public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
String s = "../" + fxmlfilename;
Parent root = FXMLLoader.load(getClass().getResource(s));
root.setUserData(ol);
Scene scene = new Scene(root);
stage.setScene(scene);
//show the stage
stage.show();
}
}
This class works good enough for switching between the scenes.
Now the problem is that I sometimes need to pass data from Scene1 to Scene2. I'm trying to do this by setting the setUserData() for the new scene which basicly works exept for one thing. How can I get the userdata when the new Scene is beeing initialized? (because the Nodes are still null at that time)
Code at scene1:
//Code connected to a button that opens the new Scene
private void openLabID(ActionEvent event) throws Exception {
final Stage primaryStage = (Stage) btnNewScene.getScene().getWindow();
ObservableList<Koe> olAfTeWerkenKoeien = DA_Koe.getAfTeWerkenKoeien();
ss.setScene(primaryStage, "GUI/scenes/koe/Koe.fxml", olAfTeWerkenKoeien);
}
Code at scene2:
public void initialize(URL url, ResourceBundle rb) {
Scene s = lbl.getScene();
ObservableList<Koe> olAfTeWerkenKoeien = (ObservableList<Koe>) s.getRoot().getUserData();
System.out.println(olAfTeWerkenKoeien.size());
}
Of course Scene s gives a null value at this point (because lbl is null at this point), so I wonder, is there a method that is beeing fired right after initialize?
When I attach this code to a button on Scene2, it works like a charm, but it should be loaded automatically.
EDIT:
The setting of the data with the setMyData() method is not a problem, however retrieving it is:
public ObservableList<Koe> getMyData() {
return this.myData;
}
How can I get the CustomScene object when a controller initializes? Because doing this below will result in a NullPointerException (because btnSluiten is not initialized just yet):
#Override
public void initialize(URL url, ResourceBundle rb) {
...
Stage stage = (Stage) btnSluiten.getScene().getWindow();
CustomScene cs = (CustomScene) stage.getScene();
ObservableList<Koe> olKoe = cs.getMyData();
System.out.println(olKoe.size());
}
I believe you missed the point within the Scene object. From the Scene class documentation we can see that:
The JavaFX Scene class is the container for all content in a scene graph.
Which means that the Scene object is just a container and as such it's not supposed to hold any data.
With that in mind, you can make another static object with a field such as
private static Label lbl;
...
public static Label getLbl()
{
return MyStaticObject.Lbl;
}
...
and use it to store your lbl (or whatever object suits your information) and then statically retrieve it.
I'm doing that to set the owner of my other Stage objects from my application. I hope it helps. Cheers
If you really want your scene to be meaningful (aka store specific user data) you can extend it:
public class FooScene extends Scene {
private ObservableList myData;
public setMyData(ObservableList data) {
this.myData = data;
//handle data
}
}
The easiest way to make sure setup code is called after scene initialized it to call it by yourself:
public class SceneSelector {
...
public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
String s = "../" + fxmlfilename;
Parent root = FXMLLoader.load(getClass().getResource(s));
// first: add root to scene
FooScene scene = new FooScene(root);
// second: apply data to scene (or root)
scene.setMyData(ol);
stage.setScene(scene);
//show the stage
stage.show();
}
}
You can use controller for scenes and pass the data through controller:
String filePath1 = "../" + fxmlfilename;
URL location1 = YourController1.class.getResource(filePath1);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location1);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Node) fxmlLoader.load(location1.openStream());
YourController1 ctrl1 = (YourController1) fxmlLoader.getController();
Then you can assign data to the controller:
ctrl1.setUserData();
Finally, just show the scene as you want:
Scene scene = new Scene(root);
stage.setScene(scene);
//show the stage
stage.show();
In the initialize() method in the controller, just get data from controller as usual data object.
Some Addition of #Sergey Grinev :
Create A custom Scene :
package sample;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class DataPassingScene extends Scene {
public DataPassingScene(Parent parent) {
super(parent);
}
String tafsir;
public String getTafsir() {
return tafsir;
}
public void setTafsir(String tafsir) {
this.tafsir = tafsir;
}
}
Suppose your Main Class Name is App.java, Then Create a method to show new Stage :
public static void showLayout (Stage primaryStage, String fxmlFileName, String stringData) throws IOException {
Parent root = FXMLLoader.load(Objects.requireNonNull(App.class.getClassLoader().getResource(fxmlFileName)));
DataPassingScene scene = new DataPassingScene(root);
scene.setTafsir(stringData); // Here we pass the data
primaryStage.setScene(scene);
primaryStage.show();
}
Now When you want to pass the Data, Call the above method from any Where / any class in your app with some Data :
String tafsir = "This My Data" ;
try {
App.showLayout(new Stage(), "showTafsirFxml.fxml",tafsir);
} catch (IOException e) {
e.printStackTrace();
}
Then Get the data in your controller. To get the scene you have to get the stage, and to get the stage you have use one of your elements of FXML, suppose here your element is a button, called closeButton, So :
#FXML
private Button closeButton;
#Override
public void initialize(URL url, ResourceBundle rb) {
Platform.runLater(new Runnable() {
#Override public void run() {
Stage stage = (Stage) closeButton.getScene().getWindow();
DataPassingScene scene = (DataPassingScene) stage.getScene();
String s = scene.getTafsir(); // Here we get the Data
if(s!=null)
System.out.println("This is Tafsir From Highlight Table: "+s);
else
System.out.println("Data Passing Null");
}});
}
because, You have to wait some Times in above runLater, because for initializing scene take some time. Other wise scene will be null.
From this example http://www.smartclient.com/smartgwt/showcase/#tree_databinding_local , I started to implement my own tree structure dynamically (TreeGrid). When I try to render it, I get this error (title).
public class ProjectTreeGridScreen extends Screen {
Tree tree;
#Override
protected void onLoad() {
super.onLoad();
TreeGrid treeGrid = new TreeGrid();
setPageTitle(Util.C.projectListTitle());
treeGrid.setWidth(600);
treeGrid.setHeight(400);
TreeGridField projectTree = new TreeGridField("ProjectName", "Project Tree");
TreeGridField projectPath = new TreeGridField("ProjectPath", "Complete path");
TreeGridField projectDescription = new TreeGridField("ProjectDescription", "Description");
TreeGridField projectInfo = new TreeGridField("ProjectInfo", "Information");
treeGrid.setFields(projectTree, projectPath, projectDescription, projectInfo);
treeGrid.setData(tree);
add(treeGrid);
}
#Override
protected void onInitUI() {
super.onInitUI();
tree = new Tree();
tree.setModelType(TreeModelType.PARENT);
tree.setNameProperty("ProjectName");
tree.setIdField("ProjectItem");
tree.setParentIdField("ProjectParent");
tree.setShowRoot(true);
populateProjects();
}
protected void populateProjects() {
Util.PROJECT_SVC.visibleProjects(
new ScreenLoadCallback<List<Project>>(this) {
#Override
public void preDisplay(final List<Project> result) {
tree.setData(ProjectTreeGridBuilder.fromRepositories(result));
}
});
}
}
what do you mean by "x"? Normally, If a component has been drawn on the window (implicit or explicit call to draw), you cannot change it's properties values. So the only possible solution is to recreate the object with the new X value each time it is changing.