Problems with data transmission in javafx and reuse variables - javafx

My program is structured package as follows
-Browser.fxml
-Elements.fxml
+BrowserController : Browser transmit values url to Elements
#FXML
void txtURL(ActionEvent event) {
Pane pnLoad = fxmlLoader.load(getClass().getResource("Elements.fxml").openStream());
FunctionController controller = (FunctionController) fxmlLoader.getController();
controller.viewURL(txtURL.getText());
}
+ElementsController :,
-With reading after I can only use the value url once for function viewURL
#FXML
public void viewURL(String url) {
System.out.println(url);
}
+How can I use the url again?
#FXML
void btnReviewUrl(ActionEvent event) {
System.out.println(url);
}
Please help me!

You can create a Static variable in your class and assign the url value to that variable to ve used again anf across classes
public static String urlValue;
#FXML
public void viewURL(String url) {
System.out.println(url);
urlValue = url;
}

Related

Error using sub-string method with textfield

We are have an error when we try to obtain the first few character of a string
First we tried to remove the last two offending characters
That produced the same error we are seeing when we try to obtain the first few characters
The On Key Typed method is attached to a textfield when MAX character are exceeded a custom alert
is fired. We have looked at many ways to remove or get sub-strings in various SO questions before posting
The string entered will never be the same hence we do not know the specific character to replace
Here is the code and a screen shot of the ERROR notice that the "o" in front of the original text
The string we are entering is "This is a test to see how many yo"
We are trying to obtain only the "This is a test to see how many"
The System.out.println(strNew) is exactly that but when strNew is add to the textfield the "o" shows up
Our question is how to prevent this ?
OR What is the cause of the odd text that is palaced in the textfield?
Here is the Minimal Code to test
public class Atest extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
The Controller
public class testController implements Initializable {
#FXML
TextField txtDesc;
#FXML
private void handleButtonAction(ActionEvent event) {
txtDesc.setText("Thanks");
}
#FXML
private void descLEN(){
txtDesc.setOnKeyTyped(event ->{
int maxCharacters = 10;
if(txtDesc.getText().length() > maxCharacters)
event.consume();
});
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
We have no idea how to post FXML Code all you need is a TextField
with the id txtDesc and set the OnKeyTyped to descLEN
Because you are consumed with the Custom Alert you may not like our answer
I call this We Hear You Knocking but You Can NOT Come In Your event is consume
OK the answer suggested by Sedrick is great but we have only used 3 Lines of Code
No Custom Alert just 30 Character and a bunch of consuming ha ha
#FXML
private void onType(){
txtDescription.setOnKeyTyped(event ->{
int maxCharacters = 30;
if(txtDescription.getText().length() > maxCharacters)event.consume();
});
All right 7 lines if you count the FXML tab and the declaration and formatting

Pass Variable to another Controller

Hello I need to pass The User and Pass Values to another Controller:
like this AdminController ->UserController.
In my code I have This in AdminController:
private TextField fusuario;
#FXML
private PasswordField fcontrasena;
String a;
String b;
public void captura() {
a=fusuario.getText().toString();
System.out.println("el usuario es x:"+a);
b=fcontrasena.getText().toString();
System.out.println("la contraseƱa es x:"+b);
}
public String setFusuario(String a) {
this.fusuario.setText(a);
return a;
}
public String setFcontrasena(String b) {
this.fcontrasena.setText(b);
return b;
}
This is in my UserController:
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane =(Parent) carga.load();
AdminScreenController control = carga.<AdminScreenController>getController();
control.deshabilitarespuesta();
Scene scene = new Scene(StackPane);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
administrador.setScene(scene);
administrador.setTitle("AdminScreen");
Stage userstage=(Stage)comentarios.getScene().getWindow();
userstage.hide();
administrador.show();
How i Pass this Values, some help or orientation?
This is easy you need to declare a static variable like this in the FIRST Controller
static String alertTYPE;
Then in our ERROR checking code we give alertTYPE a value
if(txtAmount.getLength() == 0){
alertTYPE = "1";
customAlert();
txtAmount.requestFocus();
return;
}
Now we call customAlert() method still in the same Controller class
Her is the customAlert method code
public void customAlert() throws IOException{
// This method displays the MODAL Alert alert.fxml and it is controlled by AlertController
// =========================================================================================
alertPane = FXMLLoader.load(getClass().getResource("alert.fxml"));// pane you are GOING TO
//Scene Sscene = new Scene(merrorPane, 600, 400);
// NO NEED TO RE-SIZE but this is code to change size
Scene Mscene = new Scene(alertPane);
Mstage = new Stage();
Mstage.initStyle(StageStyle.UNDECORATED);
Mstage.setResizable(false);
Mstage.initModality(Modality.APPLICATION_MODAL);
Mstage.setScene(Mscene);
Mstage.showAndWait();
}
Here in the AlertController we make use of the alertTYPE value
#Override
public void initialize(URL url, ResourceBundle rb) {
if(alertTYPE.equals("1")){
lblMessage.setText("Enter "+type+" Amount");
}else if(alertTYPE.equals("2")){
You need to be sure the Controller you are going to imports the static variable alertTYPE like this
import static checkbook.CBManagerController.alertTYPE;
This was a long way around but we hope you get the idea
One word of caution once static variables are declared and given a value that value is retained until a new value is given to the variable or you set it to nothing like this for a String alertTYPE = ""; With great power comes great responsibility ha ha

Javafx pass parameter and values from one controller to another

I am new to JavaFx and hence I cannot find a solution to solve my problem
Suppose I have following application structure :
- views
- first.fxml -> this has a button called btnSend and a textfield called txtEnter
- second.fxml -> this has a textarea called txtView
- Controller
- FirstController -> controller for First
- SecondController -> controller for second
- Modal
- AppModal -> here I have a getter and a setter method ,
as getText() and setText(String text)
- App
- Main.java -> This one used FXMLLoader to load first.fxml and second.fxml together.
What is the optimal/best way to display the text in SecondController passing it from FirstController. I mean, I enter a text in txtEnter and press the button btnSend and after pressing the button I want the text to be displayed in txtView which is using another controller.
I have read a lot about the observers pattern and JavaFX properties can be used to solve this, but unfortunately I am unable to implement a working solution.
I would be humbly thankful if you experts can help me in this. I know its not correct but can anyone please give me a working solution for the above project structure.
Thanks in advance.
Use an observable StringProperty in the model:
public class AppModel {
private final StringProperty text = new SimpleStringProperty();
public StringProperty textProperty() {
return text ;
}
public final String getText() {
return textProperty().get();
}
public final void setText(String text) {
textProperty().set(text);
}
}
Make your controllers have access to the model:
public class FirstController {
private final AppModel model ;
#FXML
private TextField textEnter ;
public FirstController(AppModel model) {
this.model = model ;
}
// action event handler for button:
#FXML
private void sendText() {
model.setText(textEnter.getText());
}
}
and
public class SecondController {
private final AppModel model ;
#FXML
private TextArea txtView ;
public SecondController(AppModel model) {
this.model = model ;
}
public void initialize() {
// update text area if text in model changes:
model.textProperty().addListener((obs, oldText, newText) ->
txtView.setText(newText));
}
}
The slightly tricky part now is that the controllers don't have a no-arg constructor, which means the default mechanism for the FXMLLoader to create them won't work. The easiest way is to set them manually. Remove both the <fx:controller> attributes from the FXML files, and then in your Main class do
AppModel model = new AppModel();
FXMLLoader firstLoader = new FXMLLoader(getClass().getResource("first.fxml"));
firstLoader.setController(new FirstController(model));
Parent firstUI = firstLoader.load();
FXMLLoader secondLoader = new FXMLLoader(getClass().getResource("second.fxml"));
secondLoader.setController(new SecondController(model));
Parent secondUI = secondLoader.load();
If you prefer to keep the <fx:controller> attributes in the FXML files, you can use a controllerFactory instead, which essentially instructs the FXMLLoader as to how to create a controller:
AppModel model = new AppModel();
Callback<Class<?>, Object> controllerFactory = type -> {
if (type == FirstController.class) {
return new FirstController(model);
} else if (type == SecondController.class) {
return new SecondController(model);
} else {
try {
return type.newInstance() ; // default behavior - invoke no-arg construtor
} catch (Exception exc) {
System.err.println("Could not create controller for "+type.getName());
throw new RuntimeException(exc);
}
}
};
FXMLLoader firstLoader = new FXMLLoader(getClass().getResource("first.fxml"));
firstLoader.setControllerFactory(controllerFactory);
Parent firstUI = firstLoader.load();
FXMLLoader secondLoader = new FXMLLoader(getClass().getResource("second.fxml"));
secondLoader.setControllerFactory(controllerFactory);
Parent secondUI = secondLoader.load();
You can make the controller factory even more flexible by using (more) reflection; basically you can implement the logic "if the controller type has a constructor taking an AppModel, call that constructor, otherwise call the no-arg constructor".
If you are creating a large application which needs to do a lot of this, then you might consider using afterburner.fx, which is a framework that essentially allows you to inject the model into the controllers using annotations.

Test case for fragment in android

In my application, I have multiple fragments on a single activity. Now I want to write a test case to check if these fragments are loading properly. To begin with, I passed some touch event to scroll to a particular fragment and then I am trying to fetch the name of this fragment. Below is my code for the test case:-
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity>
{
MainActivity mMainActivity;
ActionBar tactionbar;
Fragment tFragment;
public static final int TEST_POSITION = 2;
private static String mSelection ;
private int mPos = 0;
public MainActivityTest()
{
super(MainActivity.class);
}
protected void setUp() throws Exception
{
super.setUp();
mMainActivity = (MainActivity) getActivity();
tactionbar = mfoneclay.getActionBar();
}
public void testPreConditions()
{
assertNotNull(mMainActivity);
assertNotNull(tactionbar);
}
public void testFragmentUI()
{
mMainActivity.runOnUiThread(
new Runnable(){
public void run()
{
mMainActivity.getCurrentFocus();
}
});
for (int i = 1; i <= TEST_POSITION; i++)
{
this.sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
mPos = tactionbar.getSelectedNavigationIndex();
}
this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
mSelection = (String)tactionbar.getTabAt(mPos).getText();
String resultText = "Exclusive";
assertEquals(resultText,mSelection);
}
}
Here, "Exclusive" is the name of one of my tab to which I am navigating to via the touch event. Now, while running the test case, I can see that it is properly navigating to the "Exclusive" fragment, but the result shows the value of the msection variable as the name of the activity and not the fragments name. What am I doing wrong?
Got the solution. It was so stupid of me to use the wrong components to fetch the fragment. It turns out that I have to use "ViewPager" to fetch the fragments.

AspectJ capture button clicked

I want to know whether how to capture the button clicked with AspectJ and get its parameter (eg. button name). I think for having more generalized capturing with AspectJ, it shoudl be used MouseListener so it can capture other UI elements in general!
Example:
In a GUI example I have defined 2 buttons that take some actions
public JButton btn1 = new JButton("Test1");
public JButton btn2 = new JButton("Test2");
btn1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//take some actions
}
}
btn2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//take some actions
}
}
How to capture these buttons with AspectJ, and get their parameters (eg. name)?
It is possible. I have provided two examples. The first that prints out for every JButton that has an ActionListener. The other example only prints out if a specific buttons is clicked.
Prints the text for every JButton clicked with an ActionListener:
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent)")
public void buttonPointcut(ActionEvent actionEvent) {}
#Before("buttonPointcut(actionEvent)")
public void beforeButtonPointcut(ActionEvent actionEvent) {
if (actionEvent.getSource() instanceof JButton) {
JButton clickedButton = (JButton) actionEvent.getSource();
System.out.println("Button name: " + clickedButton.getText());
}
}
Prints the text for a specific JButton:
public static JButton j1;
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent) && if()")
public static boolean button1Pointcut(ActionEvent actionEvent) {
return (actionEvent.getSource() == j1);
}
#Before("button1Pointcut(actionEvent)")
public void beforeButton1Pointcut(ActionEvent actionEvent) {
// logic before the actionPerformed() method is executed for the j1 button..
}
UPDATED:
You can do this in many different ways. For example add your buttons to the aspect directly. But I prefere to use a enum object between (ButtonManager in this case), so the code does not know about the aspect. And since the ButtonManager is an enum object, it is easy for the aspect to retrieve values from it.
I just tested it with a Swing button class from Oracle and it works. In the Swing class:
b1 = new JButton("Disable middle button", leftButtonIcon);
ButtonManager.addJButton(b1);
AspectJ is extremely powerful when it comes to manipulating classes, but it can not weave advises into specific objects since objects is not created at the time of weaving. So you can only work with objects at runtime and that is why I have added the addJButton(..) method above. That enables the aspect to check the advised button against a list of registered buttons.
The ButtonManager class:
public enum ButtonManager {
;
private static Collection<JButton> buttonList = new LinkedList<JButton>();
public static void addJButton(JButton jButton) {
buttonList.add(jButton);
}
public static Collection<JButton> getButtonList() {
return buttonList;
}
}
Modified pointcut and advice to only print the name of the buttons registered in the ButtonManager:
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent) && if()")
public static boolean buttonListPointcut(ActionEvent actionEvent) {
Collection<JButton> buttonList = ButtonManager.getButtonList();
JButton registeredButton = null;
for (JButton jButton : buttonList) {
if (actionEvent.getSource() == jButton) {
registeredButton = jButton;
}
}
return registeredButton != null;
}
#Before("buttonListPointcut(actionEvent)")
public void beforeButtonListPointcut(ActionEvent actionEvent) {
JButton clickedButton = (JButton) actionEvent.getSource();
System.out.println("Registered button name: " + clickedButton.getText());
}
UPDATED 2
Okay, I believe I understand what you want. You want to listen to mouse events. That is possible. The downside is that you have to register all your GUI components that you want to listen for clicks with a mouse listener. It is not enough to register the JPanel of the JFrame with a MouseListener. So if you only have registered an ActionListener for your buttons, you also have to add a mouse listener.
I have created a quick solution that works for me. It only shows that it works. I have not tried to make the solution generic with many different GUI objects. But that should be quite easy to refactor in when you have got the basics to work.
In the Swing class:
private class MouseListener extends MouseInputAdapter {
public void mouseClicked(MouseEvent e) {}
}
In the init method of the Swing class:
MouseListener myListener = new MouseListener();
btn1.addMouseListener(myListener);
btn2.addMouseListener(myListener);
In the Aspect class:
#Pointcut("execution(* *.mouseClicked(*)) && args(mouseEvent)")
public void mouseEventPointcut(MouseEvent mouseEvent) {}
#Before("mouseEventPointcut(mouseEvent)")
public void beforeMouseEventPointcut(MouseEvent mouseEvent) {
if (mouseEvent.getSource() instanceof JButton) {
JButton clickedButton = (JButton) mouseEvent.getSource();
System.out.println("aspectJ --> mouseClicked: " + clickedButton.getText());
}
}
This results in the following output in the console:
aspectJ --> mouseClicked: Test1
I hope it helps!

Resources