Ok, so I know this is a common problem that has been posted about a lot but as much as I try to follow the advice given, my TableView till displays no data... I'll reduce my object a bit to keep things as short as possible. Here is my Object:
public SimpleStringProperty itemCode, itemName;
public ResourceItem(String code, String name) {
this.itemCode = new SimpleStringProperty(code);
this.itemName = new SimpleStringProperty(name);
}
public String getItemCode() {
return itemCode.get();
}
public void setItemCode(String code) {
itemCode.set(code);
}
public SimpleStringProperty itemCodeProperty() {
return itemCode;
}
public SimpleStringProperty itemNameProperty() {
return itemName;
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String name) {
itemName.set(name);
}
And here is where I create the TableColumns:
TableColumn<ResourceItem, String> code = new TableColumn("Item Code");
code.setCellValueFactory(new PropertyValueFactory("itemCode"));
TableColumn<ResourceItem, String> code = new TableColumn("Item Name");
name.setCellValueFactory(new PropertyValueFactory("itemName"));
I add Resource Items to the ObservableList through a for loop and set my items of the TableView to that list:
ObservableList<ResourceItem> data = FXCollections.observableArrayList();
....
itemsInDB.setItems(data);
itemsInDB.getColumns().addAll(code, name);
And then nothing is added. Can someone help me out please?
EDIT:
Here is a testable version. It does require you set up a database called ims, a table called im_resoureitem_br with two columns: IMItemCode Varchar(4) and IMItemName Varchar(30).
public class TableViewTest extends Application {
final String DRIVER = "com.mysql.jdbc.Driver";
String urlHead = "jdbc:mysql://localhost/ims";
final String USER = "root";
final String PASS = "";
Connection connection;
Statement statement;
private TableView<ResourceItem> table = new TableView<ResourceItem>(); //creates table to hold Course objects
private final ObservableList<ResourceItem> data
= FXCollections.observableArrayList();
#Override
public void start(Stage stage) throws ClassNotFoundException {
Scene scene = new Scene(new Group());
stage.setTitle("Fall 2015 Schedule"); //title of stage, appears at top bar
stage.setWidth(700);
stage.setHeight(500);
final Label label = new Label("Brenna Morss-Fish Fall Schedule 2015");
table.setEditable(true);
table.setItems(data); //sets rows of table as data from course arraylist
TableColumn<ResourceItem, String> code = new TableColumn<ResourceItem, String>("Code:");//creates first column
code.setMinWidth(100);
code.setCellValueFactory(
new PropertyValueFactory("itemCode"));
TableColumn<ResourceItem, String> name = new TableColumn<ResourceItem, String>("Name:");//creates first column
name.setMinWidth(100);
name.setCellValueFactory(
new PropertyValueFactory("itemName")); //defines what column holds according to name field of Course class
String query = "select * from ims.im_resourceItem_br; ";
ArrayList<String[]> items = new ArrayList<String[]>();
TableView<ResourceItem> itemsInDB = new TableView();
items = getQueryResult(query);
//itemsInDB.setEditable(false);
ResourceItem item = new ResourceItem("", "");
ObservableList<ResourceItem> data = FXCollections.observableArrayList();
data.removeAll(data);
//System.out.println(items.get(0).toString());
for (int i = 0; i < items.size(); i++) {
item.setItemCode(items.get(i)[1]);
item.setItemName(items.get(i)[2]);
data.add(item);
}
code.setCellValueFactory(new PropertyValueFactory("itemCode"));
name.setCellValueFactory(new PropertyValueFactory("itemName"));
itemsInDB.setItems(data);
System.out.println(itemsInDB.getItems());
itemsInDB.getColumns().addAll(code, name);
table.getColumns().addAll(code, name);
//adds previously defined columns to the table in the order they will appear
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(label, table); //adds label and course table to VBox layout container
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene); //adds scene to the stage
stage.show(); //displays stage
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ArrayList getQueryResult(String stmt) throws ClassNotFoundException {
String results = "";
ResultSet resultSet = null;
String row = "";
ArrayList<String[]> list = new ArrayList<String[]>();
try {
Class.forName(DRIVER);
connection = DriverManager.getConnection(urlHead, USER, PASS);
statement = connection.createStatement();
resultSet = statement.executeQuery(stmt);
int columnCount = resultSet.getMetaData().getColumnCount();
while (resultSet.next()) {
String delims = "[%]";
row = "";
for (int i = 1; i <= columnCount; i++) {
row += resultSet.getString(i) + "%";
}
String[] array = row.split(delims);
list.add(array);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public static class ResourceItem {
public SimpleStringProperty itemCode, itemName;
public ResourceItem(String code, String name) {
this.itemCode = new SimpleStringProperty(code);
this.itemName = new SimpleStringProperty(name);
}
public String getItemCode() {
return itemCode.get();
}
public void setItemCode(String code) {
itemCode.set(code);
}
public SimpleStringProperty itemCodeProperty() {
return itemCode;
}
public SimpleStringProperty itemNameProperty() {
return itemName;
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String name) {
itemName.set(name);
}
public String toString() {
String print = itemCode + " " + itemName + " ";
return print;
}
}
}
You have created two tables: one called table, which you display in the UI when you add it to vbox, and another called itemsInDB, which you populate but never display. Since the table you do display has no data in it, and the table you populate is never displayed, you never see the data.
You have another logical error when you populate the observable list: you add the same item over and over to the list, and update its properties each time. So if it were displayed you would see the same item repeatedly in the table.
There may be other errors I haven't noticed, but since you haven't created a MCVE, I can't actually run it and test it.
Related
I need to add to my TreeTableView the content for two columns("Id" and "Workplace").
I don't know how to do it, because I can't get nested value from Manager -> ArrayList.
What should I pass in TreeItemPropertyValueFactory if the type of the content can be only String???
The rest of code works OK.
I will be grateful for any help.
public void showStaffInTreeTable(){
Employee emp_1 = new Employee("1", "secretary");
Employee emp_2 = new Employee("2", "cleaner");
Employee emp_3 = new Employee("3", "driver");
Employee emp_4 = new Employee("4", "mechanic");
ArrayList<Employee> johnStaff = new ArrayList<>(Arrays.asList(emp_1, emp_2));
ArrayList<Employee> amandaStaff = new ArrayList<>(Arrays.asList(emp_3, emp_4));
Manager john = new Manager("John", johnStaff);
Manager amanda = new Manager("Amanda", amandaStaff);
TreeTableColumn<Manager, String> columnManager = new TreeTableColumn<>("Manager");
TreeTableColumn<Manager, String> columnStaffId = new TreeTableColumn<>("Id");
TreeTableColumn<Manager, String> columnStaffWorkplace = new TreeTableColumn<>("Workplace");
columnManager.setCellValueFactory(new TreeItemPropertyValueFactory<>("managersName"));
columnStaffId.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getId???"));
columnStaffWorkplace.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getWorkplace???"));
TreeTableView<Manager> managers = new TreeTableView<>();
managers.getColumns().addAll(columnManager, columnStaffId, columnStaffWorkplace);
TreeItem managerItem_1 = new TreeItem(john);
managerItem_1.getChildren().addAll(new TreeItem<>(emp_1), new TreeItem<>(emp_2));
TreeItem managerItem_2 = new TreeItem(amanda);
managerItem_2.getChildren().addAll(new TreeItem<>(emp_3), new TreeItem<>(emp_4));
TreeItem root = new TreeItem(new Manager("", new ArrayList<>()));
root.getChildren().addAll(managerItem_1, managerItem_2);
root.setExpanded(true);
managers.setRoot(root);
}
public class Employee {
private String id;
private String workplace;
public Employee(String id, String workplace) {
this.id = id;
this.workplace = workplace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getWorkplace() {
return workplace;
}
public void setWorkplace(String workplace) {
this.workplace = workplace;
}
}
public class Manager {
private String managersName;
private List<Employee> managersStaff = new ArrayList<>();
public Manager(String managersName, List<Employee> managersStaff) {
this.managersName = managersName;
this.managersStaff = managersStaff;
}
public String getManagersName() {
return managersName;
}
public void setManagersName(String managersName) {
this.managersName = managersName;
}
public List<Employee> getManagersStaff() {
return managersStaff;
}
public void setManagersStaff(List<Employee> managersStaff) {
this.managersStaff = managersStaff;
}
}
You can do
columnStaffId.setCellValueFactory(cellData -> {
TreeItem<?> item = cellData.getValue();
Object data = item.getValue();
if (data instanceof Employee) {
Employee employee = (Employee)data ;
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Note in Java 14 you can simplify this to
columnStaffId.setCellValueFactory(cellData -> {
if (cellData.getValue().getValue() instanceof Employee employee) {
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Your setup is a little weird, as you declare a TreeTableView<Manager> but some of the items don't contain Managers, but Employees. So there's no real guarantee you don't get ClassCastExceptions thrown in places here, or other errors caused by the TreeItemPropertyValueFactory trying to call getManagersName() on an object that isn't a Manager.
You might want to refactor so you use a TreeTableView<Object>, or maybe refactor the model so that Manager and Employee are both subclasses of some other class (which you then use as the type for your TreeTableView).
I have a particular TreeTableView that displays a hierarchical tree of mixed types. These types do not necessarily have overlapping columns and as such the columns for some rows will be empty. As an example, consider the following classes:
public class Person {
private final StringProperty nameProperty;
private final StringProperty surnameProperty;
public Person() {
this.nameProperty = new SimpleStringProperty();
this.surnameProperty = new SimpleStringProperty();
}
public StringProperty nameProperty() {
return this.nameProperty;
}
public void setName(String value) {
this.nameProperty.set(value);
}
public String getName() {
return this.nameProperty.get();
}
public StringProperty surnameProperty() {
return this.surnameProperty;
}
public void setSurname(String value) {
this.surnameProperty.set(value);
}
public String getSurname() {
return this.surnameProperty.get();
}
}
public class Dog {
private final StringProperty nameProperty;
private final IntegerProperty ageProperty;
private final StringProperty breedProperty;
public Dog() {
this.nameProperty = new SimpleStringProperty();
this.ageProperty = new SimpleIntegerProperty();
this.breedProperty = new SimpleStringProperty();
}
public StringProperty nameProperty() {
return this.nameProperty;
}
public void setName(String value) {
this.nameProperty.set(value);
}
public String getName() {
return this.nameProperty.get();
}
public IntegerProperty ageProperty() {
return this.ageProperty;
}
public void setAge(int value) {
this.ageProperty.setValue(value);
}
public int getAge() {
return this.ageProperty.get();
}
public StringProperty breedProperty() {
return this.breedProperty;
}
public void setBreed(String breed) {
this.breedProperty.set(breed);
}
public String getBreed() {
return this.breedProperty.get();
}
}
If I construct the TreeTableView as follows:
TreeTableView<Object> treeTableView = new TreeTableView<>();
treeTableView.setEditable(true);
List<TreeTableColumn<Object, ?>> columns = treeTableView.getColumns();
TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
nameColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
columns.add(nameColumn);
TreeTableColumn<Object, String> surnameColumn = new TreeTableColumn<>("Surname");
surnameColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
surnameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("surname"));
columns.add(surnameColumn);
TreeTableColumn<Object, Integer> ageColumn = new TreeTableColumn<>("Age");
ageColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn(new IntegerStringConverter()));
ageColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("age"));
columns.add(ageColumn);
TreeTableColumn<Object, String> breedColumn = new TreeTableColumn<>("Breed");
breedColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
breedColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("breed"));
columns.add(breedColumn);
TreeItem<Object> rootItem = new TreeItem<>();
treeTableView.setRoot(rootItem);
treeTableView.setShowRoot(false);
List<TreeItem<Object>> rootChildren = rootItem.getChildren();
Person john = new Person();
john.setName("John");
john.setSurname("Denver");
TreeItem<Object> johnTreeItem = new TreeItem<>(john);
rootChildren.add(johnTreeItem);
List<TreeItem<Object>> johnChildren = johnTreeItem.getChildren();
Dog charlie = new Dog();
charlie.setName("Charlie");
charlie.setAge(4);
charlie.setBreed("Labrador");
TreeItem<Object> charlieTreeItem = new TreeItem<>(charlie);
johnChildren.add(charlieTreeItem);
Dog daisy = new Dog();
daisy.setName("Daisy");
daisy.setAge(7);
daisy.setBreed("Bulldog");
TreeItem<Object> daisyTreeItem = new TreeItem<>(daisy);
johnChildren.add(daisyTreeItem);
I will get a TreeTableView that looks like:
The Age and Breed columns are empty for the TreeItems that contains Person objects. However, nothing stops me from editing Age or Breed cell for the top-most Person row. Setting a value in one of those cells doesn't change the Person object, but the value still hangs around there like it is committed.
Is there any way to prevent this from happening? I know that I could check for nulls in a custom TreeTableCell subclass and prevent the editing from kicking off in the startEdit() method. However, there are circumstances where a null-value is valid and preventing editing by checking nulls is not a feasible solution for all situations. Also, creating a custom TreeTableCell subclass for every datatype and corresponding columns is painful. It would have been nice if TreeItemPropertyValueFactory could provide for a way to abort the edit when no value is present for a particular cell.
Ok, I scraped together something by looking at the TreeItemPropertyValueFactory class itself for inspiration. This gives me the desired functionality, although I'm not sure if it is 100% correct or what the implications are of using it.
It basically comes down to installing a new cell-factory that checks if the cell-value-factory is of type TreeItemPropertyValueFactory. If it is the case, a new cell-factory is installed that delegates to the original but adds listeners for the table-row and tree-item properties. When the TreeItem changes, we get the row-data and see if we can access the desired property (via a PropertyReference that is cached for performance). If we can't (and we get the two exceptions) we assume that the property cannot be accessed and we set the cell's editable-property to false.
public <S, T> void disableUnavailableCells(TreeTableColumn<S, T> treeTableColumn) {
Callback<TreeTableColumn<S, T>, TreeTableCell<S, T>> cellFactory = treeTableColumn.getCellFactory();
Callback<CellDataFeatures<S, T>, ObservableValue<T>> cellValueFactory = treeTableColumn.getCellValueFactory();
if (cellValueFactory instanceof TreeItemPropertyValueFactory) {
TreeItemPropertyValueFactory<S, T> valueFactory = (TreeItemPropertyValueFactory<S, T>)cellValueFactory;
String property = valueFactory.getProperty();
Map<Class<?>, PropertyReference<T>> propertyRefCache = new HashMap<>();
treeTableColumn.setCellFactory(column -> {
TreeTableCell<S, T> cell = cellFactory.call(column);
cell.tableRowProperty().addListener((o1, oldRow, newRow) -> {
if (newRow != null) {
newRow.treeItemProperty().addListener((o2, oldTreeItem, newTreeItem) -> {
if (newTreeItem != null) {
S rowData = newTreeItem.getValue();
if (rowData != null) {
Class<?> rowType = rowData.getClass();
PropertyReference<T> reference = propertyRefCache.get(rowType);
if (reference == null) {
reference = new PropertyReference<>(rowType, property);
propertyRefCache.put(rowType, reference);
}
try {
reference.getProperty(rowData);
} catch (IllegalStateException e1) {
try {
reference.get(rowData);
} catch (IllegalStateException e2) {
cell.setEditable(false);
}
}
}
}
});
}
});
return cell;
});
}
}
For the example listed in the question, you can call it after you created all your columns as:
...
columns.forEach(this::disableUnavailableCells);
TreeItem<Object> rootItem = new TreeItem<>();
treeTableView.setRoot(rootItem);
treeTableView.setShowRoot(false);
...
You'll see that cells for the Age and Breed columns are now uneditable for Person entries whereas cells for the Surname column is now uneditable for Dog entries, which is what we want. Cells for the common Name column is editable for all entries as this is a common property among Person and Dog objects.
Im making a mediaplayer using JavaFX Media classes. I made a SongModel class, that incapsulates all metadata from a file and creates Media and MediaPlayer instances.
It looks something like this:
private final StringProperty album =
new SimpleStringProperty(this, "album");
public String getAlbum(){ return album.get(); }
public void setAlbum(String value){ album.set(value); }
public StringProperty albumProperty() { return album; }
There are also artist, year, title, and albumCover fields that look just like that. Also, MediaPlayer property is exposed as a read-only:
public MediaPlayer getMediaPlayer(){ return mediaPlayer.get(); }
public ReadOnlyObjectProperty<MediaPlayer> mediaPlayerProperty(){
return mediaPlayer.getReadOnlyProperty();
}
I use a MapChangelistener to check if the field is available and then pass it to the handleMetadata method:
private void initializeMedia(String url){
try {
final Media media = new Media(url);
media.getMetadata().addListener(new MapChangeListener<String, Object>(){
#Override
public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> ch) {
if(ch.wasAdded()){
handleMetadata(ch.getKey(), ch.getValueAdded());
}
}
});
mediaPlayer.setValue(new MediaPlayer(media));
mediaPlayer.get().setOnError(new Runnable() {
#Override
public void run() {
String errorMessage = mediaPlayer.get().getError().getMessage();
System.out.println("MediaPlayer error: "+errorMessage);
}
});
}catch(RuntimeException e){
System.out.println("Construction error: "+e);
}
}
private void handleMetadata(String key, Object value){
if(key.equals("album")){
setAlbum(value.toString());
} else if (key.equals("artist")){
setArtist(value.toString());
} if (key.equals("title")){
setTitle(value.toString());
} if (key.equals("year")){
setYear(value.toString());
} if (key.equals("image")){
setAlbumCover((Image)value);
}
}
Then I made an AbstractView class that provides access to SongModel:
public abstract class AbstractView {
protected final SongModel songModel;
protected final Node viewNode;
public AbstractView(SongModel songModel){
this.songModel = songModel;
this.viewNode = initView();
}
public Node getViewNode() {
return viewNode;
}
protected abstract Node initView();
}
But when I try to make a MetadataView class, I run into some problems.
Heres how it looks:
public class MetadataView extends AbstractView{
public Label artist;
public Label album;
public Label title;
public Label year;
public ImageView albumCover;
public MetadataView(SongModel songModel) {
super(songModel);
}
#Override
protected Node initView() {
artist = new Label();
artist.setId("artist");
album = new Label();
album.setId("album");
title = new Label();
title.setId("title");
year = new Label();
year.setId("year");
final Reflection reflection = new Reflection();
reflection.setFraction(0.2);
final URL url = getClass().getResource("resources/defaultAlbum.png");
Image image = new Image(url.toString());
albumCover = new ImageView(image);
albumCover.setFitWidth(240);
albumCover.setPreserveRatio(true);
albumCover.setSmooth(true);
albumCover.setEffect(reflection);
final GridPane gp = new GridPane();
gp.setPadding(new Insets(10));
gp.setHgap(20);
gp.add(albumCover, 0,0,1, GridPane.REMAINING);
gp.add(title, 1,0);
gp.add(artist, 1,1);
gp.add(album, 1,2);
gp.add(year, 1,3);
final ColumnConstraints c0 = new ColumnConstraints();
final ColumnConstraints c1 = new ColumnConstraints();
c1.setHgrow(Priority.ALWAYS);
gp.getColumnConstraints().addAll(c0,c1);
final RowConstraints r0 = new RowConstraints();
r0.setValignment(VPos.TOP);
gp.getRowConstraints().addAll(r0,r0,r0,r0);
return gp;
}
}
And heres how I call it in the start method:
metaDataView = new MetadataView(songModel);
The problem is that it displays only default metadata without taking it from the songmodel class. I tried running metadata view code together with data handling in one class and everything worked, but when i try to put them in separate classes - it doesnt. Music runs just fine, its just the data thats not displaying. Could anybody tell me what am I missing? How do i make it display metadata from a SongModel class? Ive spent a lot of time on that and dont want it to go to waste.
After a day of searching I have found an answer: binds. All I had to do was to bind label property of SongModel class to label property of MetadataView class:
title.textProperty().bind(songModel.titleProperty());
artist.textProperty().bind(songModel.artistProperty());
album.textProperty().bind(songModel.albumProperty());
year.textProperty().bind(songModel.yearProperty());
albumCover.imageProperty().bind(songModel.albumCoverProperty());
I've been stuck in this problem for a week. I have a listview dialog fragment that uses a custom base adapter and connect with sqlite database.
My database adapter:
public class DBAdapter {
// Column Product
static final String ROWID = "id";
static final String NAME = "name";
static final String DESC = "desc";
static final String PRICE = "price";
static final String DISPLAY = "display";
// DB Properties
static final String DBNAME = "db_prototype";
static final String TBNAME = "tbl_product";
static final int DBVERSION = 1;
static final String CREATE_TABLE = "CREATE TABLE tbl_product(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL," +
" desc TEXT NOT NULL, price TEXT NOT NULL, display INTEGER NOT NULL)";
final Context c;
SQLiteDatabase db;
DBHelper helper;
public DBAdapter(Context c) {
this.c = c;
helper = new DBHelper(c);
}
private static class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
try{
db.execSQL(CREATE_TABLE);
}catch (SQLException e){
e.printStackTrace();
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(DBHelper.class.getName(), "Upgrading DB");
db.execSQL("DROP TABLE IF EXIST tbl_product");
}
}
// Open Database
public DBAdapter openDB(){
try{
db = helper.getWritableDatabase();
}catch (SQLException e){
e.printStackTrace();
}
return this;
}
public void closeDB(){
helper.close();
}
// Insert Into Table
public long add(String name, String desc, String price, int display){
try{
ContentValues cv = new ContentValues();
cv.put(NAME, name);
cv.put(DESC, desc);
cv.put(PRICE, price);
cv.put(DISPLAY, display);
return db.insert(TBNAME, ROWID, cv);
}catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
// Delete Table
public long delete(String name){
try{
return db.delete(TBNAME, NAME + "='" + name + "'", null);
}catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
// Get All Value
public Cursor getAllValue(){
String[] columns = {ROWID, NAME, DESC, PRICE, DISPLAY};
return db.query(TBNAME, columns, null, null, null, null, null);
}
}
My Listview adapter (void refreshAdapter to refresh dataset):
public class CartAdapter extends BaseAdapter {
private Context c;
private ArrayList<Integer> display;
private ArrayList<String> nama;
private ArrayList<String> harga;
public CartAdapter(Context c, ArrayList<Integer> display, ArrayList<String> nama, ArrayList<String> harga) {
this.c = c;
this.display = display;
this.harga = harga;
this.nama = nama;
}
#Override
public int getCount() {
return nama.size();
}
#Override
public Object getItem(int position) {
return nama.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.cart_display, null);
}
// Get View
TextView txtNama = (TextView) convertView.findViewById(R.id.txtNama);
TextView txtHarga = (TextView) convertView.findViewById(R.id.txtHarga);
ImageView imgGambar = (ImageView) convertView.findViewById(R.id.imgGambar);
//Assign Data
txtNama.setText(nama.get(position));
txtHarga.setText(harga.get(position));
imgGambar.setImageResource(display.get(position));
return convertView;
}
public void refreshAdapter(ArrayList<Integer> display, ArrayList<String> nama, ArrayList<String> harga){
this.display.clear();
this.harga.clear();
this.nama.clear();
this.display = display;
this.harga = harga;
this.nama = nama;
this.notifyDataSetChanged();
}
}
My Listview dialog fragment:
public class CartDialog extends DialogFragment {
ArrayList<String> cart_name;
ArrayList<String> cart_price;
ArrayList<Integer> cart_pict;
DBAdapter dbAdapter;
CartAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_cart_dialog, null);
ListView LV = (ListView) rootView.findViewById(R.id.listCart);
Button btnDelete = (Button) rootView.findViewById(R.id.button);
// Prepare ArrayList to assign with DB
cart_pict = new ArrayList<Integer>();
cart_name = new ArrayList<String>();
cart_price = new ArrayList<String>();
getDialog().setTitle("Keranjang Belanjaan");
dbAdapter = new DBAdapter(getActivity());
adapter = new CartAdapter(getActivity(), cart_pict, cart_name, cart_price);
refreshDB();
LV.setAdapter(adapter);
LV.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String name = adapter.getItem(position).toString();
// Delete Selected Item on SQLite Database
dbAdapter.openDB();
long result = dbAdapter.delete(name);
dbAdapter.closeDB();
//Refresh Cart
refreshDB();
adapter.refreshAdapter(cart_pict, cart_name, cart_price);
}
});
return rootView;
}
public void refreshDB(){
// Refresh Data
dbAdapter.openDB();
Cursor c = dbAdapter.getAllValue();
while(c.moveToNext()){
String name = c.getString(1);
String price = c.getString(3);
int display = c.getInt(4);
cart_name.add(name);
cart_price.add(price);
cart_pict.add(display);
}
Toast.makeText(getActivity(), "Jumlah: " + c.getCount(), Toast.LENGTH_SHORT).show();
dbAdapter.closeDB();
}
}
So, whenever I click an item in the listview, DBAdapter will remove these items from SQLite Database and then CartAdapter will refresh listview. I've been looking for references to this problem, add notifyDatasetChange (), but the problem is after I called the refreshData() method, the data in listview will empty.
Try this bro
public void refreshDB(){
// Refresh Data
ArrayList<Integer> displayBaru = new ArrayList<Integer>();
ArrayList<String> namaBaru = new ArrayList<String>();
ArrayList<String> hargaBaru = new ArrayList<String>();
dbAdapter.openDB();
Cursor c = dbAdapter.getAllValue();
while(c.moveToNext()){
String name = c.getString(1);
String price = c.getString(3);
int display = c.getInt(4);
namaBaru.add(name);
hargaBaru.add(price);
displayBaru.add(display);
}
adapter.refreshAdapter(displayBaru, namaBaru, hargaBaru);
dbAdapter.closeDB();
}
There is a very similar question to this already, but mine's a bit different. I am using properties and on observable list to change it, it won't update.
Original question is here.
So when I am transferring rows between tables, like this:
The first row would appear, but when adding more than one would cause the ones after the first row to not update, like this:
They only reappear when I move around the columns though.
//Loot identification
TableColumn lootIdentCol = new TableColumn<>("Identification");
TableColumn<ItemDef, Integer> lootIDCol = new TableColumn<>("ID");
lootIDCol.setCellValueFactory(
new PropertyValueFactory<ItemDef, Integer>("id"));
TableColumn<ItemDef, String> lootNameCol = new TableColumn<>("Name");
lootNameCol.setCellValueFactory(
new PropertyValueFactory<ItemDef, String>("name"));
lootIdentCol.getColumns().addAll(lootNameCol, lootIDCol);
//Loot price
TableColumn<ItemDef, Integer> lootPriceCol = new TableColumn<>("Price");
lootPriceCol.setCellValueFactory(
new PropertyValueFactory<ItemDef, Integer>("price"));
//To loot items table
toLootItemsTableView.getColumns().addAll(lootIdentCol, lootPriceCol);
grid.add(toLootItemsTableView, 0, 1);
//Lootable items table
lootableItemsTableView.getColumns().addAll(lootIdentCol, lootPriceCol);
grid.add(lootableItemsTableView, 2, 1);
toLootItemsTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
lootableItemsTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
lootableItemsTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
toLootItemsTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
lootableTableList.add(new ItemDef("Ab", 141, false, false));
lootableTableList.add(new ItemDef("Ac", 25, false, false));
lootableTableList.add(new ItemDef("AD", 262, false, false));
AddRemoveButtons<ItemDef> addRemoveLootButtons = new AddRemoveButtons<>(
lootableTableList, lootableItemsTableView.getSelectionModel(),
toLootTableList, toLootItemsTableView.getSelectionModel()
);
Code for AddRemoveButtons:
private final ObservableList<E> fromList;
private final ObservableList<E> toList;
public AddRemoveButtons(final ObservableList<E> fromList, final SelectionModel<E> from,
final ObservableList<E> toList, final SelectionModel<E> to) {
this.fromList = fromList;
this.toList = toList;
setAlignment(Pos.CENTER);
setPadding(new Insets(5, 5, 5, 5));
setSpacing(15);
ObservableList<Node> children = getChildren();
Button moveInto = new Button("Add");
moveInto.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (from instanceof MultipleSelectionModel) {
MultipleSelectionModel<E> multipleFrom = (MultipleSelectionModel<E>) from;
ObservableList<Integer> selectedIndices = multipleFrom.getSelectedIndices();
for (int i : selectedIndices)
transfer(i, true);
} else
transfer(from.getSelectedIndex(), true);
}
});
Button delete = new Button("Del");
delete.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (to instanceof MultipleSelectionModel) {
MultipleSelectionModel<E> multipleFrom = (MultipleSelectionModel<E>) to;
ObservableList<Integer> selectedIndices = multipleFrom.getSelectedIndices();
for (int i : selectedIndices)
transfer(i, false);
} else
transfer(to.getSelectedIndex(), false);
}
});
children.addAll(moveInto, delete);
}
private void transfer(int index, boolean forward) {
if (forward)
toList.add(fromList.remove(index));
else
fromList.add(toList.remove(index));
}
ItemDef which implements Identifiable, Serializable, Comparable:
private final String name;
private final int id;
private final boolean members;
private final boolean stackable;
private int price;
public ItemDef(JSONObject jsonObject) {
this(
(String) jsonObject.get("name"),
Integer.parseInt((String) jsonObject.get("id")),
Boolean.parseBoolean((String) jsonObject.get("members")),
Boolean.parseBoolean((String) jsonObject.get("stackable"))
);
}
public ItemDef(String name, int id, boolean members, boolean stackable) {
this.name = name;
this.id = id;
this.members = members;
this.stackable = stackable;
price = -1;
}
public String getName() {
return name;
}
#Override
public int getId() {
return id;
}
public boolean isMembers() {
return members;
}
public boolean isStackable() {
return stackable;
}
public int getPrice() {
return price != -1 ? price : updatePrice();
}
//Other methods not relevant
Figured out why it kept doing that.
You just can't have the same TableColumn being referenced on multiple tables.
You should not share columns in multiple tables if you want data to update in multiple tables share the data set between them not the columns.