JavaFX2: Add rows to a TableView that uses Table Cell Binding - binding

I am attempting to modify the solution outlined in UITableView - Better Editing through Binding? (Thank you, jKaufmann, for that excellent example) to allow adding rows to the table.
I have introduced a button that, when clicked, invokes code to add an additional TableData row to the ObservableList backing the table.
The new row shows up without incident. However, after a few rows are added and you scroll through the table using the Up/Down keys a couple of times, random rows in the table start getting replaced with a blank row.
It usually takes adding a couple of rows, selecting a row, traversing down the list (using the keyboard) to the new row, adding a couple more rows, traversing down to the new row and all the way to the top again to reproduce the issue. To select a row in the table, I click on the edge of a row, so that the row is selected rather than an individual cell.
The source code (essentially jkaufmann's example modified to include an 'Add Row' button) is here.
package tablevieweditingwithbinding;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewEditingExample2 extends Application {
public static class TableData {
private SimpleStringProperty firstName, lastName, phone, email;
private ObjectProperty<SimpleStringProperty> firstNameObject;
public TableData(String firstName, String lastName, String phone, String email) {
this.firstName = new SimpleStringProperty(firstName);
this.firstNameObject = new SimpleObjectProperty(firstNameObject);
this.lastName = new SimpleStringProperty(lastName);
this.phone = new SimpleStringProperty(phone);
this.email = new SimpleStringProperty(email);
}
public String getEmail() {
return email.get();
}
public void setEmail(String email) {
this.email.set(email);
}
public SimpleStringProperty emailProperty() {
return email;
}
public String getFirstName() {
return firstName.get();
}
public SimpleStringProperty getFirstNameObject() {
return firstNameObject.get();
}
public void setFirstNameObject(SimpleStringProperty firstNameObject) {
this.firstNameObject.set(firstNameObject);
}
public ObjectProperty<SimpleStringProperty> firstNameObjectProperty() {
return firstNameObject;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public SimpleStringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public SimpleStringProperty lastNameProperty() {
return lastName;
}
public String getPhone() {
return phone.get();
}
public void setPhone(String phone) {
this.phone.set(phone);
}
public SimpleStringProperty phoneProperty() {
return phone;
}
}
public static class TextFieldCellFactory
implements Callback<TableColumn<TableData, String>, TableCell<TableData, String>> {
#Override
public TableCell<TableData, String> call(TableColumn<TableData, String> param) {
TextFieldCell textFieldCell = new TextFieldCell();
return textFieldCell;
}
public static class TextFieldCell extends TableCell<TableData, String> {
private TextField textField;
private StringProperty boundToCurrently = null;
public TextFieldCell() {
String strCss;
// Padding in Text field cell is not wanted - we want the Textfield itself to "be"
// The cell. Though, this is aesthetic only. to each his own. comment out
// to revert back.
strCss = "-fx-padding: 0;";
textField = new TextField();
//
// Default style pulled from caspian.css. Used to play around with the inset background colors
// ---trying to produce a text box without borders
strCss = ""
+ //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
"-fx-background-color: transparent;"
+ //"-fx-background-insets: 0, 1, 2;" +
//"-fx-background-insets: 0;" +
//"-fx-background-radius: 3, 2, 2;" +
//"-fx-background-radius: 0;" +
//"-fx-padding: 3 5 3 5;" + /*Play with this value to center the text depending on cell height??*/
//"-fx-padding: 0 0 0 0;" +
//"-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
//"-fx-accent: derive(-fx-control-inner-background, -40%);" +
"-fx-cell-hover-color: derive(-fx-control-inner-background, -20%);"
+ "-fx-cursor: text;"
+ "";
//
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
TextField tf = (TextField) getGraphic();
String strStyleGotFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;"
+ "-fx-background-insets: -0.4, 1, 2;"
+ "-fx-background-radius: 3.4, 2, 2;";
String strStyleLostFocus = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
"-fx-background-color: transparent;"
+ //"-fx-background-insets: 0, 1, 2;" +
"-fx-background-insets: 0;"
+ //"-fx-background-radius: 3, 2, 2;" +
"-fx-background-radius: 0;"
+ "-fx-padding: 3 5 3 5;"
+ /**/ //"-fx-background-fill: green;" + /**/
//"-fx-background-color: green;" +
"-fx-background-opacity: 0;"
+ //"-fx-opacity: 0;" +
//"-fx-padding: 0 0 0 0;" +
"-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);"
+ "-fx-cursor: text;"
+ "";
if (newValue.booleanValue()) {
tf.setStyle(strStyleGotFocus);
} else {
tf.setStyle(strStyleLostFocus);
}
}
});
textField.setStyle(strCss);
this.setGraphic(textField);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// Retrieve the actual String Property that should be bound to the TextField
// If the TextField is currently bound to a different StringProperty
// Unbind the old property and rebind to the new one
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp = (SimpleStringProperty) ov;
if (this.boundToCurrently == null) {
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(sp);
} else {
if (this.boundToCurrently != sp) {
this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(this.boundToCurrently);
}
}
System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
}
private final TableView<TableData> table = new TableView<TableData>();
final ObservableList<TableData> ol =
FXCollections.observableArrayList(
new TableData("Wilma", "Flintstone", "555-123-4567", "WFlintstone#gmail.com"),
new TableData("Fred", "Flintstone", "555-123-4567", "FFlintstone#gmail.com"),
new TableData("Barney", "Flintstone", "555-123-4567", "Barney#gmail.com"),
new TableData("Bugs", "Bunny", "555-123-4567", "BugsB#gmail.com"),
new TableData("Yo", "Sam", "555-123-4567", "ysam#gmail.com"),
new TableData("Tom", "", "555-123-4567", "tom#gmail.com"),
new TableData("Jerry", "", "555-123-4567", "Jerry#gmail.com"),
new TableData("Peter", "Pan", "555-123-4567", "Ppan#gmail.com"),
new TableData("Daffy", "Duck", "555-123-4567", "dduck#gmail.com"),
new TableData("Tazmanian", "Devil", "555-123-4567", "tdevil#gmail.com"),
new TableData("Mickey", "Mouse", "555-123-4567", "mmouse#gmail.com"),
new TableData("Mighty", "Mouse", "555-123-4567", "mimouse#gmail.com"));
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
static int counter = 1;
#Override
public void start(Stage Stage) {
Stage.setTitle("Editable Table");
BorderPane borderPane = new BorderPane();
Scene scene = new Scene(borderPane, 800, 600);
// top of border pane
Button b1 = new Button("Change value in table list");
Button b2 = new Button("Add row");
HBox hbox = new HBox(10);
hbox.setStyle("-fx-background-color: #336699");
hbox.setAlignment(Pos.BOTTOM_CENTER);
HBox.setMargin(b2, new Insets(10, 0, 10, 0));
HBox.setMargin(b1, new Insets(10, 0, 10, 0));
hbox.getChildren().addAll(b1, b2);
borderPane.setTop(hbox);
BorderPane.setAlignment(hbox, Pos.CENTER);
// Button Events
b1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String curFirstName = ol.get(0).getFirstName();
if (curFirstName.contentEquals("Jason")) {
ol.get(0).setFirstName("Paul");
} else {
ol.get(0).setFirstName("Jason");
}
}
});
b2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.runLater(new Runnable() {
#Override
public void run() {
int dataListSize = 0;
dataListSize = ol.size();
System.out.println("Table size = " + dataListSize);
ol.add(new TableData("firstName" + counter,
"lastName" + counter,
"phone" + counter,
"email" + counter++));
dataListSize = ol.size();
System.out.println("Table size = " + dataListSize);
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
}
});
}
});
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setItems(ol);
borderPane.setCenter(table);
BorderPane.setAlignment(table, Pos.CENTER);
BorderPane.setMargin(table, new Insets(25));
// Add columns
TableColumn<TableData, String> c1 = new TableColumn<TableData, String>("FirstName");
c1.setCellValueFactory(new PropertyValueFactory<TableData, String>("firstName"));
c1.setCellFactory(new TextFieldCellFactory());
TableColumn<TableData, String> c2 = new TableColumn<TableData, String>("LastName");
c2.setCellValueFactory(new PropertyValueFactory<TableData, String>("lastName"));
c2.setCellFactory(new TextFieldCellFactory());
TableColumn<TableData, String> c3 = new TableColumn<TableData, String>("Phone");
c3.setCellValueFactory(new PropertyValueFactory<TableData, String>("phone"));
c3.setCellFactory(new TextFieldCellFactory());
TableColumn<TableData, String> c4 = new TableColumn<TableData, String>("Email");
c4.setCellValueFactory(new PropertyValueFactory<TableData, String>("email"));
c4.setCellFactory(new TextFieldCellFactory());
table.getColumns().addAll(c1, c2, c3, c4);
scene.getStylesheets().add(TableViewEditingWithBinding.class.getResource("styles.css").toExternalForm());
Stage.setScene(scene);
Stage.show();
}
}
I tried adding the following code
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
in the handler for the addRow button after the row was added, but that didn't help any. I also tried clearing the backing observable list and resetting the value to the list + the new row after each row was added; that did not solve the issue either.
Any help would be most appreciated.

I had the same problem. After deleting one row some other rows are blanked out. If I scrolled the blank rows changed.
My solution was to move the line
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
to the constructor of the cell and to remove the line
setContentDisplay(ContentDisplay.TEXT_ONLY);
completely.
The API doc of Cell.updateItem states
empty - whether or not this cell represents data from the list. If it is empty, then it does not represent any domain data, but is a cell being used to render an "empty" row.
For me this looks like a bug in JavaFX because all my rows are backed with domain data but still some of them (changing when scrolling) receive an updateItem() with empty=true.

Related

cursorboundexception whille displaying listview from content provider

somebody pls get me out of this.I am trying to display a list from an sqlite database which worked absolutely fine but dont know what went wrong it showed cant find provider info.I fixed it and then when i am running the code with list_cursor.moveToFirst() it just shows the 1st item in list again and again which proves that it is fetching data....When I use list_cursor.moveToNext() it shows the following exception:PLS HELP ME
10-13 15:11:41.017 5337-5337/com.phase3.mascotnew E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.phase3.mascotnew, PID: 5337
android.database.CursorIndexOutOfBoundsException: Index 3 requested, with a size of 3
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:147)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:61)
at android.database.CursorWrapper.getString(CursorWrapper.java:114)
at com.phase3.mascotnew.SelectRecipeActivity$MyCursorAdapter.getView(SelectRecipeActivity.java:145)
at android.widget.AbsListView.obtainView(AbsListView.java:2338)
at android.widget.ListView.makeAndAddView(ListView.java:1813)
at android.widget.ListView.fillDown(ListView.java:698)
at android.widget.ListView.fillFromTop(ListView.java:759)
at android.widget.ListView.layoutChildren(ListView.java:1646)
at android.widget.AbsListView.onLayout(AbsListView.java:2149)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1160)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15140)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2474)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2180)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6412)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5299)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
at dalvik.system.NativeStart.main(Native Method)
SelectRecipeActivity.java
package com.phase3.mascotnew;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import com.phase3.mascotnew.database.Tables.Recipe;
import java.io.File;
public class SelectRecipeActivity extends Activity {
private ListView mListView = null;
private Cursor mCursor = null;
private SimpleCursorAdapter adapter;
private static final String TAG = "SELECT RECIPE ACTIVITY";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_recipe2);
mListView = (ListView) findViewById(R.id.recipe_list);
createRecipeSubFolder();
showTableItems();
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor=(Cursor)mListView.getAdapter().getItem(position);
Log.i(TAG, "Fetching item position" + position);
String pass_recname = cursor.getString(cursor.getColumnIndex(Recipe.NAME_NIC));
int pass_groupid = (cursor.getInt(cursor.getColumnIndex(Recipe.GROUPID_NIC)));
Log.i(TAG, "Fetching data" + " " + pass_recname + " " + pass_groupid);
cursor.close();
Intent i = new Intent(SelectRecipeActivity.this, WhatYouNeedActivity.class);
i.putExtra("Title", pass_recname);
i.putExtra("GroupId", pass_groupid);
startActivity(i);
Log.i(TAG, "Sending Data");
}
});
}
#Override
protected void onResume() {
super.onResume();
showTableItems();
}
#Override
protected void onPause() {
super.onPause();
if(mCursor != null){
mCursor.close();
mCursor = null;
}
}
public void showTableItems() {
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
int StatusVal=1;
String Status=Recipe.STATUS+"="+ StatusVal;
//String selection=Recipe.GROUPID;
//String selection = Recipe.GROUPID + " "+ "AND"+" "+Status;
mCursor = getContentResolver().query(Recipe.CONTENT_URI, Recipe.PROJECTION_ALL,Status, null, null);
if (mCursor == null || mCursor.getCount() == 0) {
notifyDataExist(false);
return;
}
notifyDataExist(true);
String[] from = {Recipe.NAME_NIC};
int[] to = {R.id.recname_row};
Log.i(TAG, "Setting Adapter");
adapter = new MyCursorAdapter(this, R.layout.list_recipes_row, mCursor, from, to);
mListView.setAdapter(adapter);
}
private void notifyDataExist(boolean exist)
{
if(exist)
{
mListView.setVisibility(View.VISIBLE);
}
else
{
Log.i(TAG, "Recipe Table has no data");
mListView.setVisibility(View.GONE);
}
}
class MyCursorAdapter extends SimpleCursorAdapter {
Activity mActivity = null;
int mLayoutId;
String[] from = null;
int[] to = null;
public MyCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
super(context, layout, cursor, from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
mActivity = (Activity) context;
mLayoutId = layout;
this.from = from;
this.to = to;
}
#Override
public int getCount() {
return mCursor.getCount() + 1;
}
#Override
#TargetApi(15)
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
row = mActivity.getLayoutInflater().inflate(mLayoutId, null, false);
}
Cursor list_cursor = getCursor();
list_cursor.moveToPosition(position);
list_cursor.moveToNext();
TextView txtSecondCell = (TextView) row.findViewById(R.id.recname_row);
String recipename = list_cursor.getString(list_cursor.getColumnIndex(Recipe.NAME_NIC));
txtSecondCell.setText(recipename);
Log.i(TAG, "Showing List");
return row;
}
}
private void createRecipeSubFolder(){
Cursor cursor1 = getContentResolver().query(Recipe.CONTENT_URI, Recipe.PROJECTION_ALL, null, null, null);
while(cursor1.moveToNext()){
// String path = Environment.getExternalStorageDirectory()
// + File.separator + "/MASCOT/" + File.separator
// + "/Recipe/" + File.separator + cursor.getString(cursor.getColumnIndex(Recipe.NAME_NIC));
// Log.i("Recipes", cursor.getString(cursor.getColumnIndex(Recipe.NAME_NIC)));
File recipeDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/MASCOT1/Recipe/" + cursor1.getString(cursor1.getColumnIndex(Recipe.NAME_NIC)) + "/");
if(!recipeDir.exists()) {
recipeDir.mkdirs();
Log.i("Recipes Dirs", recipeDir.getName());
}
}
cursor1.close();
}
}
Try this solution
#Override
#TargetApi(15)
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
row = mActivity.getLayoutInflater().inflate(mLayoutId, null, false);
}
Cursor list_cursor = getCursor();
list_cursor.moveToPosition(position);
if(!list_cursor.isLast()){
list_cursor.moveToNext();
TextView txtSecondCell = (TextView) row.findViewById(R.id.recname_row);
String recipename = list_cursor.getString(list_cursor.getColumnIndex(Recipe.NAME_NIC));
txtSecondCell.setText(recipename);
Log.i(TAG, "Showing List");
}
return row;
}

How to give a Contextmenu to same tableview according to Action in javafx?

I have a combobox and a table. Combobox have two items they are type1 and type2. When i select type1 from combo then table contextmenu shows "type1 menu" and When i select type2 from combo then table contextmenu shows "type2 menu". How to do this figure out?
Here is my experiment Code.... But its not work correctly..!
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TableViewSample extends Application {
private final TableView<Person> table = new TableView<>();
private final ComboBox<String> combo = new ComboBox<>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(500);
final Label label = new Label("Right Click a table Row");
label.setFont(new Font("Arial", 20));
combo.getItems().setAll("Type1","Type2");
combo.getSelectionModel().select(0);
table.setEditable(true);
//----------------------- Add table column ------------------------------//
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<>("lastName"));
TableColumn<Person, String> emailCol = new TableColumn<>("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<>("email"));
table.setItems(data);
table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol));
setTableMenu(0); // You Can Comment This //
combo.setOnAction(event -> {
setTableMenu(combo.getSelectionModel().getSelectedIndex());
});
//-------------------------- Final Works ------------------------------//
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, combo, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
//---------- Set What ContextMenu according to the combobox -----------//
private void setTableMenu(int selectedIndex) {
table.setRowFactory((TableView<Person> tableView) -> {
final TableRow<Person> row = new TableRow<>();
switch(selectedIndex){
case 0:
final ContextMenu contextMenu1 = new ContextMenu();
final MenuItem item1 = new MenuItem("Type1 menu");
item1.setOnAction((ActionEvent event) -> {
System.out.println("Type 1 menu selected");
});
contextMenu1.getItems().add(item1);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu1)
);
break;
case 1:
final ContextMenu contextMenu2 = new ContextMenu();
final MenuItem item2 = new MenuItem("Type2 menu");
item2.setOnAction((ActionEvent event) -> {
System.out.println("Type 2 menu selected");
});
contextMenu2.getItems().add(item2);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu2)
);
}
return row ;
});
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
Changing the rowFactory won't update the TableRows. The rows will still be the ones created by the initial rowFactory and the type of context menu is decided when the row is created and is never changed.
You could however prepare the ContextMenu just before it's shown and modify it according to the state of the ComboBox:
// in start method
table.setRowFactory((TableView<Person> tableView) -> {
final TableRow<Person> row = new TableRow<>();
final ContextMenu contextMenu = new ContextMenu();
final MenuItem item1 = new MenuItem("Type1 menu");
item1.setOnAction((ActionEvent event) -> {
System.out.println("Type 1 menu selected");
});
contextMenu.getItems().add(item1);
final MenuItem item2 = new MenuItem("Type2 menu");
item2.setOnAction((ActionEvent event) -> {
System.out.println("Type 2 menu selected");
});
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu)
);
row.setOnContextMenuRequested(evt -> {
// update menu when requested
switch (combo.getSelectionModel().getSelectedIndex()) {
case 0:
contextMenu.getItems().setAll(item1);
break;
case 1:
contextMenu.getItems().setAll(item2);
break;
}
});
return row;
});
/*setTableMenu(0);
combo.setOnAction(event -> {
setTableMenu(combo.getSelectionModel().getSelectedIndex());
});*/
Alternatively you could also use the same ContextMenu for all rows and just modify that on a change in the ComboBox:
// in start method
final MenuItem item1 = new MenuItem("Type1 menu");
item1.setOnAction((ActionEvent event) -> {
System.out.println("Type 1 menu selected");
});
final ContextMenu contextMenu = new ContextMenu(item1);
final MenuItem item2 = new MenuItem("Type2 menu");
item2.setOnAction((ActionEvent event) -> {
System.out.println("Type 2 menu selected");
});
combo.setOnAction(evt -> {
switch (combo.getSelectionModel().getSelectedIndex()) {
case 0:
contextMenu.getItems().setAll(item1);
break;
case 1:
contextMenu.getItems().setAll(item2);
break;
}
});
table.setRowFactory((TableView<Person> tableView) -> {
final TableRow<Person> row = new TableRow<>();
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu)
);
return row;
});
/*setTableMenu(0);
combo.setOnAction(event -> {
setTableMenu(combo.getSelectionModel().getSelectedIndex());
});*/

Recursive method not incrementing string analysis counter in TableView GUI (JavaFX)

EDIT Recursion is required for the counter increment.
I have a GUI that adds entered fields to a ListView, but also adds the name of the object to a TableView beside it and displays four substring counts. They are Plant objects, and it's supposed to display in the ListView (which it does), and then display the name with each occurrence of a certain substring:
See here:
I don't understand what I'm missing, because in my addButtonClick method, I call my recursive method. The logic seems correct to me in the method, so I must be missing something in my Integer properties, or a constructor.
Here is the method in the Controller for the add button click. There is a combo box where a user can choose Flower, Fungus, Weed, or Herb. And when the user clicks a respective plant type, respective radio buttons appear that are related to certain traits. All of that works. I will show the Flower section of code:
/*
Adds respective plant type and resets controls
*/
public void handleAddButtonClick(ActionEvent event) {
if (idInput != null && nameInput != null & colorInput != null) {
if (plantType.getValue().equals("Flower")) {
Flower flower = new Flower(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
flower.setID(idInput.getText());
flower.setName(nameInput.getText());
flower.setColor(colorInput.getText());
flower.setSmell(scentedRadio.isSelected());
flower.setThorns(thornyRadio.isSelected());
observablePlantList.add(flower);
//this is where the table information gets added.
//it adds it, just displays 0's.
flower.setPlantName(nameInput.getText());
Plant.substringCounter(name, "e"); //tried flower instead
Plant.substringCounter(name, "ar");//of Plant. still nothing.
Plant.substringCounter(name, "er");
Plant.substringCounter(name, "o");
observableAnalysisList.add(flower);
//just doing some debug printing. this prints 0
System.out.println(Plant.substringCounter(name, "e"));
//more debugging. this prints fine because of toString() method
System.out.println(flower);
Here is the relevant code in the main class and the Flower class:
//Plant Table properties ("e", "o", "ar", "er")
public StringProperty plantName = new SimpleStringProperty(this, "plantName", "");
public String getPlantName() {return plantName.get(); }
public StringProperty plantNameProperty() {return plantName; }
public void setPlantName(String plantName) {this.plantName.set(plantName); }
public IntegerProperty countLetterE = new SimpleIntegerProperty(this, "countLetterE", 0);
public int getLetterE() {return countLetterE.get();}
public IntegerProperty eProperty() {return countLetterE; }
public void setCountLetterE(int countLetterE) {this.countLetterE.set(countLetterE);}
public IntegerProperty countLetterO = new SimpleIntegerProperty(this, "countLetterO", 0);
public int getLetterO() {return countLetterO.get(); }
public IntegerProperty oProperty() {return countLetterO; }
public void setCountLetterO(int countLetterO) {this.countLetterO.set(countLetterO);}
public IntegerProperty countLetterER = new SimpleIntegerProperty(this, "countLetterER", 0);
public int getLetterER() {return countLetterER.get(); }
public IntegerProperty erProperty() {return countLetterER; }
public void setCountLetterER(int countLetterER) {this.countLetterER.set(countLetterER);}
public IntegerProperty countLetterAR = new SimpleIntegerProperty(this, "countLetterAR", 0);
public int getLetterAR() {return countLetterAR.get(); }
public IntegerProperty arProperty() {return countLetterAR; }
public void setCountLetterAR(int countLetterAR) {this.countLetterAR.set(countLetterAR);}
Recursive method:
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
//toString method for Plant class to display in ListView. Works fine.
public String toString() {
return "ID: " + this.ID + "-" + this.idNum + ", Name: " + this.name + ", Color: " + this.color;
}
}
Flower class
public class Flower extends Plant {
public Flower(String ID, int idNum, String name, String color, boolean smell, boolean thorns, boolean edible, boolean poisonous, boolean flavor, boolean medicine, boolean seasonal) {
super(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
}
public void setSmell(boolean smell) {
this.smell = smell;
}
public void setThorns(boolean thorns) {
this.thorns = thorns;
}
//toString method for the ListView only. All works fine here
public String toString() {
return super.toString() + ", Scent? " + this.smell + ", Thorns? " + this.thorns;
}
}
I sincerely hope I either 1) gave you enough information, or 2) didn't give you too much information. Thank you all for any help offered.
You are invoking a static method on a string and return a number which effectively results in absolutely nothing when you call it like that:
Plant.substringCounter(name, "e");
You need to modify a property if you want some "action" or at least process the result that's being returned by substringCounter.
Besides, I have no idea why you use recursion. This does the same:
String text = "dandelion";
String search = "d";
int count = 0;
int pos = 0;
if (!search.isEmpty()) {
while ((pos = text.indexOf(search, pos)) != -1) {
count++;
pos++;
}
}
System.out.println(count);
Basically something like this:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
// add listener for counting the number of substrings
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
int count = 0;
int pos = 0;
if( !searchText.isEmpty()) {
while( (pos = sourceText.indexOf( searchText, pos)) != -1) {
count++;
pos++;
}
}
result.setText( String.valueOf(count));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Or using your recursive method (you also need to check letters for empty string by the way):
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
result.setText( String.valueOf( substringCounter( sourceText, searchText)));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(letters.isEmpty()) {
return 0;
}
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
public static void main(String[] args) {
launch(args);
}
}
Instead of setting the label like I did in the example you of course have to change your integer properties.

BlackBerry Java Plugin for Eclipse - .net web service

I have a web service that accepts a username and password and if the login credentials are correct, it returns the user's name, status, image and last known gps coordinates.
As for now I am stuck in the "login" button where the application neither proceeds nor throws any error. Simulator produces no result and I am unable to load the app on to my handset.
package mypackage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.rmi.RemoteException;
import java.util.Hashtable;
import javacard.framework.UserException;
import javax.microedition.io.HttpConnection;
import javax.microedition.location.Location;
import javax.microedition.location.LocationProvider;
import org.kobjects.base64.Base64;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransport;
import org.xmlpull.v1.XmlPullParserException;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.component.pane.TitleView;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.image.Image;
public class LoginTest extends UiApplication
{
public static void main(String[] args)
{
//Create a new instance of the app
//and start the app on the event thread.
LoginTest app = new LoginTest();
app.enterEventDispatcher();
}
public LoginTest()
{
//Display a new screen.
pushScreen(new LoginTestScreen());
}
}
//Create a new screen that extends MainScreen and provides
//behaviour similar to that of other apps.
final class LoginTestScreen extends MainScreen
{
//declare variables for later use
private InfoScreen _infoScreen;
private ObjectChoiceField choiceField;
private int select;
BasicEditField username;
PasswordEditField passwd;
CheckboxField checkBox1;
ButtonField loginBtn;
Hashtable persistentHashtable;
PersistentObject persistentObject;
static final long KEY = 0x9df9f961bc6d6baL;
// private static final String URL="http://prerel.track24elms.com/Android/T24AndroidLogin.asmx";
String strResult;
public LoginTestScreen()
{
//Invoke the MainScreen constructor.
super();
//Add a screen title.
setTitle("Track24ELMS");
LabelField login = new LabelField("ELMS Login", LabelField.FIELD_HCENTER);
login.setFont(Font.getDefault().derive(Font.BOLD, 30));
login.setMargin(10, 0, 20, 0); //To leave some space from top and bottom
HorizontalFieldManager user = new HorizontalFieldManager();
user.setMargin(0, 0, 10, 0);
HorizontalFieldManager pass = new HorizontalFieldManager();
pass.setMargin(0, 0, 20, 0);
HorizontalFieldManager checkbox = new HorizontalFieldManager();
checkbox.setMargin(0, 0, 30, 0);
HorizontalFieldManager btns = new HorizontalFieldManager(HorizontalFieldManager.FIELD_HCENTER);
LabelField usernameTxt = new LabelField("Username :");
LabelField passwordTxt = new LabelField("Password :");
username = new BasicEditField();
passwd = new PasswordEditField();
loginBtn = new ButtonField("Login", ButtonField.CONSUME_CLICK);
// btn.setChangeListener(new view listener);
//checkBox1 = new CheckboxField("Remember me", false,Field.FOCUSABLE);
checkBox1 = new CheckboxField("Remember me",false);
user.add(usernameTxt);
user.add(username);
pass.add(passwordTxt);
pass.add(passwd);
//checkbox.add(checkBox1);
btns.add(loginBtn);
add(login);
add(user);
add(pass);
add(checkBox1);
add(btns);
// loginBtn.setChangeListener(btnlistener);
}
public void saveChecked() {
persistentHashtable.put("", username.getText());
persistentHashtable.put("", passwd.getText());
persistentHashtable.put("BoolData", new Boolean(checkBox1.getChecked()));
persistentObject.commit();
}
FieldChangeListener btnlistener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
//Open a new screen
String uname = username.getText();
String pwd = passwd.getText();
//If there is no input
if (uname.length() == 0 || pwd.length()==0) {
Dialog.alert("One of the textfield is empty!");
} else {
final String METHOD_NAME = "ValidateCredentials";
final String NAMESPACE = "http://tempuri.org/";
final String SOAP_ACTION = NAMESPACE + METHOD_NAME;
final String URL = "http://prerel.track24elms.com/Android/T24AndroidLogin.asmx";
SoapObject resultRequestSOAP = null;
HttpConnection httpConn = null;
HttpTransport httpt;
System.out.println("The username" + uname + "password" + pwd );
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
//String usernamecode = Base64.encode(username.getBytes());
//String pwdEncodeString = Base64.encode(passwd.getBytes());
request.addProperty("Username", "abc");//First parameter is tag name provided by web service
request.addProperty("Password", "xyz");
System.out.println("The request is=======" + request.toString());
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
envelope.dotNet = true;
envelope.encodingStyle = SoapSerializationEnvelope.XSD;
envelope.setOutputSoapObject(request);
System.out.println("The envelope has the value++++"+ envelope.toString());
/* URL+ Here you can add paramter so that you can run on device,simulator etc. this will work only for wifi */
httpt = new HttpTransport(URL+ ";deviceside=true;ConnectionUID=S TCP-WiFi");
httpt.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
httpt.debug = true;
try
{
System.out.println("SOAP_ACTION == " + SOAP_ACTION);
httpt.call(SOAP_ACTION, envelope);
System.out.println("the tranport" + httpt.toString());
resultRequestSOAP = (SoapObject) envelope.bodyIn;
System.out.println("result == " + resultRequestSOAP);
}
catch (IOException e) {
System.out.println("The exception is IO==" + e.getMessage());
} catch (XmlPullParserException e) {
System.out.println("The exception xml parser example==="
+ e.getMessage());
}
System.out.println( resultRequestSOAP);
UiApplication.getUiApplication().pushScreen(new InfoScreen()); //Open a new Screen
}
}
};
//To display a dialog box when a BlackBerry device user
//closes the app, override the onClose() method.
public boolean onClose()
{
if(checkBox1.equals("true"))
{
persistentObject = PersistentStore.getPersistentObject(KEY);
if (persistentObject.getContents() == null) {
persistentHashtable = new Hashtable();
persistentObject.setContents(persistentHashtable);
}
else {
persistentHashtable = (Hashtable)persistentObject.getContents();
}
if (persistentHashtable.containsKey("EditData")) {
username.setText((String)persistentHashtable.get("EditData"));
}
if (persistentHashtable.containsKey("BoolData")) {
Boolean booleanObject = (Boolean)persistentHashtable.get("BoolData");
checkBox1.setChecked(booleanObject.booleanValue());
if(booleanObject.booleanValue()==true){
saveChecked();
}
}
}
Dialog.alert("Goodbye!");
System.exit(0);
return true;
}
//Create a menu item for BlackBerry device users to click to see more
//information about the city they select.
private MenuItem _viewItem = new MenuItem("More Info", 110, 10)
{
public void run()
{
//Store the index of the city the BlackBerry device user selects
select = choiceField.getSelectedIndex();
//Display a new screen with information about the
//city the BlackBerry device user selects
_infoScreen = new InfoScreen();
UiApplication.getUiApplication().pushScreen(_infoScreen);
}
};
//Create a menu item for BlackBerry device users to click to close
//the app.
private MenuItem _closeItem = new MenuItem("Close", 200000, 10)
{
public void run()
{
onClose();
}
};
//To add menu items to the menu of the app,
//override the makeMenu method.
//Create an inner class for a new screen that displays
//information about the city a BlackBerry device user selects.
private class InfoScreen extends MainScreen
{
public InfoScreen()
{
super();
setTitle("Itinerary");
LabelField login = new LabelField("Employee Itinerary", LabelField.FIELD_HCENTER);
Bitmap bitmap = Bitmap.getBitmapResource("img1.jpg");
EditField statusMsg = new EditField("Status Message", "Update status here");
}
}
}
In the code you posted, nothing is ever setup to respond to your login button being pressed.
First of all, let's remove this anonymous class that implements FieldChangeListener:
FieldChangeListener btnlistener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
and make it like this:
private class LoginButtonListener implements FieldChangeListener {
public void fieldChanged(Field field, int context) {
// no change to the content of this method!
}
}
and in the constructor for LoginTestScreen, instantiate it, and hook it up to the login button:
loginBtn = new ButtonField("Login", ButtonField.CONSUME_CLICK);
loginBtn.setChangeListener(new LoginButtonListener());
it looks like you were close, in the commented out code. Just needed a little more. Try that, and report back!
Note: you could make it work with the anonymous button listener class you originally had. I just don't like the readability of anonymous classes when they get that big, especially since your btnListener member was declared in a totally different place than all your other ones. The real missing piece was the call to setChangeListener. I just wanted to differentiate what I'm recommending, from what's needed.

Refreshing Table Model Adapter on deleting record from it : Blackberry

I m creating a Table Model Adapter in Blackberry.(**This is a sample what i m doing****)I have added button field and two Strings.I m putting data in String from vector.Now on button click i want to delete the row against button.The Data is deleted from the database but not removed from Screen view when button is clicked.When i calld the Retrieve() function to call updated database and draw the Table model adapter again....it is adding new Table below old one....not refreshing it. Is there any solution to show the refreshed data in same table.
package mypackage;
import java.util.Vector;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.table.DataTemplate;
import net.rim.device.api.ui.component.table.TableController;
import net.rim.device.api.ui.component.table.TableModelAdapter;
import net.rim.device.api.ui.component.table.TableView;
import net.rim.device.api.ui.component.table.TemplateColumnProperties;
import net.rim.device.api.ui.component.table.TemplateRowProperties;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.BackgroundFactory;
public final class MyScreen extends MainScreen implements FieldChangeListener
{
private DeviceTableModelAdapter _tableModel;
private Vector _cities;
private static final int NUM_ROWS = 1;
private static final int ROW_HEIGHT = 50;
private static final int NUM_COLUMNS = 3;
public ButtonField btn;
public MyScreen(){
super(Manager.NO_VERTICAL_SCROLL);
_cities = new Vector();
_tableModel = new DeviceTableModelAdapter();
Vector sample =new Vector();
sample.addElement("Newyork");
sample.addElement("NewDelhi");
sample.addElement("NewOrleans");
int ik = 0;
while(ik < sample.size())
{
String modelNumber = sample.elementAt(ik).toString();
String modelName = "-Earth-";
String ne = String.valueOf(ik);
Object[] row = {modelName, modelNumber, ne};
_tableModel.addRow(row);
ik++;
}
TableView tableView = new TableView(_tableModel);
tableView.setDataTemplateFocus(BackgroundFactory.createLinearGradientBackground(Color.WHITE, Color.WHITE, Color.BLUEVIOLET, Color.BLUEVIOLET));
TableController tableController = new TableController(_tableModel, tableView);
tableController.setFocusPolicy(TableController.ROW_FOCUS);
tableView.setController(tableController);
// Specify a simple data template for displaying 3 columns
DataTemplate dataTemplate = new DataTemplate(tableView, NUM_ROWS, NUM_COLUMNS)
{
public Field[] getDataFields(int modelRowIndex)
{
Object[] data = (Object[]) (_tableModel.getRow(modelRowIndex));
Field[] fields = {getButtonFieldObject((String)data[0]), new LabelField((String) data[1]), new LabelField((String) data[2])};
return fields;
}
};
dataTemplate.useFixedHeight(true);
// Define regions and row height
dataTemplate.setRowProperties(0, new TemplateRowProperties(ROW_HEIGHT));
for(int i = 0; i < NUM_COLUMNS; i++)
{
dataTemplate.createRegion(new XYRect(i, 0, 1, 1));
dataTemplate.setColumnProperties(i, new TemplateColumnProperties(Display.getWidth() / NUM_COLUMNS));
}
// Apply the template to the view
tableView.setDataTemplate(dataTemplate);
add(tableView);
}
public void fieldChanged(Field arg0, int arg1) {
/*** tableView.DeleteAll(); ****/
/**** calling Class again to draw the table Modal Adapter again with updated value *******/
}
private final static class City
{
private String _name;
private String _region;
private String _image;
City(String name, String region, String image)
{
_name = name;
_region = region;
_image = image;
}
public String getName()
{
return _name;
}
public String getRegion()
{
return _region;
}
public String getImage()
{
return _image;
}
}
private class DeviceTableModelAdapter extends TableModelAdapter
{
public int getNumberOfRows()
{
return _cities.size();
}
public int getNumberOfColumns()
{
return NUM_COLUMNS;
}
protected boolean doAddRow(Object row)
{
Object[] arrayRow = (Object[]) row;
_cities.addElement(new City((String) arrayRow[0], (String) arrayRow[1], (String) arrayRow[2]));
return true;
}
protected Object doGetRow(int index)
{
City city = (City) _cities.elementAt(index);
Object[] row = {city.getImage(), city.getRegion(), city.getName()};
return row;
}
}
public ButtonField getButtonFieldObject(String arg){
btn = new ButtonField(arg,ButtonField.CONSUME_CLICK);
btn.setChangeListener(this);
return btn;
}
}
What you have to consider is the fact that Blackberry table UI follows the MVC design pattern.
So it means that data are updated in the model.
Like for example:
Object yes = (Object)"Yes";
// gets the Model attached to this View
TableModel tm = (TableModel)view.getModel();
// updates the data attached to the row
tm.setElement(rowIndex, columnIndex, yes);
tm.modelReset();

Resources