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).
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 was coding a very simple program that lets you move around a circle, with also a rectangle in the stage. I wanted to make the circle get in front of the rectangle while you are dragging it, but when you released the mouse, the circle would be sent back.
I don't know how to set a public variable using the getChildIndex method. I don't really care about the rest of the code. I'm mainly interested in how can I make the getChildIndex method work with a public variable.
package code
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Sprite;
public class Main extends MovieClip
{
public var myCircleIndex:int = getChildIndex(myCircle);
public function Main()
{
myCircle.addEventListener(MouseEvent.MOUSE_DOWN, mouseClicking);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
}
public function mouseClicking(e:MouseEvent): void
{
myCircle.startDrag();
setChildIndex(myCircle, numChildren-1);
}
public function mouseReleased(e:MouseEvent): void
{
myCircle.stopDrag();
setChildIndex(myCircle, myCircleIndex);
}
}
}
I'm using an instance ("myCircle") that I created directly in the stage as a movie clip.
The problem is in the public var I set at the beginning, it doesn't let me get the child index of myCircle, but if I put the same line inside a function, it works.
I know I could directly put the index number of myCircle in the last line (and erasing the public var myCircleIndex), but I figured out that there would be a way of using the getChildIndex for a public var in a class.
How do you use getChildIndex in a public variable inside a class?
The reason it doesn't work, is because your timeline objects don't yet exist when the line public var myCircleIndex:int runs.
You shouldn't try and access non-primitive objects in your class level variable declarations for this very reason, as nothing else in the class is available yet when those vars are created.
Here is how you can refactor this (see the code comments):
public class Main extends MovieClip
{
public var myCircleIndex:int; //just create the reference here, don't assign it
public var myCircle:flash.display.DisplayObject; //this line is just for better compile time checking and code completion, completely optional
public function Main()
{
//wait for all the display stuff to be created before trying to access it. The constructor function can run before timeline stuff is created, so it's not safe to reference stage or timeline objects here.
if(!stage){
this.addEventListener(Event.ADDED_TO_STAGE, timelineCreated);
}else {
timelineCreated(null);
}
}
private function timelineCreated(e:Event):void {
//now that we're certain the timeline stuff has been created, we can reference timeline objects and stage:
//store the initial z-index of myCircle
myCircleIndex = getChildIndex(myCircle);
//the rest of your code that was in the construction -Main()- before
myCircle.addEventListener(MouseEvent.MOUSE_DOWN, mouseClicking);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
}
//no change to any of the following stuff
public function mouseClicking(e:MouseEvent): void
{
myCircle.startDrag();
setChildIndex(myCircle, numChildren-1);
}
public function mouseReleased(e:MouseEvent): void
{
myCircle.stopDrag();
setChildIndex(myCircle, myCircleIndex);
}
}
All you need to do to put the circle behind the square is on release do addChild(myRectangle) or addChildAt(myCircle, 0);
You are overcomplicating things by trying to track a variable in my opinion. Let flash sort it out behind the scenes.
If you want a little more finesse and want to just put the circle directly behind the square (if there were 100 layers and the square is at level 12, but you aren't sure which level the square is at) you could do
addChildAt(myCircle, getChildIndex(myRectangle)-1);
note
setChildIndex(myCircle, numChildren-1);
That's fine to do it that way. The more common way to do this is just
addChild(myCircle);
It does the exact same thing. Many people are confused by this thinking this would add a new myCircle but it just brings it to the front if it's already in the display list, and if it's not in the display list, it adds it to the display list at the top z-order (numChildren-1).
Why MenuBar changes the background color of the scene in this code sample? It should be blue but it is white.
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.setFill(Color.rgb(0, 0, 255));
primaryStage.setScene(scene);
primaryStage.show();
MenuBar menuBar = new MenuBar();
}
public static void main(String[] args) {
launch(args);
}
}
The white background you are seeing is the background of the BorderPane. This background color is set when the default stylesheet is loaded.
The reason that you only see this when the MenuBar is created is that CSS is only applied (unless you force it) when the first control is created. This is by design, to prevent the overhead of loading stylesheets and applying CSS for applications that don't need them (e.g. for games or simulations that manage all their own graphics). Since all controls are styled by CSS, just instantiating a control forces CSS to be applied.
The fix is to make the background of the BorderPane transparent.
Either
root.setStyle("-fx-background-color: transparent;");
or
root.setBackground(Background.EMPTY);
Of course, since you have to set the background of the root pane, you may as well set that to blue instead of setting the fill of the Scene:
BorderPane root = new BorderPane();
root.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
Scene scene = new Scene(root,400,400);
Or, you can use an external style sheet:
.root {
-fx-background-color: blue ;
}
Also see this related post and this OTN discussion.
I have created a folder called anim inside res folder. I have put 9 consequtive images in a folder called drawable inside res folder. Now I have created this:
public class AndroidAnimationActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.about_screen);
ImageView myAnimation = (ImageView)findViewById(R.id.myanimation);
final AnimationDrawable myAnimationDrawable= (AnimationDrawable)myAnimation.getDrawable();
myAnimation.post(new Runnable(){
public void run() {
myAnimationDrawable.start();
}
});
}
}
As you see I am trying to display this animation on a page called about_screen. It only shows the first frame and the rest of the frames are not shown (as animation). I have seen several people having similar problem like me but not exactly the same. I hope someone can help me with this. Please be specific. I am a new android learner. Thanks
Even I faced this problem, and the solution is simple.
The problem is, you are calling myAnimationDrawable.start() inside the onCreate() function.
You have two possible alternatives...
First one, make the animation interactive, so that you can call myAnimationDrawable.start()
inside some onClick() function.
Second option is to call myAnimationDrawable.start() inside View.OnFocusChangeListener(). In this case you don't have to make it interactive.
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).