I want to make my undecorated scene draggable. My root layout contain toolbar with controls and content. I gave id for toolbar and set controller for .fxml layout.
Then i do all steps like in Dragging an undecorated Stage in JavaFX
But i have null pointer, when try to call EffectUtilities.makeDraggable(stage, tool_bar);
Here is the code:
Main
public class UpdaterMain extends Application{
private Stage primaryStage;
private BorderPane rootLayout;
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
this.primaryStage.initStyle(StageStyle.UNDECORATED);
this.primaryStage.initStyle(StageStyle.TRANSPARENT);
initRootLayout();
showContentOverview();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(UpdaterMain.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
UpdaterMainController controller =
loader.getController();
controller.registerStage(primaryStage); <<--Here is NPE
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Shows main content
*/
public void showContentOverview() {
try {
// Load person overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(UpdaterMain.class.getResource("updater-layout.fxml"));
SplitPane contentOverview = loader.load();
// Set person overview into the center of root layout.
rootLayout.setCenter(contentOverview);
} catch (IOException e) {
e.printStackTrace();
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
Controller
import com.iminegination.utils.EffectUtilities;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ToolBar;
import javafx.stage.Stage;
public class UpdaterMainController {
#FXML
private ToolBar tool_bar;
public void registerStage(Stage stage) {
EffectUtilities.makeDraggable(stage, tool_bar); <<--Here is NPE (tool_bar is null, but why?)
}
public UpdaterMainController() {
}
}
layout.fxml
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="690.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.iminegination.updater.view.UpdaterMainController">
<top>
<ToolBar id="tool_bar" nodeOrientation="RIGHT_TO_LEFT" prefHeight="40.0" prefWidth="200.0">
<items>
<Button id="exitButton" mnemonicParsing="false" text="X" onAction="#click"/>
<Button mnemonicParsing="false" text="Settings" />
<Button mnemonicParsing="false" text="_" />
</items>
</ToolBar>
</top>
</BorderPane>
You need to define an fx:id attribute for your controls in FXML.
In your FXML you have:
<ToolBar id="tool_bar" . . .
You should have:
<ToolBar id="tool_bar" fx:id="tool_bar" . . .
id defines the CSS id.
fx:id defines the link between the FXML and the controller variable names.
Related
I'm playing with the COOL xamarin shell, but I didn't found a way to change icon of the selected tab.
<TabBar Route="sections">
<Tab Title="home">
<Tab.Icon>
<FontImageSource FontFamily="{StaticResource AppIcons}" Glyph="{x:Static framework:Icons.HomePage}" />
</Tab.Icon>
<ShellContent ContentTemplate="{DataTemplate home:HomePage}" Route="home" />
</Tab>
The goal is to use Icons.HomePageFilled instead of Icons.HomePage for this tab only when it's selected. Same logic should apply to other tabs.
I think I got lost in the solutions found on the web. They talk about Custom renderers(ShellTabLayoutAppearanceTracker), Visual states, effects etc ...
But I do not know if it is feasible and what is the ideal solution
You need to use custom renderer of shell to customize the tabbar selected icon on each platform.
In iOS, override the CreateTabBarAppearanceTracker method:
[assembly: ExportRenderer(typeof(AppShell), typeof(MyShellRenderer))]
namespace App30.iOS
{
public class MyShellRenderer : ShellRenderer
{
protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
{
var renderer = base.CreateShellSectionRenderer(shellSection);
if (renderer != null)
{
}
return renderer;
}
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new CustomTabbarAppearance();
}
}
public class CustomTabbarAppearance : IShellTabBarAppearanceTracker
{
public void Dispose()
{
}
public void ResetAppearance(UITabBarController controller)
{
}
public void SetAppearance(UITabBarController controller, ShellAppearance appearance)
{
UITabBar myTabBar = controller.TabBar;
if (myTabBar.Items != null)
{
UITabBarItem itemOne = myTabBar.Items[0];
itemOne.Image = UIImage.FromBundle("tab_about.png");
itemOne.SelectedImage = UIImage.FromBundle("tab_feed.png");
UITabBarItem itemTwo = myTabBar.Items[1];
itemTwo.Image = UIImage.FromBundle("tab_feed.png");
itemTwo.SelectedImage = UIImage.FromBundle("tab_about.png");
//The same logic if you have itemThree, itemFour....
}
}
public void UpdateLayout(UITabBarController controller)
{
}
}
}
In Android, override the CreateBottomNavViewAppearanceTracker method:
[assembly: ExportRenderer(typeof(AppShell), typeof(MyShellRenderer))]
namespace App30.Droid
{
public class MyShellRenderer : ShellRenderer
{
public MyShellRenderer(Context context) : base(context)
{
}
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
{
return new CustomBottomNavAppearance();
}
}
public class CustomBottomNavAppearance : IShellBottomNavViewAppearanceTracker
{
public void Dispose()
{
}
public void ResetAppearance(BottomNavigationView bottomView)
{
}
public void SetAppearance(BottomNavigationView bottomView, ShellAppearance appearance)
{
IMenu myMenu = bottomView.Menu;
IMenuItem myItemOne = myMenu.GetItem(0);
if (myItemOne.IsChecked)
{
myItemOne.SetIcon(Resource.Drawable.tab_about);
}
else
{
myItemOne.SetIcon(Resource.Drawable.tab_feed);
}
//The same logic if you have myItemTwo, myItemThree....
}
}
}
I uploaded a sample project here and you can check it.
I am trying develop a xamarin app which has tabbed pages.
I have 3 main tabs.Each page viewmodel contructor has 3-5 Api calls.So its taking more time(20s) to load my app(for opening).
mainpage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Myapplication.Views.MenuPage"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:views="clr-namespace:Dyocense.Views"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.IsSwipePagingEnabled="False"
>
<views:A Title="A" Icon="dsjsdsd_18dp.png" ></views:A>
<views:B Title="B" Icon="askjasa.png"></views:B>
<views:C Title="C" Icon="abc.png"></views:C>
<views:D Title="D" Icon="abc.png"></views:D>
</TabbedPage>
How to load only first tab(A) detail page on app loading and rest of the pages on tab changing.
A solution is to make the heavy pages load their content in a lazy manner, only when their tab becomes selected. This way, since these pages are now empty when TabbedPage is created, navigating to the TabbedPage suddenly becomes very fast!
1.create a behavior for the TabbedPage page, called ActivePageTabbedPageBehavior.
class ActivePageTabbedPageBehavior : Behavior<TabbedPage>
{
protected override void OnAttachedTo(TabbedPage tabbedPage)
{
base.OnAttachedTo(tabbedPage);
tabbedPage.CurrentPageChanged += OnTabbedPageCurrentPageChanged;
}
protected override void OnDetachingFrom(TabbedPage tabbedPage)
{
base.OnDetachingFrom(tabbedPage);
tabbedPage.CurrentPageChanged -= OnTabbedPageCurrentPageChanged;
}
private void OnTabbedPageCurrentPageChanged(object sender, EventArgs e)
{
var tabbedPage = (TabbedPage)sender;
// Deactivate previously selected page
IActiveAware prevActiveAwarePage = tabbedPage.Children.OfType<IActiveAware>()
.FirstOrDefault(c => c.IsActive && tabbedPage.CurrentPage != c);
if (prevActiveAwarePage != null)
{
prevActiveAwarePage.IsActive = false;
}
// Activate selected page
if (tabbedPage.CurrentPage is IActiveAware activeAwarePage)
{
activeAwarePage.IsActive = true;
}
}
}
2.define IActiveAware interface
interface IActiveAware
{
bool IsActive { get; set; }
event EventHandler IsActiveChanged;
}
3.create a base generic abstract class called LoadContentOnActivateBehavior
abstract class LoadContentOnActivateBehavior<TActivateAwareElement> : Behavior<TActivateAwareElement>
where TActivateAwareElement : VisualElement
{
public DataTemplate ContentTemplate { get; set; }
protected override void OnAttachedTo(TActivateAwareElement element)
{
base.OnAttachedTo(element);
(element as IActiveAware).IsActiveChanged += OnIsActiveChanged;
}
protected override void OnDetachingFrom(TActivateAwareElement element)
{
(element as IActiveAware).IsActiveChanged -= OnIsActiveChanged;
base.OnDetachingFrom(element);
}
void OnIsActiveChanged(object sender, EventArgs e)
{
var element = (TActivateAwareElement)sender;
element.Behaviors.Remove(this);
SetContent(element, (View)ContentTemplate.CreateContent());
}
protected abstract void SetContent(TActivateAwareElement element, View contentView);
}
4.the specialized LazyContentPageBehavior
class LazyContentPageBehavior : LoadContentOnActivateBehavior<ContentView>
{
protected override void SetContent(ContentView element, View contentView)
{
element.Content = contentView;
}
}
then we can use in xaml like this:
<TabbedPage>
<TabbedPage.Behaviors>
<local:ActivePageTabbedPageBehavior />
</TabbedPage.Behaviors>
<ContentPage Title="First tab">
<Label Text="First tab layout" />
</ContentPage>
<local:LazyLoadedContentPage Title="Second tab">
<ContentPage.Behaviors>
<local:LazyContentPageBehavior ContentTemplate="{StaticResource ContentTemplate}" />
</ContentPage.Behaviors>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ContentTemplate">
<!-- Complex and slow to render layout -->
<local:SlowContentView />
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
</local:LazyLoadedContentPage>
</TabbedPage>
we moved the ContentPage complex layout to become a DataTemplate.
Here's the custom LazyLoadedContentPage page which is activation aware:
class LazyLoadedContentPage : ContentPage, IActiveAware
{
public event EventHandler IsActiveChanged;
bool _isActive;
public bool IsActive
{
get => _isActive;
set
{
if (_isActive != value)
{
_isActive = value;
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
SlowContentView do some complex things
public partial class SlowContentView : ContentView
{
public SlowContentView()
{
InitializeComponent();
// Simulating a complex view
...
}
}
you could refer to the link
As a workaround I created a new class extending the Xamarin.Forms.TabbedPage and I send a message every time one of the tabs is clicked (or in general is diplayed)
public enum TabbedPages
{
MyPage1 = 0,
MyPage2 = 1,
MyPage3 = 2,
}
public class BottomBarPage : Xamarin.Forms.TabbedPage
{
protected override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
var newCurrentPage = (TabbedPages)Children.IndexOf(CurrentPage);
MessagingCenter.Send<Xamarin.Forms.TabbedPage>(this, newCurrentPage.ToString("g"));
}
}
and then on the view models used for each page loaded when clicking on the tab I subscribe to the message and call my APIs
public class MyPage2ViewModel
{
public MyPage2ViewModel()
{
MessagingCenter.Subscribe<TabbedPage>(this, TabbedPages.MyPage2 .ToString("g"), async (obj) =>
{
//API call
});
}
}
This is my main class
package FSM;
import java.io.IOException;
import FSM.view.PersonEditDetailsControler;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import FSM.model.Person;
import FSM.view.PersonOverviewController;
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private ObservableList<Person> personData= FXCollections.observableArrayList();
public Main() {
// Add some sample data
System.out.println("1 prit");
personData.add(new Person("Hans", "Muster"));
personData.add(new Person("Ruth", "Mueller"));
personData.add(new Person("Heinz", "Kurz"));
personData.add(new Person("Cornelia", "Meier"));
personData.add(new Person("Werner", "Meyer"));
personData.add(new Person("Lydia", "Kunz"));
personData.add(new Person("Anna", "Best"));
personData.add(new Person("Stefan", "Meier"));
personData.add(new Person("Martin", "Mueller"));
}
public ObservableList<Person> getPersonData() {
return personData;
}
#Override
public void start(Stage primaryStage) throws Exception{
System.out.println("2 print");
this.primaryStage = primaryStage;
primaryStage.setTitle("AddressApp");
initRootLayout();
showPersonOverview();
}
public void initRootLayout() {
try {
// Load root layout from fxml file.
System.out.println("rootLayout");
FXMLLoader loader = new FXMLLoader();
System.out.println("geting rootlayout");
loader.setLocation(Main.class.getResource("/FSM/view/RootLayout.fxml"));
System.out.println("setting borderPane");
rootLayout = (BorderPane) loader.load();
System.out.println("loaded");
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
System.out.println("new scene 1");
primaryStage.setScene(scene);
System.out.println("set scene");
primaryStage.show();
System.out.println("rootLayout End 1");
} catch (IOException e) {
System.out.println("rootLayout Exception");
e.printStackTrace();
}
}
public void showPersonOverview() {
try {
System.out.println("3 Print");
// Load person overview.
FXMLLoader loader = new FXMLLoader();
System.out.println("getting Resouurce");
loader.setLocation(Main.class.getResource("/FSM/view/PersonOverview.fxml"));
System.out.println("got Resouurce");
AnchorPane personOverview = (AnchorPane) loader.load();
System.out.println("loading Anchor");
// Set person overview into the center of root layout.
rootLayout.setCenter(personOverview);
System.out.println("setting person overview");
PersonOverviewController controller = loader.getController();
controller.setMain(this);
} catch (IOException e) {
e.printStackTrace();
System.out.println("3 Print exception");
}
}
public boolean showPersonEditDialog(Person person){
try {
System.out.println("4 print");
FXMLLoader loader=new FXMLLoader();
loader.setLocation(Main.class.getResource("/FSM/view/PersonEditDetails.fxml"));
AnchorPane anchorPane=(AnchorPane)loader.load();
rootLayout.setCenter(anchorPane);
Stage dialogStage = new Stage();
dialogStage.setTitle("Edit Person");
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(anchorPane);
dialogStage.setScene(scene);
PersonEditDetailsControler controllerr = loader.getController();
controllerr.setDialogStage(dialogStage);
controllerr.setPerson(person);
dialogStage.showAndWait();
return controllerr.isOKClicked();
}catch (Exception e){
e.printStackTrace();
System.out.println("4th print");
return false;
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
And this is PersonOverViewController class
package FSM.view;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import FSM.model.Person;
import FSM.Main;
import javafx.scene.web.WebEvent;
import java.lang.Object.*;
/**
* Created by mfaseem on 6/9/2015.
*/
public class PersonOverviewController {
#FXML
private TableView<Person> PersonTable;
#FXML
private TableColumn<Person,String> fnameColumn;
#FXML
private TableColumn<Person, String> lnameColumn;
#FXML
private Label fnameLabel;
#FXML
private Label lnameLabel;
#FXML
private Label streetLabel;
#FXML
private Label postelCodeLabel;
#FXML
private Label CityLabel;
#FXML
private Label dobLabel;
private Main main;
public PersonOverviewController(){
}
#FXML
private void initialize(){
fnameColumn.setCellValueFactory(CellData -> CellData.getValue().fnameProperties());
lnameColumn.setCellValueFactory(CellData -> CellData.getValue().lnameProperties());
showPersonDetails(null);
PersonTable.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) ->showPersonDetails(newValue));
}
#FXML
private void deleteHandler(){
int selectedIndex=PersonTable.getSelectionModel().getSelectedIndex();
if(selectedIndex>=0){
PersonTable.getItems().remove(selectedIndex);
}else {
// ALERT alert = new Alert(AlertType.WARNING);
//alert.initOwner(mainApp.getPrimaryStage());
// alert.setTitle("No Selection");
// alert.setHeaderText("No Person Selected");
// alert.setContentText("Please select a person in the table.");
// alert.showAndWait();
}
}
#FXML
private void handleNewPerson() {
Person tempPerson = new Person();
boolean okClicked = main.showPersonEditDialog(tempPerson);
if (okClicked) {
main.getPersonData().add(tempPerson);
}
}
#FXML
private void handleEditPerson() {
Person selectedPerson = PersonTable.getSelectionModel().getSelectedItem();
if (selectedPerson != null) {
boolean okClicked = main.showPersonEditDialog(selectedPerson);
if (okClicked) {
showPersonDetails(selectedPerson);
}
} else {
/* Nothing selected.
Alert alert = new Alert(AlertType.WARNING);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("No Selection");
alert.setHeaderText("No Person Selected");
alert.setContentText("Please select a person in the table.");
alert.showAndWait();
*/
}
}
public void setMain(Main main){
this.main=main;
PersonTable.setItems(main.getPersonData());
}
private void showPersonDetails(Person person){
if(person !=null){
fnameLabel.setText(person.getFname());
lnameLabel.setText(person.getLname());
streetLabel.setText(person.getStreet());
CityLabel.setText(person.getCity());
dobLabel.setText(person.getBirthDate().toString());
postelCodeLabel.setText(String.valueOf(person.getPostalCode()));
}else{
fnameLabel.setText("");
lnameLabel.setText("");
streetLabel.setText("");
CityLabel.setText("");
dobLabel.setText("");
postelCodeLabel.setText("");
}
}
}
And the out put is
Device "Intel(R) Q45/Q43 Express Chipset" (\\.\DISPLAY1) initialization failed :
WARNING: bad driver version detected, device disabled. Please update your driver to at least version 8.15.10.2302
1 prit
2 print
rootLayout
geting rootlayout
setting borderPane
loaded
new scene 1
set scene
javafx.fxml.LoadException: /C:/Users/mfaseem/IdeaProjects/AddressApp/out/production/AddressApp/FSM/view/PersonOverview.fxml:7
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:104)
Can any one help me thanks in advance
I have been trying to figure out how to deal with a FXML file in another FXML file. But I have an exception. :(
This is my inner FXML (NewInside.fxml in view package):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="305.0" prefWidth="360.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="controller.NewInsideController">
<children>
<Button fx:id="newBtn" layoutX="30.0" layoutY="202.0" mnemonicParsing="false" onAction="#btnClick" text="Button" />
<TextField fx:id="newTxt" layoutX="30.0" layoutY="134.0" prefHeight="25.0" prefWidth="280.0" />
<Label fx:id="newLbl" layoutX="30.0" layoutY="62.0" prefHeight="17.0" prefWidth="280.0" />
</children>
</AnchorPane>
This is its controller (NewInsideController.java in controller package):
package controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class NewInsideController implements Initializable{
#FXML public static Label newLbl;
#FXML public static TextField newTxt;
#FXML public static Button newBtn;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#FXML
private void btnClick(ActionEvent e){
System.out.println("Button is clicked!");
newLbl.setText(newTxt.getText());
}
}
And this is outer FXML (New.fxml in view package):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="380.0" prefWidth="529.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="controller.NewController">
<children>
<fx:include source="NewInside.fxml" />
</children>
</AnchorPane>
This is its controller (NewController.java in controller package):
package controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
public class NewController implements Initializable {
/*#FXML private Label newLbl;
#FXML private Button newBtn;
#FXML private TextField newTxt;
*/
#Override
public void initialize(URL location, ResourceBundle resources) {
}
/*#FXML
public void btnClick(ActionEvent e){
newLbl.setText(newTxt.getText());
}*/
}
Finally, this is the Main.java in application package:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/view/New.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
When I clicked the button, it gives me very long exception:
"Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException....
.....
Caused by: java.lang.NullPointerException
at controller.NewInsideController.btnClick(NewInsideController.java:27)
... 57 more"
Please help me! :(
As #Inge suggests, using the static field is not the right way to do it. Also, instead of public, you should use private. If you need to expose your controls, use their properties.
You can read why here:
You should not use a static field here
... don't use static fields
Just change this in your NewInsideController:
#FXML private Label newLbl;
#FXML private TextField newTxt;
#FXML private Button newBtn;
EDIT
If you want to have access to your controls from other classes, instead of adding getters/setters to expose directly the controls, it is better just exposing their properties.
For instance, to have access to the text of these controls you could add:
public StringProperty newLblText() {
return newLbl.textProperty();
}
public StringProperty newTxtText() {
return newTxt.textProperty();
}
public StringProperty newBtnText() {
return newBtn.textProperty();
}
This will allow you binding (or listening to changes), getting/setting the text property from any of them from the outside of your controller.
To get a valid instance of NewInsideController from NewController, follow this link. First modify New.fxml:
<fx:include fx:id="newInside" source="NewInside.fxml" />
and now you can get an instance, and add some listeners with those properties:
public class NewController implements Initializable {
#FXML
private Parent newInside;
#FXML
private NewInsideController newInsideController;
#Override
public void initialize(URL url, ResourceBundle rb) {
newInsideController.newBtnText().addListener(
(obs,s,s1)->System.out.println("nweBtn Text;" +s1));
if(newInsideController.newLblText().get().isEmpty()){
newInsideController.newLblText().set("Text for the textfield");
}
newInsideController.newTxtText().addListener(
(obs,s,s1)->System.out.println("s1 "+s1));
}
}
I'm using a Slider in my javaFX project and I have a Label that updates when I move the slider.
I want the Label to update whilst I'm dragging the Slider and not only when the drag is dropped.
This is my code:
betSlider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> source, Boolean oldValue, Boolean newValue) {
betLabel.textProperty().setValue(String.valueOf((int)betSlider.getValue()));
} });
You just need to change the valueChangingProperty() to valueProperty() and TADA, it works as you want !
A small sample is attached here :
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Demo extends Application {
#Override
public void start(Stage primaryStage) {
// Add a scene
VBox root = new VBox();
Scene scene = new Scene(root, 500, 200);
final Label betLabel = new Label("sdsd");
final Slider betSlider = new Slider();
betSlider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(
ObservableValue<? extends Number> observableValue,
Number oldValue,
Number newValue) {
betLabel.textProperty().setValue(
String.valueOf(newValue.intValue());
}
}
});
root.getChildren().addAll(betSlider, betLabel);
betLabel.textProperty().setValue("abc");
// show the stage
primaryStage.setTitle("Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Bind the label's textProperty to the slider's valueProperty.
A format conversion is required in the binding to make it work.
Either Itachi's valueProperty() ChangeListener or a binding will work.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Slide extends Application {
#Override public void start(Stage stage) {
Label label = new Label();
Slider slider = new Slider(1, 11, 5);
label.textProperty().bind(
Bindings.format(
"%.2f",
slider.valueProperty()
)
);
VBox layout = new VBox(10, label, slider);
layout.setStyle("-fx-padding: 10px; -fx-alignment: baseline-right");
stage.setScene(new Scene(layout));
stage.setTitle("Goes to");
stage.show();
}
public static void main(String[] args) { launch(args); }
}
And if you want to do completely in in FXML, you can do this:
<TextField prefWidth="50" text="${speedSlider.value}"/>
<Slider fx:id="speedSlider" orientation="HORIZONTAL" prefWidth="300"
min="60" max="100000" blockIncrement="100"/>
Adding an alternative that seems simpler and easier to me:
Given a slider named slMySlider and a label named lblMySlider
Add a MouseEvent.MOUSE_DRAGGED event handler to the slider and have it call a helper method:
slMySlider.addEventHandler(MouseEvent.MOUSE_DRAGGED, this::changeLabelHandler);
Have the helper method change the label's text:
private void changeLabelHandler(MouseEvent e) {
lblMySlider.setText("Value: " + String.format("%1.2f", slMySlider.getValue()));
}
slider.valueProperty().addListener((observable, oldValue, newValue) ->
label.setText("sliderNameLabel: " + newValue));
If you have a slider in JavaFX 8, you could do this:
slider().addListener(e -> {
// Your code here could be anything.
});