Change dynamically border color of an agent in Repast Symphony - repast-simphony

I have to change dynamically the border color of an agent. The agent is represented as the default circle on the display. The displayed color has to change according to a boolean variable defined inside the agent Class.
When the agent is created and displayed for the first time, it has the correct style but when the boolen variable inside the agent class changes, the border color does not change.
If I do the same for the fill color of the agent instead, it works fine. I put here the code I used:
public class NodeStyle extends DefaultStyleOGL2D{
#Override
public Color getBorderColor(Object agent) {
Color borderColor = Color.BLACK;
if(agent instanceof Process) {
Process p = (Process)agent;
if(p.isParticularNode) {
borderColor = Color.RED;
}
}
return borderColor;
}
}
When the agent is created and it is added to the context, it take the correct color but if isParticularNode changes, the border color does not change.
I've tryed also to do the same importing the interface StyleOGL2D but the problem remains

I tried this with the JZombies demo, adding an "id" double to each zombie that is set with RandomHelper.nextDouble() each tick. The border color changes as expected. By default the border size is 0, so perhaps that needs to be changed in your code.
public class ZombieStyle extends DefaultStyleOGL2D {
public Color getColor(Object agent) {
return Color.RED;
}
public Color getBorderColor(Object agent) {
Zombie z = (Zombie)agent;
if (z.getID() > 0.5) {
return Color.GREEN;
}
return Color.black;
}
public int getBorderSize(Object agent) {
return 4;
}
}

Related

How to update ItemFragment when item property changes

I'm quite confused about the relationship between an ItemViewModel and its underlying item. I'm trying to show a badge on the screen, and then if the badge is "achieved" on another thread, the badge should update on screen.
Right now, the badge code looks like this:
class Badge {
val achievedProperty = SimpleBooleanProperty(this, "achieved", false)
var achieved by achievedProperty
}
class BadgeModel: ItemViewModel<Badge>() {
val achieved = bind(Badge::achievedProperty)
}
Next, I want to display it on the screen, in an ItemFragment subclass:
class BadgeFragment(badge: Badge): ItemFragment<Badge>() {
private val model: BadgeModel by inject()
init {
model.item = badge
}
override val root = rectangle {
width = 50
height = 50
stroke = Color.BLACK
fill = if (model.achieved) Color.RED else Color.GREEN
}
}
This works fine to start, but if I then set badge.achieved = true (in my controller), the color of the badge on screen doesn't change.
I'm clearly missing something about the relationship between the object and the model, but I'm having a lot of trouble figuring it out from documentation. Can someone help me get my fragment working the way I want it to?
Your problem isn't specific to models or almost anything TornadoFX-related. The way you've written it only checks for the color once upon creation. You need to use properties or bindings to listen to property changes:
class Test : Fragment() {
val modelAchieved = SimpleBooleanProperty(true) // pretend this is model.achieved
val achievedColor = modelAchieved.objectBinding { isAchieved ->
if (isAchieved == true) Color.RED
else Color.GREEN
}
override val root = vbox {
togglebutton("Toggle") {
selectedProperty().bindBidirectional(modelAchieved)
}
rectangle(width = 50, height = 50) {
stroke = Color.BLACK
fillProperty().bind(achievedColor)
}
}
}
I would also bidirectionally bind the item properties of the viewmodel and fragment together so they stay in sync. Or just use a regular fragment, and reference the model's item property by itself.

Styling background of TornadoFX ListView

Is it possible to style a ListView component so that none of the elements have a shaded background?
I.e not like this:
But instead have them all styled like the first, third, fifth item etc.
TIA
In the default stylesheet, modena.css the background color for ListCells is governed by the following lines of code:
.list-cell,
.tree-cell {
-fx-background: -fx-control-inner-background;
-fx-background-color: -fx-background;
-fx-text-fill: -fx-text-background-color;
}
/* ... */
.list-cell:odd {
-fx-background: -fx-control-inner-background-alt;
}
So to remove the alternative color for the odd-numbered cells (note that counting is zero-indexed, so the odd-numbered cells are the 2nd, 4th, etc in the list view), you just need to include the following in your external CSS file, to revert the color for the odd-numbered cells to the same as the even-numbered cells:
.list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
If you need to apply this to one specific ListView, you can set an id on that ListView:
ListView myListView ;
// ...
myListView.setId("plain-list-view");
and then the CSS selector becomes
#plain-list-view .list-cell:odd {
-fx-background: -fx-control-inner-background ;
}
You need to create a custom ListCell with a non-null Background. Once you do this, the automatic colour handling of the ListView for selected rows won't work properly any more. So you'll have to handle that yourself. The selection action will invert the colour of the text to white, but that's all. So you need to set the background colour of the cell based on the "Selected" property of the ListCell. In Java it would look like this:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
Background unselectedBackground =
new Background(new BackgroundFill(Color.WHITESMOKE, CornerRadii.EMPTY, Insets.EMPTY));
Background selectedBackground = new Background(new BackgroundFill(Color.BROWN, CornerRadii.EMPTY,
Insets.EMPTY));
backgroundProperty().bind(Bindings.createObjectBinding(() -> isSelected() ? selectedBackground :
unselectedBackground, selectedProperty()));
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
Once you do this, the cell background is no longer transparent, and the stripe pattern of the ListView itself won't show through.
EDIT:
As pointed out, this IS heavy-handed, except that in most cases a ListView isn't going to be a simple Label with a string in it. It's going to have some sort of layout in the ListCell that is going to require that you create a custom ListCell in any event.
However, messing with the Background directly via a binding to the "Selected" property is clumsy. You can create a new StyleClass, and then just define the modified PseudoClasses in the css. Then add this new StyleClass to the custom ListCell, and then it will handle it automatically as it applies the "EVEN" and "ODD" pseudoclasses.
One thing I found was that since the new "odd" definition gets applied after all of the other definitions in the default Modena css, that the "SELECTED" pseudoclass for ODD lines is suppressed. This means that the odd and even lines look different when they are selected, so a duplicate "SELECTED" definition needed to be added to the new css after the "ODD" definition. Then everything works properly. So the new code looks like this:
The CSS:
.custom-list-cell:odd {
-fx-background: -fx-control-inner-background;
}
.custom-list-cell:selected {
-fx-background: -fx-selection-bar;
-fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
}
The main, now loads the new stylesheet into the Scene:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
scene.getStylesheets().add(getClass().getResource("/css/samples.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
And then the only customization to the ListCell is to add the new StyleClass:
public class ListBackgroundWhite extends ListView<String> {
public ListBackgroundWhite() {
super();
setCellFactory(listView -> new WhiteListCell());
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}
static class WhiteListCell extends ListCell<String> {
WhiteListCell() {
getStyleClass().add("custom-list-cell");
}
#Override
public void updateItem(String item, boolean isEmpty) {
super.updateItem(item, isEmpty);
if (!isEmpty) {
setText(item);
} else {
setText(null);
}
}
}
}
But if you really are just wanting to have a ListView with just simple labels in it, you can just have the cell factory add the StyleClass on to the standard TextFieldListCell:
public ListBackgroundWhite() {
super();
setCellFactory(listView -> {
ListCell<String> cell = new TextFieldListCell<>();
cell.getStyleClass().add("custom-list-cell");
return cell;
});
setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}

Repast: set different color for different edges

I have two types edges in my supply chain model: demand_links and supply_links.
the default color is gray for all links. But I want to change the color of demand_links to red each time the attribute of the demand_link is changed (Note:the edge is the custom edge agent through edge creator). How to do this?
Below is my codes for simple test and it didn't work.
public class EdgeStyle2D extends DefaultStyleOGL2D {
#Override
public Color getColor(Object o){
// if (((CustomEdge) o).getCurrent_dl() == 1) {
// return Color.RED;
// }
// else {
// return Color.BLACK;
// }
if (o instanceof Distributor)
return Color.YELLOW;
return null;
}
}
I get the error when initialize.
Caused by: java.lang.ClassCastException: class supplyChainSystem.EdgeStyle2D cannot be cast to class repast.simphony.visualizationOGL2D.EdgeStyleOGL2D (supplyChainSystem.EdgeStyle2D and repast.simphony.visualizationOGL2D.EdgeStyleOGL2D are in unnamed module of loader repast.simphony.plugin.ExtendablePluginClassLoader #61af1510)
For styling links in this way, you should follow the example in the zombies.style.LinkStyle class within the Zombies_Demo model. Here's what the relevant parts of that class look like:
public class LinkStyle implements EdgeStyleOGL2D {
public Color getColor(RepastEdge<?> edge) {
BaseLink<?> link = (BaseLink<?>) edge;
return ReLogoSupport.lookupColor(link.getColor());
}
public int getLineWidth(RepastEdge<?> edge) {
return (int) (Math.abs(edge.getWeight()));
}
}
And you would use a class like this for the network (as opposed to agent) style.

JavaFX How to change ProgressBar color dynamically?

I was trying to solve my problem with colored progress bars in this thread. The solution was present, but then I ran into another problem: I can't change color dynamically from my code. I want to do it right from my code, not with pre-defined .css. Generally I can do it, but I run into some difficulties when I try to do it with more than one progess bar.
public class JavaFXApplication36 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
ProgressBar pbRed = new ProgressBar(0.4);
ProgressBar pbGreen = new ProgressBar(0.6);
pbRed.setLayoutY(10);
pbGreen.setLayoutY(30);
pbRed.setStyle("-fx-accent: red;"); // line (1)
pbGreen.setStyle("-fx-accent: green;"); // line (2)
root.getChildren().addAll(pbRed, pbGreen);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
I always get 2 red progressbars with it! It seems that code in line (1) changes the style of ProgressBar class, not the instance.
Another strange moment is that deleting line (1) don't result in 2 green progress bars. So I can figure that line (2) is completely useless!! WHY?! That's definitely getting odd.
Is there any way to set different colors for separate progressbars?
See also the StackOverflow JavaFX ProgressBar Community Wiki.
There is a workaround you can use until a bug to fix the sample code in your question is filed and fixed.
The code in this answer does a node lookup on the ProgressBar contents, then dynamically modifies the bar colour of the progress bar to any value you like.
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ProgressBarDynamicColor extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
PickedColorBar aquaBar = new PickedColorBar(0.4, Color.AQUA);
PickedColorBar fireBar = new PickedColorBar(0.6, Color.FIREBRICK);
HBox layout = new HBox(20);
layout.getChildren().setAll(aquaBar, fireBar);
layout.setStyle("-fx-background-color: -fx-box-border, cornsilk; -fx-padding: 15;");
stage.setScene(new Scene(layout));
stage.show();
aquaBar.wasShown();
fireBar.wasShown();
}
class PickedColorBar extends VBox {
private final ProgressBar bar;
private final ColorPicker picker;
private boolean wasShownCalled = false;
final ChangeListener<Color> COLOR_LISTENER = new ChangeListener<Color>() {
#Override public void changed(ObservableValue<? extends Color> value, Color oldColor, Color newColor) {
setBarColor(bar, newColor);
}
};
public PickedColorBar(double progress, Color initColor) {
bar = new ProgressBar(progress);
picker = new ColorPicker(initColor);
setSpacing(10);
setAlignment(Pos.CENTER);
getChildren().setAll(bar, picker);
}
// invoke only after the progress bar has been shown on a stage.
public void wasShown() {
if (!wasShownCalled) {
wasShownCalled = true;
setBarColor(bar, picker.getValue());
picker.valueProperty().addListener(COLOR_LISTENER);
}
}
private void setBarColor(ProgressBar bar, Color newColor) {
bar.lookup(".bar").setStyle("-fx-background-color: -fx-box-border, " + createGradientAttributeValue(newColor));
}
private String createGradientAttributeValue(Color newColor) {
String hsbAttribute = createHsbAttributeValue(newColor);
return "linear-gradient(to bottom, derive(" + hsbAttribute+ ",30%) 5%, derive(" + hsbAttribute + ",-17%))";
}
private String createHsbAttributeValue(Color newColor) {
return
"hsb(" +
(int) newColor.getHue() + "," +
(int) (newColor.getSaturation() * 100) + "%," +
(int) (newColor.getBrightness() * 100) + "%)";
}
}
}
The code uses inlined string processing of css attributes to manipulate Region backgrounds. Future JavaFX versions (e.g. JDK8+) will include a public Java API to manipulate background attributes, making obsolete the string processing of attributes from the Java program.
Sample program output:

How to Color TableViewer Rows alternatively

I'm using Viewer Framework in my rcp application, i would like to color viewer rows alternatively,i tried to override getBackground method of ColumnLabelProvider, below is code snippet
col.setLabelProvider(new ColumnLabelProvider(){
----//other methods
#override
public Color getBackground(Object element) {
return gray;//here gray is color object defined somewhere in class
}
});
this colors the columns, but not a row, below is output
how do i achieve this correctly
You can find an example here which uses an IColorProvider. Maybe you could just reuse the getBackground() method in your code, just change the reference to your tableViewer:
public Color getBackground(Object element) {
ArrayList list = (ArrayList) tableViewer.getInput();
int index = list.indexOf(element);
if ((index % 2) == 0) {
return gray;
} else {
return null;
}
}