Related
I'm upgrading some legacy to target Android Q, and of course this code stop working:
String[] PROJECTION_BUCKET = {MediaStore.Images.ImageColumns.BUCKET_ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DATA,
"COUNT(" + MediaStore.Images.ImageColumns._ID + ") AS COUNT",
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.MediaColumns._ID};
String BUCKET_GROUP_BY = " 1) and " + BUCKET_WHERE.toString() + " GROUP BY 1,(2";
cur = context.getContentResolver().query(images, PROJECTION_BUCKET,
BUCKET_GROUP_BY, null, BUCKET_ORDER_BY);
android.database.sqlite.SQLiteException: near "GROUP": syntax error (code 1 SQLITE_ERROR[1])
Here it supposed to obtain list of images with album name, date, count of pictures - one image for each album, so we can create album picker screen without querying all pictures and loop through it to create albums.
Is it possible to group query results with contentResolver since SQL queries stoped work?
(I know that ImageColumns.DATA and "COUNT() AS COUNT" are deprecated too, but this is a question about GROUP BY)
(There is a way to query albums and separately query photo, to obtain photo uri for album cover, but i want to avoid overheads)
Unfortunately Group By is no longer supported in Android 10 and above, neither any aggregated functions such as COUNT. This is by design and there is no workaround.
The solution is what you are actually trying to avoid, which is to query, iterate, and get metrics.
To get you started you can use the next snipped, which will resolve the buckets (albums), and the amount of records in each one.
I haven't added code to resolve the thumbnails, but is easy. You must perform a query for each bucket Id from all the Album instances, and use the image from the first record.
public final class AlbumQuery
{
#NonNull
public static HashMap<String, AlbumQuery.Album> get(#NonNull final Context context)
{
final HashMap<String, AlbumQuery.Album> output = new HashMap<>();
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
final String[] projection = {MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_ID};
try (final Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null))
{
if ((cursor != null) && (cursor.moveToFirst() == true))
{
final int columnBucketName = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
final int columnBucketId = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID);
do
{
final String bucketId = cursor.getString(columnBucketId);
final String bucketName = cursor.getString(columnBucketName);
if (output.containsKey(bucketId) == false)
{
final int count = AlbumQuery.getCount(context, contentUri, bucketId);
final AlbumQuery.Album album = new AlbumQuery.Album(bucketId, bucketName, count);
output.put(bucketId, album);
}
} while (cursor.moveToNext());
}
}
return output;
}
private static int getCount(#NonNull final Context context, #NonNull final Uri contentUri, #NonNull final String bucketId)
{
try (final Cursor cursor = context.getContentResolver().query(contentUri,
null, MediaStore.Images.Media.BUCKET_ID + "=?", new String[]{bucketId}, null))
{
return ((cursor == null) || (cursor.moveToFirst() == false)) ? 0 : cursor.getCount();
}
}
public static final class Album
{
#NonNull
public final String buckedId;
#NonNull
public final String bucketName;
public final int count;
Album(#NonNull final String bucketId, #NonNull final String bucketName, final int count)
{
this.buckedId = bucketId;
this.bucketName = bucketName;
this.count = count;
}
}
}
This is a more efficient(not perfect) way to do that.
I am doing it for videos, but doing so is the same for images to. just change MediaStore.Video.Media.X to MediaStore.Images.Media.X
public class QUtils {
/*created by Nasib June 6, 2020*/
#RequiresApi(api = Build.VERSION_CODES.Q)
public static ArrayList<FolderHolder> loadListOfFolders(Context context) {
ArrayList<FolderHolder> allFolders = new ArrayList<>();//list that we need
HashMap<Long, String> folders = new HashMap<>(); //hashmap to track(no duplicates) folders by using their ids
String[] projection = {MediaStore.Video.Media._ID,
MediaStore.Video.Media.BUCKET_ID,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media.DATE_ADDED};
ContentResolver CR = context.getContentResolver();
Uri root = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
Cursor c = CR.query(root, projection, null, null, MediaStore.Video.Media.DATE_ADDED + " desc");
if (c != null && c.moveToFirst()) {
int folderIdIndex = c.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_ID);
int folderNameIndex = c.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME);
int thumbIdIndex = c.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
int dateAddedIndex = c.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_ADDED);
do {
Long folderId = c.getLong(folderIdIndex);
if (folders.containsKey(folderId) == false) { //proceed only if the folder data has not been inserted already :)
long thumbId = c.getLong(thumbIdIndex);
String folderName = c.getString(folderNameIndex);
String dateAdded = c.getString(dateAddedIndex);
Uri thumbPath = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, thumbId);
folders.put(folderId, folderName);
allFolders.add(new FolderHolder(String.valueOf(thumbPath), folderName, dateAdded));
}
} while (c.moveToNext());
c.close(); //close cursor
folders.clear(); //clear the hashmap becuase it's no more useful
}
return allFolders;
}
}
FolderHolder model class
public class FolderHolder {
private String folderName;
public long dateAdded;
private String thumbnailPath;
public long folderId;
public void setPath(String thumbnailPath) {
this.thumbnailPath = thumbnailPath;
}
public String getthumbnailPath() {
return thumbnailPath;
}
public FolderHolder(long folderId, String thumbnailPath, String folderName, long dateAdded) {
this.folderId = folderId;
this.folderName = folderName;
this.thumbnailPath = thumbnailPath;
this.dateAdded = dateAdded;
}
public String getFolderName() {
return folderName;
}
}
GROUP_BY supporting in case of using Bundle:
val bundle = Bundle().apply {
putString(
ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
"${MediaStore.MediaColumns.DATE_MODIFIED} DESC"
)
putString(
ContentResolver.QUERY_ARG_SQL_GROUP_BY,
MediaStore.Images.ImageColumns.BUCKET_ID
)
}
contentResolver.query(
uri,
arrayOf(
MediaStore.Images.ImageColumns.BUCKET_ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DATA
),
bundle,
null
)
I am writing a Market Watch program which displays live quotes in a JFXTreeTableView, but when I update the data in the ObservableList, it doesn't get updated in the JFXTreeTableView. The changeDataDemo() method is actually tracking changes in the prices and is working fine (I'm using RethinkDB changefeeds to do it.) However I have removed the changefeed code here to increase readability. There is a method that adds rows to TreeTableView and is working perfectly but I have removed the code from here.
This is my code:
public class MainWindow implements Initializable {
private ObservableList<MarketWatchEntry> marketWatchEntries = FXCollections.observableArrayList();
private JFXTreeTableColumn<MarketWatchEntry, String> instrument_token_col;
private JFXTreeTableColumn<MarketWatchEntry, String> exchange_col;
private JFXTreeTableColumn<MarketWatchEntry, String> instrument_type_col;
private JFXTreeTableColumn<MarketWatchEntry, String> symbol_col;
private JFXTreeTableColumn<MarketWatchEntry, String> expiry_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> buy_qty_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> buy_price_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> seller_price_col;
private JFXTreeTableColumn<MarketWatchEntry, Number> sell_qty_col;
#FXML
private JFXTreeTableView<MarketWatchEntry> MarketWatch;
#Override
public void initialize(URL location, ResourceBundle resources) {
populateMarketWatch();
}
private void populateMarketWatch() {
instrument_token_col = new JFXTreeTableColumn<>("Instrument Token");
instrument_token_col.setPrefWidth(80);
instrument_token_col.setVisible(false);
instrument_token_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().instrument_token);
exchange_col = new JFXTreeTableColumn<>("Exchange");
exchange_col.setPrefWidth(80);
exchange_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().exchange);
instrument_type_col = new JFXTreeTableColumn<>("Instrument");
instrument_type_col.setPrefWidth(80);
instrument_type_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().instrument_type);
symbol_col = new JFXTreeTableColumn<>("Symbol");
symbol_col.setPrefWidth(80);
symbol_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().trading_symbol);
expiry_col = new JFXTreeTableColumn<>("Expiry");
expiry_col.setPrefWidth(80);
expiry_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, String> param) -> param.getValue().getValue().expiry);
buy_qty_col = new JFXTreeTableColumn<>("Buy Qty");
buy_qty_col.setPrefWidth(80);
buy_qty_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().buy_qty);
buy_price_col = new JFXTreeTableColumn<>("Buyer Price");
buy_price_col.setPrefWidth(80);
buy_price_col.setCellValueFactory((JFXTreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().buyer_price);
seller_price_col = new JFXTreeTableColumn<>("Seller Price");
seller_price_col.setPrefWidth(80);
seller_price_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().seller_price);
sell_qty_col = new JFXTreeTableColumn<>("Sell Qty");
sell_qty_col.setPrefWidth(80);
sell_qty_col.setCellValueFactory((TreeTableColumn.CellDataFeatures<MarketWatchEntry, Number> param) -> param.getValue().getValue().sell_qty);
final TreeItem<MarketWatchEntry> root = new RecursiveTreeItem<>(marketWatchEntries, RecursiveTreeObject::getChildren);
MarketWatch.getColumns().setAll(instrument_token_col, exchange_col, instrument_type_col, symbol_col, expiry_col,
buy_qty_col, buy_price_col, seller_price_col, sell_qty_col, ltp_col, ltq_col, open_price_col, high_price_col,
low_price_col, close_price_col, average_price_col, change_col, net_change_col);
MarketWatch.setRoot(root);
MarketWatch.setShowRoot(false);
}
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price = new SimpleDoubleProperty(100);
}
}
I have removed irrelevant code blocks to increase readability.
My question is how to get TreeTableView to update all the cells when the collection is updated with new data.
MarketWatchEntry class
class MarketWatchEntry extends RecursiveTreeObject<MarketWatchEntry> {
StringProperty instrument_token;
StringProperty exchange;
StringProperty instrument_type;
StringProperty trading_symbol;
StringProperty expiry;
DoubleProperty buy_qty;
DoubleProperty buyer_price;
DoubleProperty seller_price;
DoubleProperty sell_qty;
DoubleProperty last_price;
DoubleProperty last_qty;
DoubleProperty open_price;
DoubleProperty high_price;
DoubleProperty low_price;
DoubleProperty close_price;
DoubleProperty average_price;
DoubleProperty change;
DoubleProperty net_change;
public MarketWatchEntry(String instrument_token, String exchange, String instrument_type, String trading_symbol,
String expiry, double buy_qty, double buy_price, double sell_price, double sell_qty,
double last_price, double last_qty, double open_price, double high_price, double low_price,
double close_price, double average_price, double change, double net_change) {
this.instrument_token = new SimpleStringProperty(instrument_token);
this.exchange = new SimpleStringProperty(exchange);
this.instrument_type = new SimpleStringProperty(instrument_type);
this.trading_symbol = new SimpleStringProperty(trading_symbol);
this.expiry = new SimpleStringProperty(expiry);
this.buy_qty = new SimpleDoubleProperty(buy_qty);
this.buyer_price = new SimpleDoubleProperty(buy_price);
this.sell_qty = new SimpleDoubleProperty(sell_qty);
this.seller_price = new SimpleDoubleProperty(sell_price);
this.last_price = new SimpleDoubleProperty(last_price);
this.last_qty = new SimpleDoubleProperty(last_qty);
this.open_price = new SimpleDoubleProperty(open_price);
this.high_price = new SimpleDoubleProperty(high_price);
this.low_price = new SimpleDoubleProperty(low_price);
this.close_price = new SimpleDoubleProperty(close_price);
this.average_price = new SimpleDoubleProperty(average_price);
this.change = new SimpleDoubleProperty(change);
this.net_change = new SimpleDoubleProperty(net_change);
}
#Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.instrument_token.getValue().equals(((MarketWatchEntry) obj).instrument_token.getValue());
}
#Override
public int hashCode() {
return 7 + 5 * Integer.valueOf(instrument_token.getValue());
}
}
The problem is in your changeDataDemo method:
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price = new SimpleDoubleProperty(100);
}
You are creating new instances of your properties instead of changing their values.
Something like this works:
private void changeDataDemo() {
marketWatchEntries.get(0).buyer_price.set(100);
}
But it is recommended to provide setters/getters on your Entity class:
class MarketWatchEntry extends RecursiveTreeObject<MarketWatchEntry> {
private final DoubleProperty buyer_price;
...
public MarketWatchEntry(String instrument_token, String exchange, String instrument_type, String trading_symbol,
String expiry, double buy_qty, double buy_price, double sell_price, double sell_qty) {
...
this.buyer_price = new SimpleDoubleProperty(buy_price);
...
}
public final DoubleProperty buyer_priceProperty() {
return buyer_price;
}
public final double getBuyer_price() {
return buyer_price.get();
}
public final void setBuyer_price(double value) {
buyer_price.set(value);
}
...
}
so you can just call:
private void changeDataDemo() {
marketWatchEntries.get(0).setBuyer_price(100);
}
I believe I've searched all of the similar questions, but still am not seeing my issue anywhere. I am populating an ObservableList from a database which is succeeding per my Console output. I have a multiple controller setup for a school project to create a scheduler app. I have a root controller which functions as the borderPane, two functional controllers for Appointments and Customers which are all Singleton, and a shared DataView controller which is not to allow each view to instantiate its' own DataView. I've implemented toString on each of the controllers to spit out what the values and/or object Ids of each element are and everything seems to line up. I can't for the life of me figure out why the ListView or TableView aren't outputting the bound data. Here's the view data that I'm trying to bind to both ListView and TableView
public class AppointmentView implements IAppointmentView {
private final ZonedDateTime createdDate;
private final String createdBy;
// Interface needs these components
private ReadOnlyStringProperty title;
private ReadOnlyStringProperty description;
private ReadOnlyStringProperty location;
private ReadOnlyStringProperty contact;
private ReadOnlyStringProperty url;
private ReadOnlyStringProperty customerName;
private ReadOnlyObjectProperty<ZonedDateTime> start;
private ReadOnlyObjectProperty<ZonedDateTime> end;
private ReadOnlyProperty<ZonedDateTime> lastUpdated;
/***
*
* #param title
* #param description
* #param location
* #param contact
* #param url
* #param customerName
* #param start
* #param end
* #param createDate
* #param createdBy
* #param lastUpdate
*/
public AppointmentView(String title, String description, String location, String contact, String url, String customerName, Timestamp start, Timestamp end, Timestamp createDate, String createdBy, Timestamp lastUpdate) {
this.title = new SimpleStringProperty(title);
this.description = new SimpleStringProperty(description);
this.location = new SimpleStringProperty(location);
this.contact = new SimpleStringProperty(contact);
this.customerName = new SimpleStringProperty(customerName);
this.start = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(start.toInstant(), ZoneId.systemDefault()));
this.end = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(end.toInstant(), ZoneId.systemDefault()));
this.lastUpdated = new SimpleObjectProperty<>(ZonedDateTime.ofInstant(lastUpdate.toInstant(), ZoneId.systemDefault()));
this.url = new SimpleStringProperty(url);
this.createdDate = ZonedDateTime.ofInstant(createDate.toInstant(), ZoneId.systemDefault());
this.createdBy = createdBy;
}
public String getTitle() {
return title.getValue();
}
ReadOnlyStringProperty titleProperty() {
return title;
}
public String getDescription() {
return description.getValue();
}
ReadOnlyStringProperty descriptionProperty() {
return description;
}
public String getLocation() {
return location.getValue();
}
ReadOnlyStringProperty locationProperty() {
return location;
}
public String getContact() {
return contact.getValue();
}
ReadOnlyStringProperty contactProperty() {
return contact;
}
public String getUrl() {
return url.getValueSafe();
}
ReadOnlyStringProperty urlProperty() {
return url;
}
public String getCustomerName() {
return customerName.getValue();
}
ReadOnlyStringProperty customerNameProperty() {
return customerName;
}
public ZonedDateTime getStart() {
return ZonedDateTime.ofInstant(start.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> startProperty() {
return start;
}
public ZonedDateTime getEnd() {
return ZonedDateTime.ofInstant(end.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> endProperty() {
return end;
}
public LocalDate getCreateDate() {
return createdDate.toLocalDate();
}
public String getCreatedBy() {
return createdBy;
}
public ZonedDateTime getLastUpdate() {
return ZonedDateTime.ofInstant(lastUpdated.getValue().toInstant(), ZoneId.systemDefault());
}
ReadOnlyProperty<ZonedDateTime> lastUpdatedProperty() {
return lastUpdated;
}
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("AppointmentView{");
sb.append("createdDate=").append(createdDate);
sb.append(", createdBy='").append(createdBy).append('\'');
sb.append(", titleProperty=").append(title);
sb.append(", descriptionProperty=").append(description);
sb.append(", locationProperty=").append(location);
sb.append(", contactProperty=").append(contact);
sb.append(", urlProperty=").append(url);
sb.append(", customerName=").append(customerName);
sb.append(", startProperty=").append(start);
sb.append(", endProperty=").append(end);
sb.append(", lastUpdated=").append(lastUpdated);
sb.append('}');
return sb.toString();
}
}
Here's the AppViewController:
public class AppViewController extends BorderPane {
private BorderPane rootPane;
private MenuBar menuBar;
private Menu fileMenu;
private Menu editMenu;
private Menu reportMenu;
private Menu helpMenu;
private MenuItem closeMenuItem;
private MenuItem copyMenuItem;
private MenuItem monthlyAppointmentReportMenuItem;
private MenuItem consultantScheduleMenuItem;
private MenuItem customersByCountryMenuItem;
private MenuItem aboutMenuItem;
private VBox vbAppView;
private TabPane tpAppPane;
private Tab tabCustomers;
private ScrollPane spCustomerEditor;
private Tab tabAppointments;
private ScrollPane spAppointmentEditor;
private MainApp mainApp;
private static AppViewController instance;
private static AppointmentViewController appointmentViewController = AppointmentViewController.getInstance();
private static CustomerViewController customerViewController = CustomerViewController.getInstance();
private static DataViewController dataViewController;
private AppViewController() {
initialize();
}
public static AppViewController getInstance() {
if (instance == null) {
new AppViewController();
}
return instance;
}
/**
* Called to initialize a controller after its root element has been
* completely processed.
**/
public void initialize() {
instance = this;
this.rootPane = new BorderPane();
this.menuBar = new MenuBar();
this.fileMenu = new Menu("_File");
this.editMenu = new Menu("_Edit");
this.reportMenu = new Menu("_Report");
this.helpMenu = new Menu("_Help");
this.closeMenuItem = new MenuItem("Close");
this.copyMenuItem = new MenuItem("Copy");
this.monthlyAppointmentReportMenuItem = new MenuItem("Monthly Appointment Report");
this.consultantScheduleMenuItem = new MenuItem("Consultant Schedule Report");
this.customersByCountryMenuItem = new MenuItem("Customers by Country Report");
this.aboutMenuItem = new MenuItem("About");
this.vbAppView = new VBox();
this.tpAppPane = new TabPane();
this.tabCustomers = new Tab("Customers");
this.tabCustomers.setClosable(false);
this.spCustomerEditor = new ScrollPane();
this.tabAppointments = new Tab("Appointments");
this.tabAppointments.setClosable(false);
this.spAppointmentEditor = new ScrollPane();
// populate menus and menuBar and add them to top pane
this.fileMenu.getItems().setAll(closeMenuItem);
this.fileMenu.setMnemonicParsing(true);
this.editMenu.getItems().setAll(copyMenuItem);
this.editMenu.setMnemonicParsing(true);
this.reportMenu
.getItems()
.setAll(monthlyAppointmentReportMenuItem, consultantScheduleMenuItem, customersByCountryMenuItem);
this.reportMenu.setMnemonicParsing(true);
this.helpMenu.getItems().setAll(aboutMenuItem);
this.helpMenu.setMnemonicParsing(true);
this.menuBar.getMenus().addAll(fileMenu, editMenu, reportMenu, helpMenu);
this.rootPane.setTop(menuBar);
// populate scroll panes with included views
this.spAppointmentEditor.setContent(getAppointmentView());
this.spCustomerEditor.setContent(getCustomerView());
// populate tab panes and controllers and add them to the center pane
this.tabAppointments.setContent(spAppointmentEditor);
this.tabCustomers.setContent(spCustomerEditor);
this.tpAppPane.getTabs().addAll(tabAppointments, tabCustomers);
vbAppView.getChildren().addAll(tpAppPane);
this.rootPane.setCenter(vbAppView);
// add data view to bottom pane
this.rootPane.setBottom(AppointmentViewController.getDataView());
setupEventHandlers(this);
}
private void setupEventHandlers(AppViewController appViewController) {
this.tabCustomers.setOnSelectionChanged((event -> {
if (tabCustomers.isSelected()) {
// Change to Customer View
setCustomerView();
} else {
setAppointmentView();
}
}));
this.tabAppointments.setOnSelectionChanged(event -> {
if (tabAppointments.isSelected()) {
setAppointmentView();
} else {
setCustomerView();
}
});
this.closeMenuItem.setOnAction(event -> quitApp());
this.tpAppPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if(newValue.getText().toLowerCase().equals("Customer".toLowerCase())){
setCustomerView();
}
if (newValue.getText().toLowerCase().equals("Appointments".toLowerCase())){
setAppointmentView();
}
});
}
private void setCustomerView() {
CustomerViewController customerViewController = CustomerViewController.getInstance();
setDataView(customerViewController.getDataViewController().tabPane);
customerViewController.getGpCustomerEditor().getChildren().filtered(node -> toggleTextFields(node, true));
}
private void setAppointmentView() {
AppointmentViewController controller = AppointmentViewController.getInstance();
setDataView(controller.getDataViewController().tabPane);
controller.getGpAppointmentEditor().getChildren().filtered(node -> toggleTextFields(node, true));
}
/***
* Sets whether text fields are enabled or disabled
* true = disable Text Fields
* false = enable Text Fields
* #param node the child nodes of the editor
* #param disabled whether to disable or enable the text fields
* #return whether node was affected or not
*/
public static boolean toggleTextFields(Node node, boolean disabled) {
if (node instanceof TextField) {
((TextField) node).setEditable(!disabled);
node.setDisable(disabled);
return true;
}
return false;
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
private void quitApp() {
Platform.exit();
}
public Parent getBorderPane() {
return rootPane;
}
public TabPane getTpAppPane() {
return tpAppPane;
}
public Tab getTabCustomers() {
return tabCustomers;
}
public Tab getTabAppointments() {
return tabAppointments;
}
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("AppViewController{");
sb.append("\nrootPane=").append(rootPane);
sb.append(",\n menuBar=").append(menuBar);
sb.append(",\n fileMenu=").append(fileMenu);
sb.append(",\n editMenu=").append(editMenu);
sb.append(",\n reportMenu=").append(reportMenu);
sb.append(",\n helpMenu=").append(helpMenu);
sb.append(",\n closeMenuItem=").append(closeMenuItem);
sb.append(",\n copyMenuItem=").append(copyMenuItem);
sb.append(",\n monthlyAppointmentReportMenuItem=").append(monthlyAppointmentReportMenuItem);
sb.append(",\n consultantScheduleMenuItem=").append(consultantScheduleMenuItem);
sb.append(",\n customersByCountryMenuItem=").append(customersByCountryMenuItem);
sb.append(",\n aboutMenuItem=").append(aboutMenuItem);
sb.append(",\n vbAppView=").append(vbAppView);
sb.append(",\n tpAppPane=").append(tpAppPane);
sb.append(",\n tabCustomers=").append(tabCustomers);
sb.append(",\n spCustomerEditor=").append(spCustomerEditor);
sb.append(",\n tabAppointments=").append(tabAppointments);
sb.append(",\n spAppointmentEditor=").append(spAppointmentEditor);
sb.append(",\n dataViewController=").append(dataViewController);
sb.append("\n}");
return sb.toString();
}
public void setDataViewController(DataViewController dataViewController) {
this.dataViewController = dataViewController;
}
public DataViewController getDataViewController() {
return dataViewController;
}
}
And the AppointmentView:
private TableView<AppointmentView> tvAppointments = new TableView<>();
private TableColumn<AppointmentView, String> tcTitle = new TableColumn<>("Title");
private TableColumn<AppointmentView, String> tcDescription = new TableColumn<>("Description");
private TableColumn<AppointmentView, String> tcLocation = new TableColumn<>("Location");
private TableColumn<AppointmentView, String> tcContact = new TableColumn<>("Contact");
private TableColumn<AppointmentView, String> tcUrl = new TableColumn<>("URL");
private TableColumn<AppointmentView, String> tcCustomerName = new TableColumn<>("Customer Name");
private TableColumn<AppointmentView, ZonedDateTime> tcStart = new TableColumn<>("Start Time");
private TableColumn<AppointmentView, ZonedDateTime> tcEnd = new TableColumn<>("End Time");
private TableColumn<AppointmentView, ZonedDateTime> tcCreateDate = new TableColumn<>("Created Date");
private TableColumn<AppointmentView, String> tcCreatedBy = new TableColumn<>("Created By");
private TableColumn<AppointmentView, Timestamp> tcLastUpdate = new TableColumn<>("Last Updated");
---- snip ----
this.tcTitle.setCellValueFactory(new PropertyValueFactory<>("title"));
this.tcTitle.setVisible(true);
this.tcTitle.setMinWidth(50);
this.tcCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
this.tcCustomerName.setVisible(true);
this.tcCustomerName.setMinWidth(40);
this.tcDescription.setCellValueFactory(new PropertyValueFactory<>("description"));
this.tcDescription.setVisible(true);
this.tcDescription.setMinWidth(100);
this.tcLocation.setCellValueFactory(new PropertyValueFactory<>("location"));
this.tcLocation.setVisible(true);
this.tcLocation.setMinWidth(40);
this.tcContact.setCellValueFactory(new PropertyValueFactory<>("contact"));
this.tcContact.setVisible(true);
this.tcContact.setMinWidth(40);
this.tcUrl.setCellValueFactory(new PropertyValueFactory<>("url".toUpperCase()));
this.tcUrl.setVisible(true);
this.tcUrl.setMinWidth(40);
this.tcStart.setCellValueFactory(new PropertyValueFactory<>("start"));
this.tcStart.setVisible(true);
this.tcStart.setMinWidth(40);
this.tcEnd.setCellValueFactory(new PropertyValueFactory<>("end"));
this.tcEnd.setVisible(true);
this.tcEnd.setMinWidth(40);
this.tcCreateDate.setCellValueFactory(new PropertyValueFactory<>("createDate"));
this.tcCreateDate.setVisible(true);
this.tcCreateDate.setMinWidth(40);
this.tcCreatedBy.setCellValueFactory(new PropertyValueFactory<>("createdBy"));
this.tcCreatedBy.setVisible(true);
this.tcCreatedBy.setMinWidth(40);
this.tcLastUpdate.setCellValueFactory(new PropertyValueFactory<>("lastUpdate"));
this.tcLastUpdate.setVisible(true);
this.tcLastUpdate.setMinWidth(40);
this.tvAppointments = new TableView<>();
this.tvAppointments.setItems(appointmentViews);
this.tvAppointments.getColumns().addAll(
tcTitle,
tcDescription,
tcLocation,
tcContact,
tcUrl,
tcCustomerName,
tcStart,
tcEnd,
tcCreateDate,
tcCreatedBy,
tcLastUpdate);
this.lvListView = new ListView<>();
this.lvListView.setItems(appointmentViews);
this.dataViewController.setTableView(this.tvAppointments);
this.dataViewController.setLblListView(new Label("Appointment List"));
this.dataViewController.setListView(this.lvListView);
this.dataViewController.setLblTableView(new Label("Appointments"));
And the base DataViewController that I'm trying to manipulate:
public class DataViewController extends TabPane {
// private static DataViewController instance;
public TabPane tabPane;
private Tab tabTableView;
private Tab tabListView;
private VBox vbListView;
private VBox vbTableView;
private Label lblListView;
private Label lblTableView;
protected ScrollPane spListView;
protected ScrollPane spTableView;
private ListView<?> listView;
private TableView<?> tableView;
private MainApp mainApp;
public DataViewController() {
initialize();
}
/* public static DataViewController getInstance(){
if(instance == null){
new DataViewController();
}
return instance;
}*/
/**
* Called to initialize a controller after its root element has been
* completely processed.
*
*/
public void initialize() {
// this.instance = this;
this.tabPane = new TabPane();
this.tabPane.setPrefHeight(250.0);
this.tabPane.setMaxHeight(400.0);
this.tabPane.setMaxWidth(Integer.MAX_VALUE);
this.tabTableView = new Tab("Table View");
this.tabTableView.setClosable(false);
this.tabListView = new Tab("List View");
this.tabListView.setClosable(false);
this.spListView = new ScrollPane();
this.spTableView = new ScrollPane();
this.lblListView = new Label("List View");
this.lblTableView = new Label("Table View");
this.vbListView = new VBox();
this.vbTableView = new VBox();
this.listView = new ListView<>();
this.tableView = new TableView<>();
this.vbListView.getChildren().setAll(this.lblListView, this.listView);
this.spListView.setContent(this.listView);
this.tabListView.setContent(this.spListView);
this.vbTableView.getChildren().setAll(this.lblTableView, this.spTableView);
this.spTableView.setContent(this.tableView);
this.tabTableView.setContent(vbTableView);
this.tabPane.getTabs().setAll(tabListView, tabTableView);
}
public Label getLblListView() {
return lblListView;
}
public void setLblListView(Label lblListView) {
this.lblListView = lblListView;
}
public Label getLblTableView() {
return lblTableView;
}
public void setLblTableView(Label lblTableView) {
this.lblTableView = lblTableView;
}
public ListView<?> getListView() {
return listView;
}
public void setListView(ListView<?> listView) {
this.listView = listView;
}
public TableView<?> getTableView() {
return tableView;
}
public void setTableView(TableView<?> tableView) {
this.tableView = tableView;
}
public void setMainApp(MainApp mainApp){
this.mainApp = mainApp;
}
/* public static DataViewController getInstance() {
if (instance == null){
instance = new DataViewController();
}
return instance;
}*/
#Override
public String toString() {
return new StringBuilder()
.append("DataViewController{")
.append("\ntabPane=")
.append(tabPane)
.append(", \ntabTableView=")
.append(tabTableView)
.append(", \ntabListView=")
.append(tabListView)
.append(", \nvbListView=")
.append(vbListView)
.append(", \nvbTableView=")
.append(vbTableView)
.append(", \nlblListView=")
.append(lblListView.getText())
.append(", \nlblTableView=")
.append(lblTableView.getText())
.append(", \nspListView=")
.append(spListView)
.append(", \nspTableView=")
.append(spTableView)
.append(", \nlistView=")
.append(listView.getItems())
.append(", \ntableView=")
.append(tableView.getColumns())
.append("\n}")
.toString();
}
}
As mentioned, I put in a few toString calls and implementations and I keep seeing the objects in DataViewController per this:
listView=[AppointmentView{createdDate=2017-09-02T00:00-07:00[America/Los_Angeles], createdBy='test1', titleProperty=StringProperty [value: Meet with Amari], descriptionProperty=StringProperty [value: Meeting WR of the Raiders], locationProperty=StringProperty [value: Raiders HQ, Alameda], contactProperty=StringProperty [value: Jack DelRio], urlProperty=StringProperty [value: raiders.com], customerName=StringProperty [value: Amari Cooper], startProperty=ObjectProperty [value: 2017-09-04T16:00-07:00[America/Los_Angeles]], endProperty=ObjectProperty [value: 2017-09-04T16:15-07:00[America/Los_Angeles]], lastUpdated=ObjectProperty [value: 2017-09-02T23:07-07:00[America/Los_Angeles]]}, AppointmentView{createdDate=2017-09-02T00:00-07:00[America/Los_Angeles], createdBy='test1', titleProperty=StringProperty [value: Meet with Amari], descriptionProperty=StringProperty [value: Meeting WR of the Raiders], locationProperty=StringProperty [value: Raiders HQ, Alameda], contactProperty=StringProperty [value: Jack DelRio], urlProperty=StringProperty [value: raiders.com], customerName=StringProperty [value: Amari Cooper], startProperty=ObjectProperty [value: 2017-09-04T16:00-07:00[America/Los_Angeles]], endProperty=ObjectProperty [value: 2017-09-04T16:15-07:00[America/Los_Angeles]], lastUpdated=ObjectProperty [value: 2017-09-02T23:07-07:00[America/Los_Angeles]]}],
tableView=[javafx.scene.control.TableColumn#6167e82, javafx.scene.control.TableColumn#50658769, javafx.scene.control.TableColumn#f65aae1, javafx.scene.control.TableColumn#2d5ab3ab, javafx.scene.control.TableColumn#180d2aec, javafx.scene.control.TableColumn#64afb84b, javafx.scene.control.TableColumn#463f349d, javafx.scene.control.TableColumn#3e80101a, javafx.scene.control.TableColumn#4fab076c, javafx.scene.control.TableColumn#565f8332, javafx.scene.control.TableColumn#697bdeb8]
And here's the MainApp method that's calling it:
private void initLayout() {
// rootPane = new BorderPane();
appointmentViewController = AppointmentViewController.getInstance();
appointmentView = appointmentViewController.apAppointmentView;
appointmentViewController.setMainApp(this);
dataViewController = appointmentViewController.getDataViewController();
dataView = dataViewController.tabPane;
dataViewController.setMainApp(this);
customerViewController = CustomerViewController.getInstance();
customerView = customerViewController.apCustomerView;
customerViewController.setMainApp(this);
appViewController = AppViewController.getInstance();
appView = appViewController.getBorderPane();
appViewController.setMainApp(this);
appViewController.setDataViewController(appointmentViewController.getDataViewController());
System.out.println(this.dataViewController);
System.out.println(this.dataView);
System.out.println(appointmentViewController.toString());
System.out.println(customerViewController.toString());
System.out.println(appViewController.toString());
rootPane = (BorderPane) appView;
scene = new Scene(rootPane);
scene.getStylesheets().add("/styles/Styles.css");
primaryStage.setScene(scene);
primaryStage.show();
}
I've setup the CellValueFactories,etc. What am I missing here?
This is how the UI is shown:
In DataViewController the scene structure is initialized from the constructor. Using any of the setters in this class modifies the fields, it does not modify the scene in any way leaving the old empty ListView in the scene but printing the new one containing items from the toString method.
i'm trying to write data from sqlite to a listview. the compiler doesn't show error, but when I run the app on my phone, it crashes. please help me
Cursor resultSet = db.rawQuery("Select * from weight_listview ORDER BY `id` DESC",null);
resultSet.moveToFirst();
String[] list = new String[] {};
String[] weighttolist={};
String[] datetolist={};
ArrayList<String> List=new ArrayList<String>();
ArrayList<String> List2=new ArrayList<String>();
resultSet.moveToFirst();
int x = 0;
while(resultSet.moveToNext()){
String data = resultSet.getString(resultSet.getColumnIndex("weight"));
String data2 = resultSet.getString(resultSet.getColumnIndex("date"));
String id = resultSet.getString(resultSet.getColumnIndex("ID"));
List.add(data + " " + data2);
x++;
}
final ListView listView = (ListView) findViewById(R.id.listView1);
if(List != null){
weighttolist=(String[])List.toArray(new String[0]);
String[] from = { "weight", "date" };
int[] to = { R.id.weight, R.id.date };
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this,R.layout.row, resultSet, from, to);
listView.setAdapter(cursorAdapter);
// ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
// android.R.layout.simple_list_item_1, android.R.id.text1, weighttolist);
// ListView.setAdapter(adapter);
}
edit:
I successed to fix the problem but now I have another problem. I want that the listview will show 2 columns , not only 1 . I created fill row.xml , as you can see in the first code.
Cursor resultSet = db.rawQuery("Select * from weight_listview ORDER BY `id` DESC",null);
resultSet.moveToFirst();
String[] list = new String[] {};
String[] weighttolist={};
String[] datetolist={};
ArrayList<String> List=new ArrayList<String>();
ArrayList<String> List2=new ArrayList<String>();
resultSet.moveToFirst();
int x = 0;
while(resultSet.moveToNext()){
String data = resultSet.getString(resultSet.getColumnIndex("weight"));
String data2 = resultSet.getString(resultSet.getColumnIndex("date"));
List.add(data + " " + data2);
x++;
}
final ListView listView = (ListView) findViewById(R.id.listView1);
if(List != null){
weighttolist=(String[])List.toArray(new String[0]);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, weighttolist);
listView.setAdapter(adapter);
}
Well without the exact error it is hard to see what is going wrong. Here is my guess you are using a SimpleAdapter who's constructor looks like this
SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
For your second parameter you are using a Cursor not a list, your from variable are keys so you need to use a hash map I believe
Comment out your code and try this
List<HashMap<String, String>> List = new ArrayList<HashMap<String, String>>();
int x = 0;
while(resultSet.moveToNext()){
HashMap<String, String> map = new HashMap<String, String>();
String weight = resultSet.getString(resultSet.getColumnIndex("weight"));
String date = resultSet.getString(resultSet.getColumnIndex("date"));
String id = resultSet.getString(resultSet.getColumnIndex("ID"));
map.put("weight", weight);
map.put("date", date);
List.add(map);
x++;
}
final ListView listView = (ListView) findViewById(R.id.listView1);
if(List != null){
weighttolist=(String[])List.toArray(new String[0]);
String[] from = { "weight", "date" };
int[] to = { R.id.weight, R.id.date };
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this,R.layout.row, List, from, to);
listView.setAdapter(cursorAdapter);
i am developing a smartGWt application that needs to filter list grid content by date and by other staff, every thing is working correctly except the date filtration, this is how i am defining the date fields :
registeredDate = new DataSourceDateField("registrationDate", voc.registeredDate());
registeredDate.setRequired(true);
verificationDate = new DataSourceDateField("lastVerificationDate", voc.verificationDate());
verificationDate.setRequired(true);
the same as every other field
this is how i fill records :
registeredUsersRecords = new ListGridRecord[registeredUsers.length()];
ListGridRecord record = new ListGridRecord();
record.setAttribute(ID, user.getId());
record.setAttribute("firstName", user.getFirstName());
record.setAttribute("lastName", user.getLastName());
record.setAttribute("email", user.getEmail());
record.setAttribute("userMainType", type);
record.setAttribute("isActivated", (user.isActivated())? voc.active(): voc.inActive());
record.setAttribute("country", user.getSelectedCountry().getValue());
record.setAttribute("companyName", user.getCompanyName());
record.setAttribute("registrationDate", user.getRegistrationDate());
record.setAttribute("lastVerificationDate", user.getVerificationDate());
registeredUsersRecords[i] = record;
and then i put them into datasource :
DataSource ds = new DataSource();
ds.setClientOnly(true);
ds.setFields(fName, lName, email, type,typeDetails, status, country, companyName, registeredDate,verificationDate);
for(int i = 0; i< registeredUsersRecords.length; i++){
ds.addData(registeredUsersRecords[i]);
}
registeredUsersListGrid.setDataSource(ds);
registeredUsersListGrid.fetchData();
You have not shared a complete code.
Still I am trying to provide you a sample code. Please have a look.
public class SmartGWTProject implements EntryPoint {
public void onModuleLoad() {
class User {
private int id;
private String firstName;
private Date registrationDate;
public User(int id, String firstName, Date registrationDate) {
this.id = id;
this.firstName = firstName;
this.registrationDate = registrationDate;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public Date getRegistrationDate() {
return registrationDate;
}
}
DateTimeFormat format = DateTimeFormat.getFormat("MM/dd/yyyy");
User[] registeredUsers = new User[] { new User(1, "a", format.parse("01/20/2014")),
new User(2, "b", format.parse("05/20/2013")),
new User(3, "c", format.parse("02/20/2014")) };
ListGridRecord[] registeredUsersRecords = new ListGridRecord[registeredUsers.length];
for (int i = 0; i < registeredUsers.length; i++) {
User user = registeredUsers[i];
ListGridRecord record = new ListGridRecord();
record.setAttribute("id", user.getId());
record.setAttribute("firstName", user.getFirstName());
record.setAttribute("registrationDate", user.getRegistrationDate());
registeredUsersRecords[i] = record;
}
DataSourceDateField registeredDate = new DataSourceDateField("registrationDate", "Date");
DataSourceTextField firstName = new DataSourceTextField("firstName", "Name");
DataSourceIntegerField id = new DataSourceIntegerField("id", "ID");
id.setRequired(true);
id.setPrimaryKey(true);
id.setHidden(true);
DataSource ds = new DataSource();
ds.setClientOnly(true);
ds.setFields(id, firstName, registeredDate);
for (int i = 0; i < registeredUsersRecords.length; i++) {
ds.addData(registeredUsersRecords[i]);
}
ListGrid registeredUsersListGrid = new ListGrid();
registeredUsersListGrid.setDataSource(ds);
registeredUsersListGrid.fetchData();
registeredUsersListGrid.draw();
}
}