lets say you have lable in MainWindow ..
and you want change value of this lable
from Window2
Not in Same Window !!
i want the changes while the MainWindow its open
It's easy if ur using 2 .fxml files with there own controllers
if that's the case create a new class file namely 'AllControllers'
you have two 2 controllers namely ControllerWindow1 and ControllerWindow2
public class AllControllers {
private static ControllerWindow1 control1;
private static ControllerWindow2 control2;
public static ControllerWindow1 getControl1() {
return control1;
}
public static void setControl1(ControllerWindow1 control1) {
Controlls.control1 = control1;
}
public static ControllerWindow2 getControl2() {
return control2;
}
public static void setControl2(ControllerWindow2 control2) {
Controlls.control2 = control2;
}
}
You have to initialize each controller like this
public class ControllerWindow1 implements Initializable{
#FXML
public Label mylabel;
#Override
public void initialize(URL location, ResourceBundle resources) {
AllControllers.setControl1(this);
}
}
Now you can access your controller from any class. Just use
AllControllers.getControl1().mylabel.setText("hello");
Related
I am trying to change one of my columns and its cell values from another class however i keep getting a null pointer exception when java try's to execute that line OverviewController.getOverviewController.returnStatusColumn.setCellValueFactory(
cellData -> cellData.getValue().getStatusProperty());, I have removed all irreverent code
TableView Class:
#FXML
private TableView<Task> taskTable;
#FXML
private TableColumn<Task, String> statusColumn;
private final static OverviewController controller = new OverviewController
();
public static OverviewController getOverviewController() {
return controller;
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
taskTable.setItems(mainApp.getTaskData());
taskTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
taskTable.setPlaceholder(new Label(""));
}
public TableView<taskTable> returnTasks() {
return taskTable;
}
public TableColumn<taskTable, String> returnStatusColumn() {
return statusColumn;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
statusColumn.setCellValueFactory(cellData ->
cellData.getValue().getStatusProperty());
}
#FXML
public void createTask(ActionEvent event) throws InterruptedException,
IOException, ParseException {
thread = new MyThread();
thread.main(null);
statusColumn.setCellValueFactory(cellData ->
cellData.getValue().getStatusRunningProperty());
statusColumn.setStyle("-fx-text-fill: green; -fx-font-weight: bold;");
taskTable.refresh();
}
#FXML
public void stopTasks() {
statusColumn.setCellValueFactory(cellData ->
cellData.getValue().getStatusProperty());
statusColumn.setStyle("-fx-text-fill: red; -fx-font-weight: bold;");
taskTable.refresh();
}
This class works fine when i want to update the table columns, if i click stop tasks method (which is linked to a button) the status column gets updated to the stop label which i want to do, same with start tasks method.
Random class where i want to update the Table view status column:
public class UpdateTable {
public static void main(String[] args) {
OverviewController.getOverviewController.returnStatusColumn.setCellValueFactory(
cellData -> cellData.getValue().getStatusProperty());
OverviewController.getOverviewController().returnTasks().refresh();
}
}
TableView Data:
//Status Information
private final SimpleStringProperty status;
private final SimpleStringProperty statusRunning;
public Task() {
this(null, null);
}
public Task() {
this.statusRunning = new SimpleStringProperty("Running");
this.status= new SimpleStringProperty("Stop");
}
public StringProperty getStatusProperty( ) {
return status;
}
public StringProperty getStatusRunningProperty( ) {
return statusRunning;
}
}
If i ran the random class it will lead to a null pointer exception in particular this line:
OverviewController.getOverviewController().returnStatusColumn().setCellValueFactory(cellData -> cellData.getValue().getStatusProperty());
Have i done this completely the wrong way? I just want to be able to update the Table view column cells from a different class.
Yes, you're doing this the wrong way.
You don't use a Application subclass anywhere which needs to be used as entry point of your application (assuming you're not using JFXPanel or Platform.startup). Furthermore you access the column as first statement in your program which means there's no way the statusColumn field is initialized.
Also usually there shouldn't be a need to involve any class but the controller class for initializing the cellValueFactory. Especially using static fields is a bad approach:
Assuming you specify the controller class in the fxml, FXMLLoader creates a new instance of the controller class. This instance is different from the instance stored in the controller field so even when using
OverviewController.getOverviewController.returnStatusColumn.setCellValueFactory(
cellData -> cellData.getValue().getStatusProperty());
after loading the fxml you wouldn't get the instance you need.
Instead I recommend using the initialize method of the controller class for these kind of initialisations. It's invoked by FXMLLoader after creating and injecting all the objects specified in the fxml.
public class OverviewController {
...
#FXML
private TableColumn<Task, String> statusColumn;
...
#FXML
private void initialize() {
statusColumn.setCellValueFactory(cellData -> cellData.getValue().getStatusProperty());
}
}
If you do need to pass some info from an class that is not the controller, refer to the answers here Passing Parameters JavaFX FXML . Better approaches than using static are described in the answers.
I have a class named Parser which gets some input and do some calculations and output the results. I also have a jFrame, which has some text fields. I am misunderstanding how to run the parser and use the inputs from the jFrame. I don't know if I should implement the action Listener in my Parser class? or should I import all my Parser class methods in the jFrame? should I have run method in my main of the Parser or should I use the void run in the jframe class??
Here is my class Parser:
public class Parser{
public static List getXKeywords(String Url, int X, String html) throws Exception {
//somemethod with someoutput
}
public static void main(String[] args) throws Exception {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
SpyBiteDemo Sp = new SpyBiteDemo();
Sp.setVisible(true);
int X=Sp.getKeywordcount();
//this top line is not correct because it can only be done when the jframe jButton1 was clicked
}
});
}
}
and here is the jFrame;
public class SpyBiteDemo extends javax.swing.JFrame {
/**
* Creates new form SpyBiteDemo
*/
public SpyBiteDemo() {
initComponents();
}
public String getKeywordcount()
{
return jTextField4.getText();
}
//some methods
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//get the input from the jframe
//feed it to the parser?? how???
String SeedUrl=jTextField1.getText();
Parser P=new Parser();
//I don't have access to methods
because they are static
}
}
here I am trying to get keywordcount variable from the jFrame which is the int X in the getXKeywords method.
I solved my problem with the help of this link
I created a constructor in my parser class and also included a jframe in the parser class as follow:
public class Parser {
SpyBiteDemo Sp=new SpyBiteDemo();
public Parser(SpyBiteDemo Sp)
{
this.Sp=Sp;
int X = Sp.getXKeywords();
//do whatever
}
and in the action performed of the jframe class I call my parser constructor class:
public class SpyBiteDemo extends javax.swing.JFrame {
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Parser P=new Parser(this);
}
}
I'll write the code first and ask my question below
Below is my main class
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runApp();
}
});
}
public static void runApp() {
Model model = new Model();
View view = new View(model);
Controller controller = new Controller(view, model);
view.setLoginListener(controller);
}
}
Below is my another class
public class LoginFormEvent {
private String name;
private String password;
public LoginFormEvent(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Below is my controller class
public class Controller implements LoginListener {
private View view;
private Model model;
public Controller(View view, Model model) {
this.view = view;
this.model = model;
}
#Override
public void loginPerformed(LoginFormEvent event) {
System.out.println("Login event received: " + event.getName() + "; " + event.getPassword());
}
}
Below is my LoginListener interface
public interface LoginListener {
public void loginPerformed(LoginFormEvent event);
}
Lastly below is my view class which I have just deleted the JFrame code for simplicity.
public class View extends JFrame implements ActionListener {
private Model model;
private JButton okButton;
private JTextField nameField;
private JPasswordField passField;
private LoginListener loginListener;
#Override
public void actionPerformed(ActionEvent e) {
String password = new String(passField.getPassword());
String name = nameField.getText();
fireLoginEvent(new LoginFormEvent(name, password));
}
public void setLoginListener(LoginListener loginListener) {
this.loginListener = loginListener;
}
public void fireLoginEvent(LoginFormEvent event) {
if(loginListener != null) {
loginListener.loginPerformed(event);
}
}
}
It is a standard button coordinating code so you guys probably won't even need to read my code to answer my question.
So I know how to write this code and this is how I write it when I want a button to do call some action. But when I try to get my logic around it to understand 'why' it works, I get very confused.
so when I call view.setLoginListener(controller) I'm obviously expecting some kind of LoginFormEvent.
Then when I click the button, in the view class, new LoginFormEvent is constructed.
But then how is the constructed LoginFormEvent within the view class be set as the parameter of expected LoginFormEvent in controller class when there's not really any connection between the two classes except that I have defined view.setLoginListener(controller) in the Application class. This just makes setLoginListener of particular instance of view to expect some kind of LoginListener, meaning it doesn't really have to be the one that I set up in the view class upon a click of a button? But obviously it does have to be because that's how the code is run. but why?
You can see the flow as below
Lets start withApplication.java. lets see the method runApp(). It does below things.
Objects of View.java and Controller.java are created.
Controller.java implements LoginListener.java
view.setLoginListener(controller); // this sets the object of
Controller.java in the object of View.java, both these objects are
same as created in step-1.
Now lets move to View.java
It has a field private LoginListener loginListener; and method public void setLoginListener(LoginListener loginListener). This method sets the field loginListener As we see above in step 2 loginListener refers to the same object of Controller.java created in step 1 above.
Now lets move to public void actionPerformed(ActionEvent e) defined in View.java.
It calls fireLoginEvent(new LoginFormEvent(name, password)); See now Object of LoginFormEvent.java is created and it is passed as a parameter to the method fireLoginEvent(LoginFormEvent event).
Now moving to public void fireLoginEvent(LoginFormEvent event)
It has code : loginListener.loginPerformed(event);. From above we know loginListener refers to the one and only object of Controller.java
method public void loginPerformed(LoginFormEvent event) on that very object of Controller.java is called and same object of (again one and only one) LoginEvent.java is passed as parameter.
For such type of scenarios, I would recommend you to note the objects created of each type and connect the flow of calls. Hope above helps you understand the code.
In my project when a client will be disconnected, server will delete the name from observable list and the tableview should stop showing the name. But the tableview is not updating.
Controller class
public class Controller {
#FXML
public TableView tableView;
#FXML
private TableColumn<clientLoginData,String> client;
#FXML
private TableColumn<clientLoginData,String> activeTime;
void initialize(ObservableList<clientLoginData> data)
{
client.setCellValueFactory(new PropertyValueFactory<>("clientName"));
client.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
activeTime.setCellValueFactory(new PropertyValueFactory<>("time"));
activeTime.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
tableView.setItems(data);
tableView.setEditable(true);
}
}
main class
public class Main extends Application{
volatile public ObservableList<clientLoginData> data= FXCollections.observableArrayList();
public Controller controller;
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("server.fxml"));
Parent root = loader.load();
data.addAll(new clientLoginData((new SimpleStringProperty("john")),new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
controller=loader.getController();
controller.initialize(data);
primaryStage.setTitle("Server");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
Thread t=new Thread(new messengerServer(this));
t.start();
}
public static void main(String[] args) {
launch(args);
}
}
updating class
public class messengerReadThread implements Runnable {
private Thread thr;
private NetworkUtil nc;
public Hashtable<SimpleStringProperty, NetworkUtil> table;
SimpleStringProperty oldName;
Main main;
public messengerReadThread(NetworkUtil nc, Hashtable<SimpleStringProperty, NetworkUtil> table, SimpleStringProperty s, Main main) {
this.nc = nc;
this.thr = new Thread(this);
thr.start();
this.table=table;
oldName=s;
this.main=main;
}
public void run() {
try {
while(true) {
String s1=(String)nc.read();
StringTokenizer st=new StringTokenizer(s1);
if(st.nextToken().equals("Name"))
{
String sn=s1.substring(5,s1.length());
NetworkUtil n1=table.get(oldName);
table.remove(oldName);
oldName=new SimpleStringProperty(sn);
table.put(oldName, n1);
main.data.add(new clientLoginData(oldName,new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
}
else
{
System.out.println("here it is"+s1);
}
}
} catch(Exception e) {
System.out.println("disconnected "+oldName.toString());
main.data.remove(oldName);
//System.out.println(main.data.contains(oldName));
main.controller.tableView.refresh();//the tableview should update
}
nc.closeConnection();
}
}
There are some modification I should to to that code, like avoid using those "static references", by defining the ObservableList and move your Updating Code inside Controller so you can have a 2 classes code, the Main Class and your Controller... but i'll try to keep it simple.
First, you need to define the ObservableList inside you controller.
Then place your "updating" code inside the controller in a method. I suggest you to use a Task<> to keep your controller updated in the JavaFX Thread.
Try something like this:
private void updateTable(){
Task<Void> myUpdatingTask=new Task<Void>() {
#Override
protected Void call() throws Exception {
//Your Updating Code Here
}
}
//and then you run it like this:
Thread hilo=new Thread(myUpdatingTask);
hilo.setDaemon(true);
hilo.start();
}
Then, remove the parameter from your Initialize Method and define it private with the #FXML annotation like this:
#FXML
private void initialize(){
//Your Stuff to initialize
//here is were you fill your table like you did in the Main
//and don't forget to call you updateTable Method
this.updateTable();
}
Since this a dirty hack as pointed out by #kleopatra I am going to decorate it as a dirty hack.
****************************Dirty Hack*****************************************
Try hiding a column and displaying it again and your tableview should refresh
Will it be possible just to simply extend textfield in creating a custom widget that consists of a textbox and label and subsequently inheriting the functionality of the textfield as well as the eventhandling.
From what I understand is that one would normaly extend Composite and then implement initWidget() in the constructor.
initWidget(binder.createAndBindUi(this));
Can I do something similar by just extending textfield.
The reason I want to do this is because of creating an indicator textfield with label already but applying the eventhandling in this custom widget gives me unexpected results when I try to use it somewhere.
import com.google.gwt.core.client.GWT;
public class IndicatorTextField extends Composite implements HasText, HasKeyUpHandlers{
public interface Binder extends UiBinder<Widget, IndicatorTextField> {
}
private static final Binder binder = GWT.create(Binder.class);
public interface Style extends CssResource{
String textStyling();
String requiredInputLabel();
String colorNotValidated();
}
#UiField Style style;
#UiField Label label;
#UiField TextBox textBox;
public IndicatorTextField()
{
initWidget(binder.createAndBindUi(this));
}
public void setBackgroundValidateTextbox(boolean validated)
{
if(validated)
{
textBox.getElement().addClassName(style.colorNotValidated());
}
else
{
textBox.getElement().removeClassName(style.colorNotValidated());
}
}
#Override
public String getText() {
return label.getText();
}
#Override
public void setText(String text) {
label.setText(text);
}
#UiHandler("textBox")
public void onKeyUp(KeyUpEvent event)
{
DomEvent.fireNativeEvent(event.getNativeEvent(), this);
}
#Override
public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
//return textBox.addKeyUpHandler(handler);
return addDomHandler(handler, KeyUpEvent.getType());
}
}
Look at the default constructor of the TextBox class.
/**
* Creates an empty text box.
*/
public TextBox() {
this(Document.get().createTextInputElement(), "gwt-TextBox");
}
It creates the text input element. You can create your custom class LabeledTextBox with a constructor like this:
public class LabeledTextBox extends TextBox {
public MyTextBox() {
super(Document.get().createDivElement());
final DivElement labelElement = Document.get().createDivElement();
final InputElement textBoxElement = Document.get().createTextInputElement();
getElement().appendChild(labelElement);
getElement().appendChild(textBoxElement);
}
...
}
I didn't try this class myself. Most likely, it will require extra adjustments, there might be listener issues etc.
Do you really need to create a widget by subclassing TextBox? Why don't you use some sort of Panel instead? It's an easier approach as for me.