I have 5 pictures in the image properties in simulation window. I would like the images to be changing every 5 seconds. In Image properties advanced section i can change the picture manually using image index. Can I use while loop to do such operation in simulation window?
If yes How can I implement it?
In the simulation window you can do this on the initial experiment setup java action:
new Thread(new Runnable() {
public void run() {
while(true){
image.setIndex(image.getIndex()==image.getImageCount()-1 ? 0 : image.getIndex()+1);
try{
TimeUnit.SECONDS.sleep(5);
}catch(Exception e){
}
}
}
}).start();
This will require to add in the advanced section, on the imports section: import java.util.concurrent.TimeUnit;
Related
So how does one end an application/game on a button click and exit as if the window red close symbol (X) has been clicked on or better still
how does one end the current application and without closing the whole window / stage starts a new one ?
so for example we have something like
public class Main extends Application
{
public Scene scene ;
private parent createContent()
{
// root pane, nodes and everything is here
//which makes up the game
//return root;
}
#Override
public void start(Stage stage)
{
scene = new Scene(createContent());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {launch(args); }
}
So at the end of the current game, the user should be giving the option to start a new game or to exit the application completely by clicking on buttons. If he should click on exit game then the game should close as if he has pressed on the window red x close symbol.
If the user should click on start a new game, then the prefered behavior will be for method
private parent createContent()
to start all over again, but of course all stages and nodes created in the previous calls of createContent() should be eliminated..
How can this be done?
I have the similar workflow in my project and I implemented the next way.
Register a handler for OnCloseRequest:
stage.setOnCloseRequest(windowEvent -> appToBeClosed(stage, windowEvent));
Below methods to show a dialog with a question. Only if an user decided to stay you should consume the current window event and do something otherwise the application will be closed:
private void appToBeClosed(Stage notUsedStage, WindowEvent windowEvent) {
if (hasNotSavedEvents()) {
final Optional<ButtonType> userResponse = alertAboutNotSavedChangedEvents(
"alert.changed.header", "alert.changed.content");
if (userResponse.isPresent() && userResponse.get() == ButtonType.NO) {
windowEvent.consume();
}
}
}
private Optional<ButtonType> alertAboutNotSavedChangedEvents(String headerResourceKey,
String contentResourceKey) {
final Alert alert = new Alert();
// TODO prepare alert as you wish...
return alert.showAndWait();
}
I hope the main idea is clear and you will be able to adopt it to your project.
Let me know your questions.
I have two scenes, scene 1 has a Label on it that simply reads "This is scene 1", it also has a button on it with the text "Press me to go to scene 2". scene 2 is similar to scene 1 but the Label and text on scene 2 say the opposite.
The problem is very simple, or at least should be. I am able to do this the javaFX way but cannot seem to do it the FXML way.
I have a main class -
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class ManinApp extends Application
{
Stage primaryStage;
private AnchorPane rootLayout;
public static void main(String [] args)
{
launch(args);
}
public void start(Stage primaryStage)
{
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Two Scenes");
initRootLayout();
//showSecondScene();
}
public void initRootLayout()
{
try
{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(ManinApp.class.getResource("Scene1.fxml"));
rootLayout = (AnchorPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
}
catch(IOException e)
{
e.printStackTrace();
}
}
/**
public void showSecondScene()
{
try
{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(ManinApp.class.getResource("Scene2.fxml"));
AnchorPane secondScene = (AnchorPane)loader.load();
rootLayout.getChildren().add(secondScene);
}
catch(IOException e)
{
e.printStackTrace();
}
}
*/
public Stage getPrimaryStage()
{
return primaryStage;
}
}
the showSecondScene() has been commented out for now. My understanding is that you also need a Controller class to wire up the code to SceneBuilder?
the solution the FX way was
btnscene1.setOnAction(e ->
{
if(e.getSource() == btnscene1)
thestage.setScene(scene2);
else
thestage.setScene(scene1);
});
btnscene2.setOnAction(e ->
{
if(e.getSource()==btnscene2)
thestage.setScene(scene1);
else
thestage.setScene(scene2);
});
apologies for the formatting!
how am I able to do this using a controller class from which i am able to use the primary stage and two scene declared in my main class?
i hope it makes sense
I think your are doing quite well. FXML (and SceneBuilder) are used correctly here.
I would suggest few things:
Use a root container (e.g. StackPane) to host either scene1 or scene2
(better names would be layout1 / layout2). You don't need to use
different Scene here.
Load both fxml files at init time (or lazy loading if needed)
switch from one to the other by removing the content of the root container, and adding the other one.
Now, if the layouts are big, with a lot of css involved, and you need to switch very often from layout1 to layout2, you may want to add both layout in the root container. Then, use:
setVisible()
setManaged()
... on the root of the layout you want to hide / show.
Doing this, you avoid the layout and css steps that is done as soon as you add a node in the scene graph.
While I technically understand, what you want to achieve, I'm still lost about the reason behind it.
If you just want to switch the "main" content of the window, use a StackPane as the root, add multiple Layouts to that stack, and solve your problem by switching the one you want to work on #toFront().
Normally the Layouts on the stack are transparent (except for the controls like buttons and so on, of course), so you would either need to set a background of the stacked Layouts OR (which I would prefer) toggle the visibility of the one in the back (or set opaqueness to 0, or something like that).
Hi does anyone know a good way to take a screenshot of a simulation, in such way that you can specify the resolution and get a higher quality image?
the only way i can think of is zooming in and stitch multiple image together, but it takes a long time...
update:
I've managed to successfully export the whole area, the magic parameter is the: .setAnimationParameterEnabled(Panel.ANIM_BOUNDS_CLIPPING_XJAL, false)
it will force Anylogic to draw the whole area, and not just the visible area.
But it doesn't always work. I have to run the code, move around the area, zoom in/out and try again. At some point it gets really glitchy, probably because it starts to draw every thing, and then the code works. The problem is that i can't figure out exactly what to do to make it work...
java.awt.Component alPanel = getExperiment().getPresentation().getPanel();
getExperiment().getPresentation().getPanel().setAnimationParameterEnabled(Panel.ANIM_BOUNDS_CLIPPING_XJAL, false);
getExperiment().getPresentation().setMaximized(false);
getExperiment().getPresentation().setPanelSize(5000, 5000);
java.awt.image.BufferedImage imageExperiment = new java.awt.image.BufferedImage(
alPanel.getWidth(),
alPanel.getHeight(),
java.awt.image.BufferedImage.TYPE_INT_RGB
);
getExperiment().drawPresentation(getExperiment().getPresentation().getPanel(), imageExperiment.createGraphics(), false);
java.awt.Component component = getExperiment().getPresentation().getPanel();
// call the Component's paint method, using
// the Graphics object of the image.
component.paintAll( imageExperiment.getGraphics() ); // alternately use .printAll(..)
try {
// write the image as a PNG
javax.imageio.ImageIO.write(
imageExperiment,
"png",
new File("screenshotAnylogic.png"));
} catch(Exception e) {
e.printStackTrace();
}
Okay... so after a lot of experimentation, i found that the "magic parameter" wasn't as magic as i thought.
but this piece of code should be able to create a screenshot that extends the visible area:
public void capturePanel (ShapeGroup p, String fileName) {
Panel argPanel = p.getPresentable().getPresentation().getPanel();
BufferedImage capture = new BufferedImage(4000, 4000, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = capture.createGraphics();
g.setClip( -200, -200, 4000, 4000 );
p.draw( argPanel, g, null, true );
g.dispose();
try {
ImageIO.write(capture, "png", new File(fileName));
} catch (IOException ioe) {
System.out.println(ioe);
}
}
Well, afaik there is no built in method in Anylogic for that.You could try to use Java to realize that though. It is possible to get the Panel that contains the simulation via getExperiment().getPresentation().getPanel() and you can create an image from that. This is explained here for example and the code would look like this:
public static BufferedImage getScreenShot(Component component)
{
BufferedImage image = new BufferedImage(
component.getWidth(),
component.getHeight(),
BufferedImage.TYPE_INT_RGB
);
// call the Component's paint method, using
// the Graphics object of the image.
component.paint( image.getGraphics() ); // alternately use .printAll(..)
return image;
}
public static void saveComponentScreenshot(Component component)
{
try {
// write the image as a PNG
ImageIO.write(
getScreenShot(component),
"png",
new File("screenshot.png"));
} catch(Exception e) {
e.printStackTrace();
}
}
Unfortunately this does not give you the bigger viewport you probably want to have. Maybe the method public final void drawPresentation(Panel panel, java.awt.Graphics2D g, boolean publicOnly) that is available from the Experiment object returned from getExperiment() could help you to draw the simulation on a custom Panel with the wanted dimensions. Pretty hacky but it's all that I can come up with ^^
I have a problem to display a text at run time in my game for a second , so I want to know if its possible to add or remove a GUI label to the seen at run time ?
Do you mean something like this?
void OnGUI() {
if (textShouldBeShown) {
GUI.Label(new Rect(10f, 10f, 100f, 50f), "MyText");
}
}
GUI components get drawn on every frame. the OnGUI() function is just like the Update() function except that unlike the Update() function GUI components can be called in it.
You can think of OnGUI as a loop. It will call GUI components declared inside of it in order, then do it all over again every frame. So if you hook into this loop and block some components from being called at runtime, the very next frame those componants will not be rendered.
Here is a set of functions that can allow you to do this is a specified time:
private bool guiIsOn = true;
private void TurnOffGUIInSeconds(int seconds)
{
StartCoroutine(_TurnOffGUIInSeconds(seconds));
}
private IEnumerator _TurnOffGUIInSeconds(int seconds)
{
yield return new WaitForSeconds(seconds);
guiIsOn = false;
}
void OnGUI()
{
if(guiIsOn)
{
GUI.Label(new Rect(5,5,5,5), "Label text");
}
}
I am making an application based on Eclipse e4 framework. I was wondering how the minimal size of the application window can be controlled. There seems no properties can be defined in e4xmi file for this purpose.
Does anyone know how to do it?
I found a thread in Eclipse Community Forum (http://www.eclipse.org/forums/index.php/t/244875/) saying it can be achieved by creating my own renderer. How can I do that exactly?
Thank you very much :)
Assuming you are using the built-in SWT Renderers, you can also listen for the creation of your E4 MWindow elements and gain access to the underlying SWT Shell. In this example the listener is registered in an AddOn, which you can add to your e4xmi.
import javax.annotation.PostConstruct;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.swt.widgets.Shell;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
public class MinSizeAddon {
#PostConstruct
public void init(final IEventBroker eventBroker) {
EventHandler handler = new EventHandler() {
#Override
public void handleEvent(Event event) {
if (!UIEvents.isSET(event))
return;
Object objElement = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(objElement instanceof MWindow))
return;
MWindow windowModel = (MWindow)objElement;
Shell theShell = (Shell)windowModel.getWidget();
if (theShell == null)
return;
theShell.setMinimumSize(400, 300);
}
};
eventBroker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, handler);
}
}
Note, that this will be executed for any MWindow in your application, and there can be more of them (i.e. when an MPart is detached from the MPartStack into a seperate window). If you want to limit the execution to specific MWindows, I recommend to add a tag to the window in the e4xmi and check for this tag before setting the minimum size.
If anyone is still looking to do this in an e4 application and doesn't want to roll their own renderer, you can simply do the following in the post-construct of your part class:
#PostConstruct
public void postConstruct(Composite parent) {
parent.getShell().setMinimumSize(300, 300);
//...
}
The parent Composite passed in by the framework gives you access to the Shell, which lets you set the minimum size. This stops the application from being resized to less than the specified minimum size (in pixels).