I'm having a difficults to add rows to a table that located in different class.
Following are the classes structure:
The dashed arrow is the desired relation that I dont manage to have
in the AddPanel class I have a fileds and Addbutton.
when clicking the addButton I first creating an instance of Product (class located in Logic Package). Then I need to add row to the table (Using the TableModel.AddRow method).
Following are the GUI Looks (the focused tab is AddPannel):
I tried different approches but non of them were successed.
My last attempt was to create in the Table class the following method:
public void AddRow(Product p) {
tbmStock.addRow(new Object[] { p.getExternalId(), p.getName(),
p.getAmount(), p.getPriceForMe(), p.getPriceForCustomer() });
}
In addition, in the AddPanel class I tried to add the following method:
private void AddButtonAction() {
btnAddProduct.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
Product p = new Product(txtName.getText(), txtExternalID
.getText(), Integer.parseInt(txtAmount.getText()),
Double.parseDouble(txtPriceForMe.getText()),
Double.parseDouble(txtPriceForCustomer.getText()),
Integer.parseInt(txtFromYear.getText()), Integer
.parseInt(txtToYear.getText()), Integer
.parseInt(txtSupplier.getText()), Integer
.parseInt(txtCarType.getText()));
AddRow(p); //This call doesn't compiles
}
catch (Exception e1){
JOptionPane.showMessageDialog(null,"Error");
}
}
});
}
Any suggestions ? (actually I'm not sure even that my structure is good :S )
Provide a custom event and event listener. If you create a new product fire the event and notify all listeners. The MainPanel (assuming that's where you create the instance of AddPanel), should register a listener. In this listener you then can update the table as the MainPanel has access to the table.
This is also known as the Mediator pattern.
Some pointers:
Create an event class, e.g. ProductCreatedEvent extends EventObject. Pass the Product as an argument to the constructor and make it accessible with a getter.
Create an event listener class: interface ProductCreatedEventListener extends EventListener. Provide a method such as productCreated(ProductCreatedEvent productCreatedEvent).
In the AddPanel add something like:
private final List<ProductCreatedEventListener> productCreatedEventListeners = new ArrayList<>();
...
public void addProductCreatedEventListener(ProductCreatedEventListener productCreatedEventListener){
productCreatedEventListeners.add(productCreatedEventListener);
}
public void removeProductCreatedEventListener(ProductCreatedEventListener productCreatedEventListener){
productCreatedEventListeners.remove(productCreatedEventListener);
}
private void fireProductCreatedEvent(ProductCreatedEvent event){
for (ProductCreatedEventListener productCreatedEventListener : productCreatedEventListeners){
productCreatedEventListener.productCreated(event);
}
}
Replace:
AddRow(p); //This isn't working
with
fireProductCreatedEvent(new ProductCreatedEvent(AddPanel.this, p));
Related
first of all I will introduce what I am trying to do. This is an assignment in university we are making Hotel booking system with JAVA. To go straight to the point, all I need to know is how to update JList when I press button.
listModel = new DefaultListModel<Hotel>();
bookingList = new JList(listModel);
class MouseAdapterMod extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(e.getSource() == searchButton){
for(lists.getRoomsList() p : lists.getRoomsList())
{
listModel.addElement(p);
}
bookingList.setModel(listModel);
}
In this GUI class I have instance variable (lists) of Hotel class, in Hotel class there are methods
public ArrayList<Rooms> getRoomsList()
{
return roomsList.getListRooms();
}
public ArrayList<Suite> getSuitesList()
{
return roomsList.getListSuites();
}
this returns whole ArrayList of Room class objects and also ArrayList of Suite class.
QUESTION would be is how to show whole ArrayList of Rooms when I press button, in other words how to update JList which consists of objects, by pressing button?
I hope I explained alright.
Your for-each loop is wrong. Try this and see:
public void mousePressed(MouseEvent e) {
if(e.getSource().equals(searchButton)){
ArrayList<Rooms> rooms = lists.getRoomsList();
for(Rooms r : rooms) {
listModel.addElement(r);
}
bookingList.setModel(listModel);
}
}
This still looks sorta messy to me though. A more appropriate approach would be to set an event handler on the searchButton, to populate the JList when searchButton is clicked.
Also, are Rooms and Suites sub classes of Hotel? If not, you'll have to create listModel like this (for rooms):
listModel = new DefaultListModel<Rooms>();
I have one question regarding Javafx controller.
Lets say, I have multiple fxml files that are bind together in a main app. Then I have separate controllers for every fxml files. Lets see the following structure
com.par.app
- MainApp.java -> This is the main Application
- FirstController.java
- SecondController.java
com.par.app.view
- First.fxml
- Second.fxml
com.par.app.model
- MyModel -> This has some getter and setter methods.
Now as per above structure, I have a checkbox in First.fxml and a label in Second.fxml.
My Question : How can i set the label text in Second.FXML by checking and unchecking the checkbox in First.FXML , I have tried like this:
// In FirstController.Java
1) Initialize the SecondController
2) Get checkbox from FXMl as , priate CheckBox box1;
3) On initialize(....) method, I have set the event handler, as box1.setOnAction(enableHandle)
4) Finally the event Handler as,
EventHandler<ActionEvent> enableHandle = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (box1.isSelected()) {
secondController.setLabelText("PoP");
} else {
secondController.setText("Gone Wrong");
}
}
};
Similarly, On my second controller I have declared FXML control as,
#FXML
private Label lblTes;
// the method
public void setLabelText(String a)
{
this.lblTes.settest(a);
}
-> The above wont work as it returns Unknown Source.
The next way I tried is by using the MyModel , and using getter and setter methods, But unsuccessful.
I'm sorry my question is really long. I have tried but not succeeded.
What can I do to solve this?
Thanks in advance.
// my model looks like
public class MyModel {
private String btnname;
public String getBtnname() {
return btnname;
}
public void setBtnname(String btnname) {
this.btnname = btnname;
}
}
When you check the check box then in the controller of the FirstView (where you implement an event handler for the check box click) change the label text in your model.
Your model should be bound to your views therefore the label text in your SecondView should be updated.
If you did not bind the model to your views you may use an Observer pattern.
1.Change your model and extend java.util.Observable
public class MyModel extends Observable {
private String btnname;
public String getBtnname() {
return btnname;
}
public void setBtnname(String btnname) {
this.btnname = btnname;
pingObservers()
}
private void pingObservers() {
setChanged();
notifyObservers();
}
}
Register your SecondController as an Observer of the model. When you set the model to the controller add a line similar to this:
model.addObserver(this);
SecondController must implement java.util.Observer.update(...)
void update(Observable o, Object o1) {
// Set the label text with model value
}
In you event handler in the FirstController when you call the setBtnname() method on your model the update() method in the SecondController will be called. There up to you to add the code to change your label text. Since the label is in the view controlled by SecondController you just need to inject a reference of the label in the controller with #FXML annotation.
I have some doubts about the use of the PropertyChangeListener interface.
I have a class named GUI that implements the PropertyChangeListener interface.
In this class I have the following method that create and show a JFrame (LoginFrame is a custom class that extends JFrame):
private void showLoginFrame() {
loginFrame = new LoginFrame();
loginFrame.setVisible(true);
loginFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Notify every change to every bound property for that object:
loginFrame.addPropertyChangeListener(this);
}
So, on my LoginFrame object I add a PropertyChangeListener. So I think that I am adding a mechanism for which when change the value of a property in this object it notify this change that will be handle by the following method (declared in my GUI class):
#Override
public void propertyChange(PropertyChangeEvent arg0) {
System.out.println("GUI SingleFrameApplication ---> propertyChange(): " + arg0.getPropertyName());
if (arg0.getPropertyName().equals("buttonLogOffClicked")) {
//System.out.println("GUI SingleFrameApplication ---> richiamo exit");
//exit();
mainFrame.OnWindowClose();
mainFrame.dispose();
mainFrame = null;
showLoginFrame();
}
if (arg0.getPropertyName().equals("loginResult")) {
System.out.println("GUI SingleFrameApplication ---> richiamo MainFrame");
//loginFrame.setVisible(false);
loginFrame.dispose();
loginFrame = null;
showMainFrame();
}
}
In the specific case in my LoginFrame class I have a JButton that if clicked fire the event that will be handled by the previous method, in this way:
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("Button LogIn cliccked");
// this.addPropertyChangeListener(listener); // I add the PropertyChange Listener to this LoginFrame object
// I fire a PropertyChange: the event start and will be handled by the propper propertyChange() method definied in the listener class:
firePropertyChange("loginResult", false, loginResult);
}
Is it my reasoning correct?
Thanks
Andrea
Instead of firing property change from Action performed function directly, better extends your target bean class, define a setXXX() method to change the xxx property. All Java beans is incorporating with getXXX() and setXXX() method to get and set their Property xxxx. The setXXX() is the one changing the property. we should fire the property, After we change the property, in the context we are changing it, hence it is the setXXX() method. Let us look into setPreferredSize(Dimesion) method source code of Component class :
public void setPreferredSize(Dimension preferredSize) {
if (prefSizeSet) {
old = this.prefSize;
}
else {
old = null;
}
this.prefSize = preferredSize;
prefSizeSet = (preferredSize != null);
firePropertyChange("preferredSize", old, preferredSize);
}
See, we are firing the property upon changes of the property with the corresponding property name. The advantage is that it adds better clarity and make the code structure more readable.
Rather than with conditional checking with each property while listening, i would like to use: addPropertyChangeListener("aProperty", PropertyChangeListener) method: which will listen to specific property changes as defined by in place of "aProperty".
As recommended by #Hovercraft below, the property name be a public String constant so as not to run into spelling or capitalization issues.
I am building a simple app and I am implementing it in a simple MVC pattern where the controller adds event handlers to the view. Here's a sample controller code attaching a handler to the UI.
Basically, the code adds an event handler when the UI's save button is clicked. The UI contains the name and id number entry. What I wanted to happen is to pass the name and id number into the actionPerformed function.
ui.onAddStudent(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.print("test");
}
});
And the receiving function in the UI (in another file) is the following.
public void onAddStudent(ActionListener handler){
//something missing here
addStudent.addActionListener(handler);
}
I am not really into Java because it's not my forte. I actually do JavaScript. Now, a similar handler In JavaScript, one can use the call() or apply() method to call the handler and pass in additional parameters. If the above code was in JS, it would be like
//in the controller
ui.onAddStudent(function(event,id,name){
//I can use id and name
});
//in the UI
ui.onAddStudent = function(handler){
//store into a cache
//add handler to the button
}
//when student is added (button clicked)
handler.call(this,event,id,name);
How do I do the same thing in Java?
You have two choices:
let it as it is, and have the controller get the ID and name from the GUI (and that is the easiest and simplest solution, IMHO)
use your own Event and Listener types, containing this information. For example:
public class StudentAddedEvent {
private long ID;
private String name;
...
}
public interface StudentAddedListener {
void studentAdded(StudentAddedEvent event);
}
The UI would register an ActionListener on the button, and this action listener would do:
#Override
public void actionPerformed(ActionEvent e) {
long id = getIdInGui();
String name = getNameInGui();
StudentAddedEvent event = new StudentAddedEvent(id, name);
for (StudentAddedListener listener : studentAddedListeners) {
listener.studentAdded(event);
}
}
You can define your own Actions too, and set those to the buttons (constructor argument or setAction) and other components.
Extend AbstractAction for that.
I can't get my head round this one. I've tried to adhere to the MVC pattern for the first time and now have difficulties accessing the source of an ActionEvent because the ActionListener is located in a different class. But let the code do the talking...
In the "view":
// ControlForms.java
...
private JPanel createSearchPanel() throws SQLException {
...
comboBoxCode = new JComboBox(); // Field comboBoxCode -> JComboBox()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
AutoCompleteSupport<Object> support = AutoCompleteSupport.install(
comboBoxCode, GlazedLists.eventListOf(jnlCodeArray));
}
}); // Auto-Complete comboBox from GlazedLists
...
public void setComboListener(ComboListener comboListener) {
comboBoxCode.addActionListener(comboListener);
}
...
}
Then, in what I term the controller, I have two different classes:
// Controller.java
public MyController() throws SQLException {
...
addListeners();
}
...
private void addListeners(){
View view = getView();
getView().getControlForm().setComboListener(new ComboListener());
}
and
public class ComboListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("ComboBox listened to! e = " + e.toString());
}
}
Now, e obviously doesn't give the name of the variable (which at the moment I wish it would), so I cannot if test for e.getSource().
My question is thus: is there either a) a way to query (via if for example) the source of e, or b) a less complicated way to get to the variable name?
Many, many thanks in advance for your insights and tips!
Why do you need the name of the variable? Why can't you do the event handling like this
public class ComboListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JComboBox source = (JComboBox)e.getSource();
//do processing here
}
}
I'd think that if you need to do processing according the variable name, obviously you need different listeners for different combo boxes.
Generally, there are only two situations in which you should use a listener like that: a) you're going to handle a certain event the same way for a bunch of objects, or b) you're only going to use the listener for one object. In the latter case, I'd prefer handling the event locally anyway.
That said, the direct answer to your question is: you shouldn't have to check inside your ActionListener implementation to see whether the appropriate object is the source of the event; you should simply only add the ActionListener to that one object.
One final note: without knowing the specifics of your architecture... generally, MVC will treat all event handling as part of the View (it reduces coupling) and the View will pass commands or method calls or your own events (i.e., not Swing's) to the Controller.