I have a autodrop Combobox and a EventListener for the "Events.ON_CHANGING". My problem is that only work once.
Example, I type,do the search, I erase the values, retype and no event is fired. I need to click in other component and then re-click on the combobox to type another time.
My code:
public class ComboUsuariosComponent extends Combobox {
public ComboUsuariosComponent(String width, boolean buttonVisible, boolean autodrop) {
this.setButtonVisible(buttonVisible);
this.setAutodrop(autodrop);
this.setWidth(width);
this.addEventListener(Events.ON_CHANGING, new GrillaComboOnChange());
}
private class GrillaComboOnChange implements EventListener<Event>{
#Override
public void onEvent(Event event) throws Exception {
finUsers(getValue());
}
}
}
Solved, i miss this.setInstant(true);
Related
I created an application that retrieves datas from a Mysql database and displays them in a JTable. Then I added checkboxes in the 1st column and I am able to display them with TableCellRendere. But when I try to check them , the checkboxes are not checked. In fact, I read how to use properly a TableCellEditor in this link, but I didn't understand well:
https://docs.oracle.com/javase/8/docs/api/javax/swing/table/TableCellEditor.html
Then I got this code but I don't know what to add in the method public Component getTableCellEditorComponent().
Here is the code which I need to complete:
public class CheckBoxCellEditor extends AbstractCellEditor implements TableCellEditor {
protected JCheckBox checkBox;
public CheckBoxCellEditor() {
checkBox = new JCheckBox();
checkBox.setHorizontalAlignment(SwingConstants.CENTER);
}
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column) {
// What should I add here and can you explain me
return checkBox;
}
public Object getCellEditorValue() {
return Boolean.valueOf(checkBox.isSelected());
}
}
Thanks
I have resolved the issue:
[https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSelectionDemoProject/src/components/TableSelectionDemo.java][1]
Thanks
I have had a challenge finding anything on the following situation. Let's say I have a record called DatabaseRecord which is a POJO with several fields:
public class DatabaseRecord {
private Long recordId;
private StringProperty foreignKeyId;
private StringProperty otherValuesForMainRecord....
... setters/getters
public class LookUpDataValue {
private String recordId;
private String descriptiveText;
private String otherValues.....
....
I have a combo box which displays the selectable values for the foreignKeyId value something like this:
#FXML
ComboBox<LookUpDataValue> combobox;
combobox.setCellFactory
(new Callback<ListView<LookUpDataValue>, ListCell<LookUpDataValue>>() {
#Override
public ListCell<LookUpDataValue> call(ListView<LookUpDataValue> p) {
ListCell<LookUpDataValue> cell = new ListCell<LookUpDataValue>() {
#Override
protected void updateItem(LookUpDataValue item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
} else {
setText(item.getDescriptiveText());
}
}
};
return cell;
}
});
I would like to Bidirectionally bind the POJO DatabaseRecord.foreignKeyIdProperty to the combobox.valueProperty() - but this doesn't work since one is a string and one is a LookUpDataValue object.
I would like this combobox to be set correctly when the records are loaded, and conversely update the record when it's changed.
I would appreciate any pointers on where I can find an example of this...
I was not able to change my datamodel so I found the following solution which works.
// Handle ComboBox event.
myComboBox.setOnAction((event) -> {
LookUpDataValue selected = myComboBox.getSelectionModel().getSelectedItem();
if(selected != null){
dto.setForeignKeyId(selected.getId());
}
});
This works well. Thanks for your comments.
When i use arrow key in combobox (implementing changeListener) it fires action.How can I make it to work only when enter is pressed or selected with mouse .
Edit:
Basically the problem I feel is with mouse event. An action is fired when dropdown button of combobox is pressed in
CCombobox.setEditable(true);
CCombobox.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Clicked");
}
The ChangeListener is registering modification made on the Selected Items. It will never give you information about the mouse or the keyboard.
What you have to do is to add some EventHandler on keyTyped (or keyPressed), and also on MouseClicked in order to catch specifically what you want. You can then react to those events:
//cb = a ComboBox
cb.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
//Do what you want to do
}
}
});
cb.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
//Do what you want to do
}
});
I have often run into situations where I want to have a 3-State checkbox to select all/deselect all of my view models. I have run into difficulties creating a reusable class to do this with.
I tried to create the following base classes:
public class SelectAllListVM
{
public List<SelectableVM> ChildList = new List<SelectableVM>();
public bool? SelectAll // call UpdateSelectedChildren on set
internal void UpdateSelectAll ()
// Set SelectAll based on ChildList elements
// true = all selected, false = non selected, null = some selected
private void UpdateSelectedChildren () {
foreach ( SelectableVM vm in ChildList )
vm.SetIsSelected( SelectAll.Value );
}
}
public class SelectableVM
{
public SelectableVM (SelectAllListVM parentVM) {}
public bool IsSelected // call parentVM.UpdateSelectAll
}
The problem with this is every time I want to iterate through the ChildList I have to cast the SelectableVM to it's concrete implementation. How can I reuse this behavior and avoid casting?
I did some attached behavior trickery back in the day to do this. Everything is handled by the view no need for the VM to care about select all logic. I wrote the details of how to do it in three parts (part 1, part 2, part 3) I made the code available on fileden...and subsequently lost it because I didn't log into the account enough times. But all the code is there throughout the three posts.
You could create an Interface ISelectableVM
public interface ISelectableVM
{
public bool IsSelected;
}
and implement it in your derived classes.
public class SelectableVM : ISelectableVM
{}
public class OtherSelectableVM : ISelectableVM
{}
Then in your ParentVM you don't have to cast:
public class SelectAllListVM
{
public List<ISelectableVM> ChildList = new List<ISelectableVM>();
public bool? SelectAll; // call UpdateSelectedChildren on set
private void UpdateSelectedChildren()
{
foreach (ISelectableVM vm in ChildList)
vm.IsSelected = SelectAll.Value;
}
}
Instead of an interface you could also use
public class BaseSelectableVM
{
public bool IsSelected;
}
and derive from it.
I have a WPF ListView bound to a CollectionViewSource. The source of that is bound to a property, which can change if the user selects an option.
When the list view source is updated due to a property changed event, everything updates correctly, but the view is not refreshed to take into account any changes in the CollectionViewSource filter.
If I attach a handler to the Changed event that the Source property is bound to I can refresh the view, but this is still the old view, as the binding has not updated the list yet.
Is there a decent way to make the view refresh and re-evaluate the filters when the source changes?
Cheers
Updating the CollectionView.Filter based on a PropertyChanged event is not supported by the framework.
There are a number of solutions around this.
1) Implementing the IEditableObject interface on the objects inside your collection, and calling BeginEdit and EndEdit when changing the property on which the filter is based.
You can read more about this on the Dr.WPF's excellent blog here : Editable Collections by Dr.WPF
2) Creating the following class and using the RefreshFilter function on the changed object.
public class FilteredObservableCollection<T> : ObservableCollection<T>
{
public void RefreshFilter(T changedobject)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedobject, changedobject));
}
}
Example:
public class TestClass : INotifyPropertyChanged
{
private string _TestProp;
public string TestProp
{
get{ return _TestProp; }
set
{
_TestProp = value;
RaisePropertyChanged("TestProp");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
FilteredObservableCollection<TestClass> TestCollection = new FilteredObservableCollection<TestClass>();
void TestClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "TestProp":
TestCollection.RefreshFilter(sender as TestClass);
break;
}
}
Subscribe to the PropertyChanged event of the TestClass object when you create it, but don't forget to unhook the eventhandler when the object gets removed, otherwise this may lead to memory leaks
OR
Inject the TestCollection into the TestClass and use the RefreshFilter function inside the TestProp setter.
Anyhow, the magic here is worked by the NotifyCollectionChangedAction.Replace which updates the item entirely.
Are you changing the actual collection instance assigned to the CollectionViewSource.Source, or are you just firing PropertyChanged on the property that it's bound to?
If the Source property is set, the filter should be recalled for every item in the new source collection, so I'm thinking something else is happening. Have you tried setting Source manually instead of using a binding and seeing if you still get your behavior?
Edit:
Are you using CollectionViewSource.View.Filter property, or the CollectionViewSource.Filter event? The CollectionView will get blown away when you set a new Source, so if you had a Filter set on the CollectionView it won't be there anymore.
I found a specific solution for extending the ObservableCollection class to one that monitors changes in the properties of the objects it contains here.
Here's that code with a few modifications by me:
namespace Solution
{
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e != null) // There's been an addition or removal of items from the Collection
{
Unsubscribe(e.OldItems);
Subscribe(e.NewItems);
base.OnCollectionChanged(e);
}
else
{
// Just a property has changed, so reset the Collection.
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
protected override void ClearItems()
{
foreach (T element in this)
element.PropertyChanged -= ContainedElementChanged;
base.ClearItems();
}
private void Subscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged += ContainedElementChanged;
}
}
private void Unsubscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged -= ContainedElementChanged;
}
}
private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e);
// Tell the Collection that the property has changed
this.OnCollectionChanged(null);
}
}
}
Maybe a bit late to the party but just in case
You can also use CollectionViewSource.LiveSortingProperties
I found it through this blog post.
public class Message : INotifyPropertyChanged
{
public string Text { get; set; }
public bool Read { get; set; }
/* for simplicity left out implementation of INotifyPropertyChanged */
}
public ObservableCollection<Message> Messages {get; set}
ListCollectionView listColectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(Messages);
listColectionView.IsLiveSorting = true;
listColectionView.LiveSortingProperties.Add(nameof(Message.Read));
listColectionView.SortDescriptions.Add(new SortDescription(nameof(Message.Read), ListSortDirection.Ascending));
I found a relatively simple method to do this.
I changed the readonly ICollectionView property to get/set and added the raised property event:
Property TypeFilteredCollection As ICollectionView
Get
Dim returnVal As ICollectionView = Me.TypeCollection.View
returnVal.SortDescriptions.Add(New SortDescription("KeyName", ListSortDirection.Ascending))
Return returnVal
End Get
Set(value As ICollectionView)
RaisePropertyChanged(NameOf(TypeFilteredCollection))
End Set
End Property
Then to update, i just used:
Me.TypeFilteredCollection = Me.TypeFilteredCollection
This clearly won't work if you don't have somewhere to trigger that update though.