JavaFX DatePicker - Controlling display of days of the prev/next month - javafx

I'm working with the dayCellFactory to format the display. I've implemented disabling prev dates, allowing to select Mondays only, and highlighting period upon date selection.
final Callback<DatePicker, DateCell> dayCellFactory = new Callback<DatePicker, DateCell>() {
#Override
public DateCell call(final DatePicker datePicker) {
return new DateCell() {
#Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item.isBefore(LocalDate.now().minusWeeks(1).plusDays(1))) {
setDisable(true);
setStyle("-fx-background-color: #d3d3d3;");
}
else if (item.getDayOfWeek() != DayOfWeek.MONDAY) {
setDisable(true);
}
if (selectedDate != null) {
LocalDate startDate = selectedDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
if (item.isAfter(startDate) && item.isBefore(startDate.plusWeeks(weeksInPeriod))) {
setStyle("-fx-background-color: #ffc0cb;");
}
}
}
};
}
};
The only thing I can't figure out is how to make only current month's dates to show up on my calendar (not current month as in LocalDate.now().getMonth(), the currently displayed month in the DatePicker popup).

Related

Javafx: Reduce events of checkable Listbox

I have a generic Javafx Listbox with checkable items (up to 20 items).
When I (de-)select an item, a property change is released to update other parts of the program.
It works all fine so far.
But I have additionally 2 buttons to (de-)select all items at once.
Also this working as expected, but I get an event for each item, which means that up to 20 property change events are fired, when one would be enough.
It is not a performance problem, not much is done on the events, but it is bad style.
Can anybody suggest a better solution?
public class FilterBox extends AnchorPane {
ListView<Item> listFilter;
Button buttonAll;
Button buttonNone;
public FilterBox() {
init();
place();
action();
getChildren().addAll(listFilter, buttonAll, buttonNone);
handleChange();
}
private void init() {
listFilter = new ListView<>();
buttonAll = new Button("All");
buttonNone = new Button("None");
}
private void place() {
setTopAnchor(listFilter, 0d);
setBottomAnchor(listFilter, 40d);
setLeftAnchor(listFilter, 0d);
setRightAnchor(listFilter, 0d);
setBottomAnchor(buttonAll, 5d);
setLeftAnchor(buttonAll, 0d);
buttonAll.setPrefWidth(75d);
setBottomAnchor(buttonNone, 5d);
setRightAnchor(buttonNone, 0d);
buttonNone.setPrefWidth(75d);
}
private void action() {
listFilter.setCellFactory(CheckBoxListCell.forListView((Item item) -> item.selectedProperty()));
buttonAll.setOnAction((t) -> {
changeAll(true);
});
buttonNone.setOnAction((t) -> {
changeAll(false);
});
}
private void changeAll(Boolean state) {
for (Item i : listFilter.getItems()) {
i.setSelected(state);
}
}
private void setListener(Item item) {
item.selectedProperty().addListener((o, ov, nv) -> {
Trigger.setNewFilterEvent();
});
}
private void handleChange() {
HashSet<String> list = InputData.getSportList();
for (String s : list) {
Item item = new Item(s, true);
listFilter.getItems().add(item);
setListener(item);
}
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final BooleanProperty selected = new SimpleBooleanProperty();
public Item(String name, boolean on) {
setName(name);
setSelected(on);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final BooleanProperty selectedProperty() {
return this.selected;
}
public final boolean isSelected() {
return this.selectedProperty().get();
}
public final void setSelected(final boolean sel) {
this.selectedProperty().set(sel);
}
#Override
public String toString() {
return getName();
}
}
}
Assuming Trigger.setNewFilterEvent() is what you want called only once when the "select all" or the "deselect all" actions are fired, then you can use a boolean flag for this.
public class FilterBox {
private boolean ignoreIndividualChanges;
// other fields omitted for brevity
private void changeAll(boolean state) {
ignoreIndividualChanges = true;
try {
for (Item i : listFilter.getItems()) {
i.setSelected(state);
}
Trigger.setNewFilterEvent(); // fire one event
} finally {
ignoreIndividualChanges = false;
}
}
private void setListener(Item item) {
item.selectedProperty().addListener((obs, ov, nv) -> {
if (!ignoreIndividualChanges) {
Trigger.fireNewFilterEvent();
}
});
}
// other methods omitted for brevity
}
Also, note I changed the parameter type for changeAll from Boolean to boolean. There's no reason to use the reference type here, so you should stick with the primitive type.

Filter Data from RecyclerView Firebase

I am trying to implement a searchview in my action bar and for that to filter the RecyclerView Data that I retrieved from Firebase. Right now I am looking for the code that I need to add to the recycleradapter to be able to filter the retrieved data.
This is how I added the recyclerView to my MainActivity.
Query query = mRef.orderByChild("city");
// everything else
FirebaseRecyclerAdapter<City, CityViewHolder> firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<City, CityViewHolder>(
City.class,
R.layout.city_starter,
CityViewHolder.class,
query
) {
#Override
protected void populateViewHolder(CityViewHolder viewHolder, City city, int position) {
viewHolder.setDetails(getApplicationContext(),
city.getCity());
}
// for click of parent item
#Override
public CityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CityViewHolder viewHolder = super.onCreateViewHolder(parent, viewType);
viewHolder.setOnClickListener(new CityViewHolder.ClickListener() {
#Override
public void onItemClick(View view, int position) {
//get Data from Firebase
String cCity = getItem(position).getCity();
// pass this data to new activity
Intent secondMainActivity = new Intent(view.getContext(), SecondMainActivity.class);
secondMainActivity.putExtra("city", cCity);
startActivity(secondMainActivity);
}
#Override
public void onItemLongClick(View view, int position) {
// possible to implement another way of interacting for a long click
}
});
return viewHolder;
}
};
// set adapter to recyclerview
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
Is there anybody who is able to help?
Thank you :)
This is what I found searching for solutions but I don't get it how to adapt it to my code:
public void filter(String text) {
items.clear();
if(text.isEmpty()){
items.addAll(itemsCopy);
} else{
text = text.toLowerCase();
for(PhoneBookItem item: itemsCopy){
if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
items.add(item);
}
}
}
notifyDataSetChanged();
}
You can use android's Filterable interface..
Follow this link for example
Firstly implements Filterable to your adapter class.. You can use another array list of same type you are using for storing and showing filtered items.
Implements Filterable interface's method getFilter()
Example Code...
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
contactListFiltered = contactList;
} else {
List<Contact> filteredList = new ArrayList<>();
for (Contact row : contactList) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getName().toLowerCase().contains(charString.toLowerCase()) || row.getPhone().contains(charSequence)) {
filteredList.add(row);
}
}
contactListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = contactListFiltered;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
contactListFiltered = (ArrayList<Contact>) filterResults.values;
// refresh the list with filtered data
notifyDataSetChanged();
}
};
}
Add search view into your toolbar....
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.action_search)
.getActionView();
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
searchView.setMaxWidth(Integer.MAX_VALUE);
// listening to search query text change
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
// filter recycler view when query submitted
mAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
// filter recycler view when text is changed
mAdapter.getFilter().filter(query);
return false;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
// close search view on back button pressed
if (!searchView.isIconified()) {
searchView.setIconified(true);
return;
}
super.onBackPressed();
}

JavaFX ComboBox displaying object not it's property

i have built GUI with combo box. I have ObservableList<SimpleTableObject> types
which should display types of material. It looks like this
material_comboBox_type.getItems().addAll(types);
material_comboBox_type.setCellFactory((ListView<SimpleTableObject>
param) -> {
final ListCell<SimpleTableObject> cell = new
ListCell<SimpleTableObject>() {
#Override
public void updateItem(SimpleTableObject item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getName().get());//return String, actuall name of material
}
else {
setText(null);
}
}
};
return cell;
});
Now the problem is this: when i click combobox, it shows names as desired. But when i select one, instead of the string property, an object itself is displayed, which looks like that classes.SimpleTableObject#137ff5c.
How can I achieve it?
The selected item in a combo box is displayed in a cell called the buttonCell. So you need to set the button cell as well as the cell factory (which generates the cells in the dropdown).
To do this, it's probably easier to refactor your cell implementation as a (named) inner class:
private static class SimpleTableObjectListCell extends ListCell<SimpleTableObject> {
#Override
public void updateItem(SimpleTableObject item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getName().get());//return String, actuall name of material
}
else {
setText(null);
}
}
}
And then:
materialComboBoxType.setCellFactory(listView -> new SimpleTableObjectListCell());
materialComboBoxType.setButtonCell(new SimpleTableObjectListCell());
Ok, i did this with converter:
material_comboBox_type.setConverter(new StringConverter<SimpleTableObject>() {
#Override
public String toString(SimpleTableObject object) {
return object.getName().get();
}
#Override
public SimpleTableObject fromString(String string) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});

How can I create a combo box from an object that has an arraylist of objects in javafx?

If I have an object that has an arrayList of objects:
class Event{
private ArrayList<Room> rooms;
//..
public void setRooms(ArrayList<Room> rooms) {
this.rooms = rooms;
}
public ArrayList<Room> getRooms() {
return rooms;
}
}
//---------------------
class Room{
private String roomId;
private String roomName;
public Room(String roomId, String roomName) {
this.roomId = roomId;
this.roomName = roomName;
}
public String getRoomId() {
return roomId;
}
public String getRoomName() {
return roomName;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public void setRoomName(String roomName) {
this.roomName = roomName;
}
}
How can I create a combobox in my table from the array of room objects?
What I have that is only showing an object identifier of some sort.
TableColumn<Event, ArrayList> roomsColumn = new TableColumn<>("Room Select");
roomsColumn.setMinWidth(200);
roomsColumn.setCellValueFactory(new PropertyValueFactory<>("rooms"));
//Create an observable list to populate the table with.
ObservableList<Event> eventList = FXCollections.observableArrayList();
//loop the json to populate the observable list
for (Event event : events.getEventList() ){
eventList.add(event);
}
//populate the table
eventTable.setItems(eventList);
eventTable.getColumns().addAll(eventColumn, bDateColumn, eDateColumn, roomsColumn);
**All of the columns are built but the rooms column shows a comma separated list of room objects:
com.***.Room#345, com.***.Room#653, com.***.Room#889
You need a custom cell factory to return a TableCell with a ComboBox.
roomsColumn.setCellFactory(call -> {
// create a new cell for array lists
return new TableCell<Event, ArrayList<String>>() {
#Override
protected void updateItem(ArrayList<String> item, boolean empty) {
super.updateItem(item, empty);
// if there is no item, return an empty cell
if (empty || item == null) {
setGraphic(null);
}
else {
ComboBox<String> box = new ComboBox<>();
// set combo box items
box.setItems(FXCollections.observableArrayList(item));
// listen for changes
box.valueProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("new room "+newValue);
});
// set cell contents
setGraphic(box);
}
}
};
});

Is there any Date and Time picker available for javaFx?

I am new to Java and I have started developing applications in java using javaFx. searched a lot but couldn't find any date and time picker in javaFx. Even i tried JFxtras but its not working. By the way i am using javafx 2.2.3 and java 7. Any help would be highly appreciated.
Here is a Java version of the DateTimePicker control above, slightly improved.
This code is now part of TornadoFX Controls and you can have a look at the latest version of DateTimePicker.java in the GitHub Repo. The control is available in Maven Central as well under these coordinates:
<dependency>
<groupId>no.tornado</groupId>
<artifactId>tornadofx-controls</artifactId>
<version>1.0.3</version>
</dependency>
The implementation right now:
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.DatePicker;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.util.StringConverter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
* A DateTimePicker with configurable datetime format where both date and time can be changed
* via the text field and the date can additionally be changed via the JavaFX default date picker.
*/
#SuppressWarnings("unused")
public class DateTimePicker extends DatePicker {
public static final String DefaultFormat = "yyyy-MM-dd HH:mm";
private DateTimeFormatter formatter;
private ObjectProperty<LocalDateTime> dateTimeValue = new SimpleObjectProperty<>(LocalDateTime.now());
private ObjectProperty<String> format = new SimpleObjectProperty<String>() {
public void set(String newValue) {
super.set(newValue);
formatter = DateTimeFormatter.ofPattern(newValue);
}
};
public DateTimePicker() {
getStyleClass().add("datetime-picker");
setFormat(DefaultFormat);
setConverter(new InternalConverter());
// Syncronize changes to the underlying date value back to the dateTimeValue
valueProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == null) {
dateTimeValue.set(null);
} else {
if (dateTimeValue.get() == null) {
dateTimeValue.set(LocalDateTime.of(newValue, LocalTime.now()));
} else {
LocalTime time = dateTimeValue.get().toLocalTime();
dateTimeValue.set(LocalDateTime.of(newValue, time));
}
}
});
// Syncronize changes to dateTimeValue back to the underlying date value
dateTimeValue.addListener((observable, oldValue, newValue) -> {
setValue(newValue == null ? null : newValue.toLocalDate());
});
// Persist changes onblur
getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue)
simulateEnterPressed();
});
}
private void simulateEnterPressed() {
getEditor().fireEvent(new KeyEvent(getEditor(), getEditor(), KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false));
}
public LocalDateTime getDateTimeValue() {
return dateTimeValue.get();
}
public void setDateTimeValue(LocalDateTime dateTimeValue) {
this.dateTimeValue.set(dateTimeValue);
}
public ObjectProperty<LocalDateTime> dateTimeValueProperty() {
return dateTimeValue;
}
public String getFormat() {
return format.get();
}
public ObjectProperty<String> formatProperty() {
return format;
}
public void setFormat(String format) {
this.format.set(format);
}
class InternalConverter extends StringConverter<LocalDate> {
public String toString(LocalDate object) {
LocalDateTime value = getDateTimeValue();
return (value != null) ? value.format(formatter) : "";
}
public LocalDate fromString(String value) {
if (value == null) {
dateTimeValue.set(null);
return null;
}
dateTimeValue.set(LocalDateTime.parse(value, formatter));
return dateTimeValue.get().toLocalDate();
}
}
}
The dateTimeValue property contains the value with time, and the valueProperty contains only the date value.
I have not added tests for this component yet, so the implementation might change, check GitHub for the latest version.
JFXtras project has a working version for JavaFX 2.2. Look for CalendarPicker, CalendarTimePicker, ... at the repo, under the 2.2 branch.
You can test it by downloading the lastest release (2.2-r6-SNAPSHOT) from jfxtras.org.
This short snippet will create a calendar for picking both date and time:
#Override
public void start(Stage primaryStage) {
CalendarPicker dateTime = new CalendarPicker();
dateTime.withCalendar(Calendar.getInstance());
dateTime.withShowTime(Boolean.TRUE);
dateTime.withLocale(Locale.ENGLISH);
dateTime.calendarProperty().addListener(new ChangeListener<Calendar>() {
#Override
public void changed(ObservableValue<? extends Calendar> ov, Calendar t, Calendar t1) {
System.out.println("Selected date: "+t1.getTime().toString());
}
});
StackPane root = new StackPane();
root.getChildren().add(dateTime);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Date & Time from JFXtras 2.2");
primaryStage.setScene(scene);
primaryStage.show();
}
I find it most convenient to enter the time via the keyboard instead of changing it with sliders. It's quite easy to extend the included DatePicker to look like this:
I also find it annoying that the DatePicker doesn't commit the edited value in the TextField onblur, so the following code fixes that as well.
The snippet is written in Kotlin for brevety, you can easily convert it to Java via IntelliJ IDEA:
import javafx.beans.property.SimpleObjectProperty
import javafx.scene.control.DatePicker
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.input.MouseEvent
import javafx.util.StringConverter
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
class DateTimePicker(val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) : DatePicker() {
private var dateTimeValue = SimpleObjectProperty<LocalDateTime>(LocalDateTime.now())
init {
converter = object : StringConverter<LocalDate>() {
override fun toString(value: LocalDate?): String {
return if (dateTimeValue.get() != null) dateTimeValue.get().format(formatter) else ""
}
override fun fromString(value: String?): LocalDate? {
if (value == null) {
dateTimeValue.set(null)
return null
}
dateTimeValue.set(LocalDateTime.parse(value, formatter))
return dateTimeValue.get().toLocalDate()
}
}
// Syncronize changes to the underlying date value back to the dateTimeValue
valueProperty().addListener { observable, old, new ->
if (new == null) {
dateTimeValue.set(null)
} else {
if (dateTimeValue.get() == null) {
dateTimeValue.set(LocalDateTime.of(new, LocalTime.now()))
} else {
val time = dateTimeValue.get().toLocalTime()
dateTimeValue.set(LocalDateTime.of(new, time))
}
}
}
// Syncronize changes to dateTimeValue back to the underlying date value
dateTimeValue.addListener { observable, old, new ->
valueProperty().set(new?.toLocalDate())
}
// Persist changes onblur
editor.focusedProperty().addListener { observable, old, new ->
if (!new)
simulateEnterPressed()
}
}
private fun simulateEnterPressed() =
editor.fireEvent(KeyEvent(editor, editor, KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false))
fun dateTimeValueProperty() = dateTimeValue;
}
Bind your LocalDateTime property to the dateTimeValueProperty.
Slightly "improved" (at least for my needs) version that works with NullableTimeStamp... in order to be able to, well, null it (for ease with MySQL)...
Dunno if this can help anyone but here it is:
NullableTimeStamp:
public class NullableTimestamp extends Timestamp {
public NullableTimestamp() {
super(0L);
}
public NullableTimestamp(long value) {
super(value);
}
#Override
public String toString() {
return this.getTime() > 0L ? super.toString() : "";
}
public static NullableTimestamp valueOf(LocalDateTime localDateTime) {
return new NullableTimestamp(Timestamp.valueOf(localDateTime).getTime());
}
}
and DateTimePicker:
public class DateTimePicker extends DatePicker {
public static final String DefaultFormat = "yyyy-MM-dd HH:mm";
private DateTimeFormatter formatter;
private ObjectProperty<LocalDateTime> dateTimeValue = new SimpleObjectProperty<>(LocalDateTime.now());
private ObjectProperty<String> format = new SimpleObjectProperty<String>() {
public void set(String newValue) {
super.set(newValue);
formatter = DateTimeFormatter.ofPattern(newValue);
}
};
public DateTimePicker() {
getStyleClass().add("datetime-picker");
setFormat(DefaultFormat);
setConverter(new InternalConverter());
// Syncronize changes to the underlying date value back to the dateTimeValue
valueProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == null) {
dateTimeValue.set(null);
} else {
if (dateTimeValue.get() == null) {
dateTimeValue.set(LocalDateTime.of(newValue, LocalTime.now()));
} else {
LocalTime time = dateTimeValue.get().toLocalTime();
dateTimeValue.set(LocalDateTime.of(newValue, time));
}
}
});
// Syncronize changes to dateTimeValue back to the underlying date value
dateTimeValue.addListener((observable, oldValue, newValue) -> {
setValue(newValue == null ? null : newValue.toLocalDate());
});
// Persist changes onblur
getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue)
simulateEnterPressed();
});
}
private void simulateEnterPressed() {
getEditor().fireEvent(new KeyEvent(getEditor(), getEditor(), KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false));
}
public LocalDateTime getDateTimeValue() {
return dateTimeValue.get();
}
public void setDateTimeValue(LocalDateTime dateTimeValue) {
if(dateTimeValue.isAfter(LocalDateTime.of(1971, 6, 30, 12, 00)))
this.dateTimeValue.set(dateTimeValue);
else
this.dateTimeValue.set(null);
}
public ObjectProperty<LocalDateTime> dateTimeValueProperty() {
return dateTimeValue;
}
public String getFormat() {
return format.get();
}
public ObjectProperty<String> formatProperty() {
return format;
}
public void setFormat(String format) {
this.format.set(format);
}
class InternalConverter extends StringConverter<LocalDate> {
public String toString(LocalDate object) {
LocalDateTime value = getDateTimeValue();
return (value != null) ? value.format(formatter) : "";
}
public LocalDate fromString(String value) {
if (value == null) {
dateTimeValue.set(null);
return null;
}
dateTimeValue.set(LocalDateTime.parse(value, formatter));
return dateTimeValue.get().toLocalDate();
}
}
}
It basically masks the 0L Timestamp value as if it was NULL... hope this can help cheers

Resources