Not really sure how to phrase the question. Essentially my issue is this:
I have a Form that when the user clicks a button, it invokes a JFrame that populates a datatable with a sql query. The datable frame also has a button. The user can select a cell in the frame and then press the "Select" button. What I need to have happen is to somehow populate a text field with a value from the selection on the parent form. The datatable is invoked from a method in my Main Form class. There is an action event listener associated with the button on the datatable form. Provided is the code from Main:

private void MTHSelectAlertTypeActionPerformed(java.awt.event.ActionEvent evt) {                                                   
// TODO add your handling code here:
    showPreviousAlertTypes();
}                                                  



private void showPreviousAlertTypes()
{
    String query = "select distinct dc_alert_type_id from  custom_alert order by dc_alert_type_id";
    String labels [] = {"Alert Type", "Select" };
    ArrayList selections = new ArrayList();
    
    JFrame frame = new JFrame("Existing Alert Types ");
    //DataTable is a class I defined based on the Sun Tutorial on how to create Swing Tables. It is pretty robust and I am happy with it.
    DataTable existingAlertTypesTable = new DataTable(query, labels, conn, "Existing Alert Types", "Selections", true, frame);
    //Draw and render the frame:
    existingAlertTypesTable.setOpaque(true);
    frame.setContentPane(existingAlertTypesTable);
    
    frame.pack();
    frame.setVisible( 
}

So that's the calling function from Main. I have a public action event associated with my button. All of the values passed in to the constructor are necessary to render my table with the required data:
query is fairly obvious, conn is my database connection object (instantiated globally on the form), The next string is the title of the form, The string "Selections" is a descriptor that I use to differentiate which action I want performed on which table. (I have other buttons on this form that display different data and I have other actions associated with them), The boolean tells the renderer that I want checkboxes displayed on the table, and the frame is the actual table. I pass this in so I can refresh the table from a public method.
So the table is displayed with the requisite data. The user can select cells in the table that populate an array. When they press the "Select" button, I want to pass that array back to the caller, and then set a value from that array in a Text field on the parent frame. Here is the acton Event in the DataTable class:

public void actionPerformed(ActionEvent event) {
        String command = event.getActionCommand();
        // A button (with an action listener) has been rendered on the DataTable frame object. When the user clicks on it, this ActionEvent fires 
        if ("Select" == command)
        {
            if (selection_array.size() <= 1)
            {
                //selection_array is populated with selections from the dataframe. The user hasn't selected anything. I display a JOption pane admonishing them for their ineptitude
            }
/*I have populated an array of values with the selections already. I need to pass this back to main now. I figure I need some type of event listener in the function that instantiated this object that is invoked here. The end result is to populate a text frame with a value from this array (to be determined in the main frame.) */
          
        }
    }

So that's the long and short of it. Let me know if you need any additional data or requirements. I'm still trying to wrap my head around events

Recommended Answers

All 7 Replies

I'm struggling a bit to understand the exact behavior you are aiming for, but if you're just saying that the "main frame" needs to take some action when the selection array changes, you can make a small listener model for this yourself very easily

interface SelectionListener {
    void selectionChanged();
}

/** These go in your DataTable class */
List<SelectionListener> selectionListeners = new ArrayList<SelectionListener>();

public void addSelectionListener(SelectionListener listener){
    selectionListeners.add(listener);
}   

private void fireSelectionChanged(){
    for (SelectionListener listener : selectionListeners){
        listener.selectionChanged();
    }
}

Your action listener would call fireSelectionChanged() to notify all listeners of a selection change. Your main frame can then query the info that it needs. If you wanted to send that data with the selection change event, you could make a small SelectionChangeEvent object to pass with that info.

You could also just wire up a ChangeListener or set up your selection list as a bound property of the DataTable.

. Your main frame can then query the info that it needs.

I think you understand what I was getting at pretty well. It sometimes is difficult asking about something you don't really know too much about. But essentially the quoted element above is the meat and potatoes of the matter. I need to figure out how the main frame can do just that. I've already implemented a selectionListener in the data table class, that's how the selected values get populated in the array. I have an accessor method in the data table that can pass the array, but here is the deal, my main frame can't explicitly know when that array is populated with the data it needs that can only happen after the user has selected the button on the data frame. So when that event occurs, I want to somehow tell the main frame, "I'm done here, go ahead and call the accessor method if you want to"

That is exactly the point of the models I mentioned above. You need to implement a way that your main frame can register itself as a listener for the selection change.

With the small model I included above, your main frame would implement that SelectionListener interface and register itself with the data panel as a listener (calling addSelectionListener(this); ). Any method that made changes to the selection would use fireSelectionChanged() to notify that things had been changed. That is when your main frame would call the accessor to get it's data. So basically your main frame would have an implementation of the SelectionListener like this

public void selectionChanged(){
   dataTable.getSelections();  // or whatever
}

The listener models are there to handle that "let other things know things changed" part.

Here is a "bare bones" mockup of how such an event model can be implemented. I've retained your names so it might be a little clearer

import java.util.ArrayList;
import java.util.List;

public class MainFrame implements SelectionListener {

    DataTable dataTable;
    String mainData;

    public MainFrame() {
        dataTable = new DataTable();
        // Add this as a listener to the DataTable objectd
        dataTable.addSelectionListener(this);
    }

    /** simulate the events and notification */
    public void run() {
        // initial state
        mainData = dataTable.getData();
        System.out.println(mainData);

        // data table gets updated (in reality this represents a user action,
        // but I have to simulate here)
        dataTable.updateSomeData();

        // verify our new data
        System.out.println(mainData);
    }

    /** implementation of SelectionListener interface */
    public void selectionChanged() {
        // get the updated data
        mainData = dataTable.getData();
    }

    public static void main(String[] args) {
        MainFrame mFrame = new MainFrame ();
        mFrame.run();
    }
}

class DataTable {

    private String someData = "initial data here";
    
    // list of listeners
    private List<SelectionListener> selectionListeners = new ArrayList<SelectionListener>();

    /** Add a SelectionListener */
    public void addSelectionListener(SelectionListener listener) {
        selectionListeners.add(listener);
    }

    /** notify SelectionListeners of change*/
    private void fireSelectionChanged() {
        for (SelectionListener listener : selectionListeners) {
            listener.selectionChanged();
        }
    }

    public String getData() {
        return someData;
    }

    /** This method just represents some operation that alters the data */
    public void updateSomeData() {
        // doing stuff...
        someData = "new data here now";
        
        // done, so let all the listeners know
        fireSelectionChanged();
    }
}

interface SelectionListener {

    void selectionChanged();
}
commented: Very detailed and quality help +4

Here is a "bare bones" mockup of how such an event model can be implemented. I've retained your names so it might be a little clearer

import java.util.ArrayList;
import java.util.List;

public class MainFrame implements SelectionListener {

    DataTable dataTable;
    String mainData;

    public MainFrame() {
        dataTable = new DataTable();
        // Add this as a listener to the DataTable objectd
        dataTable.addSelectionListener(this);
    }

    /** simulate the events and notification */
    public void run() {
        // initial state
        mainData = dataTable.getData();
        System.out.println(mainData);

        // data table gets updated (in reality this represents a user action,
        // but I have to simulate here)
        dataTable.updateSomeData();

        // verify our new data
        System.out.println(mainData);
    }

    /** implementation of SelectionListener interface */
    public void selectionChanged() {
        // get the updated data
        mainData = dataTable.getData();
    }

    public static void main(String[] args) {
        MainFrame mFrame = new MainFrame ();
        mFrame.run();
    }
}

class DataTable {

    private String someData = "initial data here";
    
    // list of listeners
    private List<SelectionListener> selectionListeners = new ArrayList<SelectionListener>();

    /** Add a SelectionListener */
    public void addSelectionListener(SelectionListener listener) {
        selectionListeners.add(listener);
    }

    /** notify SelectionListeners of change*/
    private void fireSelectionChanged() {
        for (SelectionListener listener : selectionListeners) {
            listener.selectionChanged();
        }
    }

    public String getData() {
        return someData;
    }

    /** This method just represents some operation that alters the data */
    public void updateSomeData() {
        // doing stuff...
        someData = "new data here now";
        
        // done, so let all the listeners know
        fireSelectionChanged();
    }
}

interface SelectionListener {

    void selectionChanged();
}

That's how I've come to understand it. I'm already implementing a predefined selection listener and fire event property change. All i need to do is follow your suggestion to register those changes in the main class. The definitions of the interface and listeners are structured very similarly to your example. Thanks much for the update!

Ahh yes that worked excellently. The only issue that I had was declaring a datatable globally in the main frame. I had already created the data table in a method in main. It seemed a bit excessive to have such a large object to merely transport a few bytes of data. Lol, too late to refactor the code though. It works and I learned how to implement an interface which I am pleased with.
So I will mark this thread as solved. Thank you much. Your code sample was much more lucid than any of the Sun tutorials or documents (too abstract) as far as the implementation I originally had, there was a pre-defined Interface (ListSelection, I think) an event handler (ListSelectionEvent) But there wasn't an add method defined in the ListSelectionEvent that suited my needs. There probably was but it didn't jump out at me from the java docs. At any rate, if you're bored, I have one other question:
In the DataTable class, I have a method with a signature:

public void addSelectionListener(SelectionListener listener)

And it is called from Main thusly:

dataTable.addSelectionListener(this);

So it is my understanding that in this context the this pointer is a pointer to the main frame. The main frame implements SelectionListener but it also contains all of the objects implemented in the main frame (viewports, buttons, text fields etc.) this seems like a type incompatibility. Yes, the required type data is there, but how does java resolve that from all of the other things included in the this pointer?
Once again thanks for the excellent treatment of my question. You nailed it!

The main frame implements SelectionListener but it also contains all of the objects implemented in the main frame (viewports, buttons, text fields etc.) this seems like a type incompatibility. Yes, the required type data is there, but how does java resolve that from all of the other things included in the this pointer?

The only requirement is that the parameter meet the type specified by the method declaration, which it does by implementing the interface. It doesn't care about anything else but the interface specified.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.