I'm new to JavaFX and I would like to do the following:
Whenever the value of one of my four textfields is changed, I would like a fifth textfield to calculate the sum of the values from the others. Lets assume the values come already as numbers.
Code looks like this:
power1KW = new TextField();
power2KW = new TextField();
... etc.
powerSumKW = new TextField();
How do I do this properly? Do I add a ChangeListener on each of my powerXKW-TextFields? And calculate on change?
Or do I need to add an EventHandler for my powerSumKW-Textfield? How can I handle the Event fired only by the powerXKW-TextFields?
Any advice would be appreciated. Thank you!
I would just bind the textProperty of the 5th Textfield to the other textfields..something like this:
tf5.textProperty().bind(Bindings.createStringBinding(()->{
//Do your calculation
//Return result as String
return result;
}, tf1.textProperty(),tf2.textProperty(), tf3.textProperty(), tf4.textProperty()));
Related
I have written a windows universal app under windows 10 that has a ListView.
This ListView updates every five seconds if new data if available. Its data source is an ObservableCollection that only allows a maximum of ten items to be shown, with the newest being inserted at the front of the collection. This seems to work well as you see the ListView with items slowly scrolling down the screen.
What I want to do is add some sort of colour transition to the new items in the ListView, so that when they appear, the background of the item starts off grey and fades to white. I want this effect so that a user can easily see the new item or items that have just appeared in the ListView.
The new objects added to the collection have a flag set to indicate they are new. I thought this could be used as an indicator if the animation process was able to reset this flag after the animation? Or should I look to use an event off the ListView, if there is one?
I’m new to storyboards so am not sure the best approach. Can anyone advise on the areas I should research to get the animation or even if it's possible under the UWP?
Basically, whenever a new item has been added, you want to animate its color to light gray and then animate it right back.
So the key thing is to find the event that's invoked during the item container creation. In this case, ContainerContentChanging is your friend.
Since you need to animate the color a few times during an animation, you will need ColorAnimationUsingKeyFrames rather than a normal ColorAnimation. The whole Timeline and Storyboard syntax can be a bit confusing at times so I have created a simple demo for you here. Hope it helps. :)
private void OnListViewContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.ItemContainer != null && !args.InRecycleQueue && args.Phase == 0)
{
var colorAnimation = new ColorAnimationUsingKeyFrames
{
// 'cause the new item comes in with an animation of which duration is about 300s, we add a little delay here to only
// animate the color after it appears.
BeginTime = TimeSpan.FromMilliseconds(300)
};
var keyFrame1 = new LinearColorKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)), Value = Colors.White };
var keyFrame2 = new LinearColorKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(400)), Value = Colors.LightGray };
var keyFrame3 = new LinearColorKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(1200)), Value = Colors.White };
colorAnimation.KeyFrames.Add(keyFrame1);
colorAnimation.KeyFrames.Add(keyFrame2);
colorAnimation.KeyFrames.Add(keyFrame3);
Storyboard.SetTarget(colorAnimation, args.ItemContainer);
Storyboard.SetTargetProperty(colorAnimation, "(Control.Background).(SolidColorBrush.Color)");
var storyboard = new Storyboard();
storyboard.Children.Add(colorAnimation);
storyboard.Begin();
}
}
Here's how it looks like in a demo app.
I have created a (JavaFX) combobox, which I am populating with an observable list made from HBoxes, so that I can display an image with some text in each list cell.
This displays well, other than the fact that whenever you select one of the items in the list, it will disappear. Once you have selected every item, it will not render any items at all. (You can still select them by clicking in the space where they previously were.
Do you know how I might correct this, please?
Part of my code is displayed below:
public class IconListComboBox {
Group listRoot = new Group();
VBox mainVBox = new VBox();
ComboBox selectionBox = new ComboBox();
List<HBox> list = new ArrayList<HBox>();
ListView<HBox> listView = new ListView<HBox>();
ObservableList<HBox> observableList;
public IconListComboBox(int dimensionX, int dimensionY, ArrayList<String> names, ArrayList<ImageView> icons)
{
//VBox.setVgrow(list, Priority.ALWAYS);
selectionBox.setPrefWidth(dimensionY);
selectionBox.setPrefHeight(40);
for(int i = 0; i < names.size(); i++)
{
HBox cell = new HBox();
Label name = new Label(names.get(i));
Label icon = new Label();
icon.setGraphic(icons.get(i));
name.setAlignment(Pos.CENTER_RIGHT);
icon.setAlignment(Pos.CENTER_LEFT);
icon.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(icon, Priority.ALWAYS);
cell.getChildren().add(icon);
cell.getChildren().add(name);
list.add(cell);
}
observableList = FXCollections.observableList(list);
listView.setItems(observableList);
listView.setPrefWidth(dimensionX);
selectionBox.setMaxWidth(dimensionX);
listView.setMaxWidth(dimensionX);
selectionBox.setItems(observableList);
mainVBox.getChildren().add(selectionBox);
mainVBox.getChildren().add(listRoot);
//mainVBox.getChildren().add(listView);
//listRoot.getChildren().add(listView);
}
Thanks in advance for your assistance!
Ok, so I've managed to work this out, thanks to #James_D 's very kind help!
This is for anyone who, like me, was slightly daunted by the example that was given in the Java documentation. (Although, my description below is probably worse!!)
So, I started by adding an HBox which was in the layout I wanted straight into the ComboBox... which is a bad idea!
So, before you go deleting everything you've done, save the HBox somewhere, and do the following:
1. Create a new class to hold your date (Image, and String) which will go into each cell. Make getters/setters to do this. I called mine IconTextCell.
2. Add the following code to the class where your ComboBox is located:
yourComboBox.setCellFactory(new Callback<ListView<T>, ListCell<T>>() {
#Override public ListCell<T> call(ListView<T> p) {
return new ListCell<T>() {
Label name = new Label();
Label icon = new Label();
private final HBox cell;
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
cell = new HBox();
//HERE, ADD YOUR PRE-MADE HBOX CODE
name.setAlignment(Pos.CENTER_RIGHT);
icon.setAlignment(Pos.CENTER_LEFT);
icon.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(icon, Priority.ALWAYS);
cell.getChildren().add(icon);
cell.getChildren().add(name);
}
#Override protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
name.setText(item.getLabel());
icon.setGraphic(item.getIcon());
setGraphic(cell);
//HERE IS WHERE YOU GET THE LABEL AND NAME
}
}
};
}
});
You'll see that the main content is very similar to what I had already produced, so no code is lost.
Just replace "T" with your own class for representing a cell.
3. This will display your icon and string in the list, but you need to to also be displayed in the button (the grey top selector part of the combobox, aka the button). Do do this, we need to add the following code:
class IconTextCellClass extends ListCell<T> {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getLabel());
}
}
};
selectionBox.setButtonCell(new IconTextCellClass());
...and that's how I did it. I hope this helps - please compare this to my original post. The actual content (where I create the HBox etc) is obviously not generalised. You can make this as simple or as complex as you want.
Once again, thanks for your help! I hope this post helps others!
This is exactly the example cited in the documentation under "A warning about inserting Nodes into the ComboBox items list".
The list of items in the combo box should represent data - not the UI component used to display the data. The issue is that the HBox cannot appear twice in the scene graph: so it cannot appear both in the "selected cell" and as a cell in the drop-down list.
Instead, create a class that represents the data you are displaying in the ComboBox, and use a cell factory to instruct the ComboBox as to how to display those data. Be sure to set a button cell as well (the cell used for the selected item).
I have a TableView and I would like to bind the disable property of a Button with the size of the ObservableList model of the table. In particular, I would like to disable the button when the size of the ObservableList is grater than 2.
How can I achieve that?
To disable another button when no row is selected in table I used
editRoadButton.disableProperty().bind(roadsTable.getSelectionModel().selectedItemProperty().isNull());
Is there a similar way?
There are factory methods for useful bindings in the Bindings class. In your case f.i.:
button.disableProperty().bind(Bindings.size(items).greaterThan(2));
You can do something like that
ListProperty<String> list = new SimpleListProperty<>(FXCollections.<String>emptyObservableList());
Button foo = new Button();
foo.disableProperty().bind(new BooleanBinding() {
{
bind(list);
}
#Override
protected boolean computeValue() {
return list.size() > 2;
}
});
I have above scenario: If user click on ListBox, it will either have sub items (again ListBox) or detail view.
So what i did currently is: Whenever user clicks any item, made a web call and filled up the same ListBox if clicked item is having further sub items.
Now, issue comes in picture:
Suppose i am in 4th screen (detail view),
Moved to the 3rd and 2nd screen with data maintained as stack (Its working fine, yes i am maintaining data in ObservableCollection<ObservableCollection<MyObjects>> so while moving back, i am fetching data from there)
Now, if i click any item in screen 2, it will open detail view for the screen 3 ListBox data.
Means that ListBox is not getting notified that we have filled data inside OnBackKeyPress()
FYI, i am filling up ListBox and WebBrowser in the same page., so my problem is that how do i notify ListBox once i filled up data from stack which i have maintained?
Yes i have also implemented INotifyPropertyChanged but don't know why its not working.
Please check my code:
ListBox and WebView screen: http://pastebin.com/K1G27Yji
RootPageItem class file with the implementation of INotifyPropertyChanged: http://pastebin.com/E0uqLtVG
sorry for pasting code in above way, i did as question is being long.
Problem:
How do i notify ListBox that data is changed from OnBackKeyPress?
And what is the behavior if you set:
listBox1.ItemsSource = null;
before
listBox1.ItemsSource = listRootPageItems;
This is just wrong architecture. Instead of reloading the same listbox, please add a single page for each screen. Share data between them inside the App class (internal static) and use the built in navigation stack for handling "going back". Don't override OnBackKeyPress for this purpose.
You will get your desired functionality for "free" with easier to maintain and use codebase.
Oops it was a silly mistake i made.
I forgot to set items[] array inside OnBackKeyPress() but was accessing while clicking item, hence its having items[] data of last step we moved in forward direction, it was executing the same data.
Now, i have just included a single line and it has solved my problem.
items = listRootPageItems.ToArray(); // resolution point
So final code of onBackKeyPress() is:
/**
* While moving back, taking data from stack and displayed inside the same ListBox
* */
protected override void OnBackKeyPress(CancelEventArgs e)
{
listBox1.Visibility = Visibility.Visible;
webBrowser1.Visibility = Visibility.Collapsed;
listBox1.SelectedIndex = -1;
if (dataStack.Count != 0)
{
listBox1.ItemsSource = null;
listRootPageItems = dataStack[dataStack.Count-1];
listBox1.ItemsSource = listRootPageItems;
items = listRootPageItems.ToArray(); // resolution point
dataStack.Remove(listRootPageItems);
e.Cancel = true;
}
}
I'm trying to add ListItems to a ListBox (ListBox3) depending on the selectedItem of another ListBox (ListBox1). The problem is , The Items aren't added to the Listbox.
Here's the code :
private void createlist()
{
if (listBox1.SelectedValue.ToString().Equals("EPL"))
{
ListBoxItem manchesterunited = new ListBoxItem();
manchesterunited.Content = "Manchester United";
listBox3.Items.Add(manchesterunited);
}
}
private void listBox1_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
createlist();
}
createlist() does the changes and is called in the SelctionChanged() event of ListBox1.
New to C# and WP7 programming , any help will be much appreciated.
Create the lists in your viewmodel and bind the listbox to a list<> in your viewmodel say SelectedList. When the user selects the item from ListBox1 just change the value of SelectedList with the appropriate List and Notify the property changed event. And it will be done.!
i think you program not run in mvvm structure.
make sure your logic is right. you can make a breakpoint at the line
ListBoxItem manchesterunited = new ListBoxItem();
Ensure run those code in if code block.
the way add a control in a listbox is correct.