I seem not to grasp the concept of Events and such. After reading a while on how to implement the listeners and such I came across the Java tutorial saying I should extend AbstractListModel to get the data event firing. For some reason it still doesn't work.
Is there anything I'm doing wrong?
And what kind of code is expected at addListDataListener(ListDataListener l) for it to work? Since I don't understand that either.
public class CarComboBox extends AbstractListModel<Object> implements ComboBoxModel<Object> {
private JdbcRowSet jdbc;
private int size = 0;
private String selection;
public CarComboBox() {
try {
jdbc = new Query().getCarInfo();
jdbc.beforeFirst();
while (jdbc.next()) {
size++;
}
jdbc.beforeFirst();
}
catch (SQLException ex) {
System.err.println(ex.toString());
}
}
#Override
public void setSelectedItem(Object anItem) {
selection = (String) anItem;
}
#Override
public Object getSelectedItem() {
return selection;
}
#Override
public void addListDataListener(ListDataListener l) {
}
#Override
public void removeListDataListener(ListDataListener l) {
}
#Override
public int getSize() {
return size;
}
#Override
public String getElementAt(int index) {
try {
jdbc.absolute(index + 1);
return jdbc.getString(2);
}
catch (SQLException ex) {
System.out.println(ex.toString());
}
return null;
}
}
And to add a listener to the CarComboBox I do:
CarComboBox ccb = new CarComboBox();
ccb.addListDataListener(new ListDataListener()
I'm guessing that you are using the official tutorial.
However you should not touch ListModel and ComboBoxModel. Those are more advanced features you probably do not need.
The 4 examples in the tutorial do NOT use ListModel and ComboBoxModel.
If you use a standard JComboBox (no ListModel or ComboBoxModel), what happens is that when someone makes a selection, an ActionEvent is fired. This event is magically fired by Swing; you don't have to worry about how it is generated. However what is your responsibility is to have some (zero, one or more) objects being able to receive and do something about the ActionEvent:
public class MyClass implements ActionListener {
JComboBox comboBox = ...;
...
// You must register explicitly every ActionListener that you
// want to receive ActionEvent's from comboBox.
// Here we register this instance of MyClass.
comboBox.addActionListener(this);
...
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JComboBox) {
System.out.println("MyClass registered an ActionEvent from a JComboBox.");
System.out.println("Selected: " +
((JComboBox) e.getSource()).getSelectedItem());
}
}
}
Note that if you don't have any other ActionEvent's fired by different Swing components you
can skip the if (e.getSource() instanceof JComboBox) since you know your ActionEvent always comes from a JComboBox.
In my example the JComboBox is inside MyClass, but it does not have to be:
JComboBox comboBox = ...;
MyClass myClass = ...;
comboBox.addActionListener(myClass);
...
comboBox.addActionListener(someOtherActionListener);
You don't need to override addListDataListener() and removeListDataListener() method. The AbstractListModel already take care of the listeners. Here is the implementation of AbstractListModel.addListDataListener():
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
The idea of abstract classes is that they do most of the work for you. Usually you only need to implement abstract methods.
XXListener and XXModel are different sides of the coin: the former is the observer to the latter which is the observable. The listener registers itself to the model when it wants to get notified on changes. It's the responsibility of the model to
manage its listeners (that's typically handled already by the AbstractXXModel, as already explained by #userWhateverNumber ;)
fire the notifications if appropirate: that's the part a custom model must take over, in your case
like
#Override
public void setSelectedItem(Object item) {
selection = item;
fireContentChanged(this, -1, -1);
}
Arguably (there are personal preferences around :-) you often don't need custom model implementations but can just as well re-use the provided DefaultXXModels. In your context and assuming the content of the resultset is immutable it might be an option to fill the default model with the data at construction time, like
DefaultComboBoxModel model = new DefaultComboBoxModel();
forEachRowInResultSet {
model.addElement(resultSet.getString(2));
}
If, on the other hand, the content changes then your model implementation is invalid anyway: the model must notify its listeners whenever something had changed
Object one = model.getElementAt(index);
Object other = model.getElementAt(index)
if (!one.equals(other)) {
listener must have received a contentsChanged
}
Related
I'm building a Java Swing class called ListView that attempts to be a general purpose list.
public class ListView<T> extends JPanel {
private IListViewDataSource<T> dataSource;
private JPanel list;
public ListView(IListViewDataSource<T> dataSource, Dimension dimension) {
this.dataSource = dataSource;
list = new JPanel(new GridLayout(0, 1));
this.add(new JScrollPane(list));
this.setPreferredSize(dimension);
}
public void loadRows() {
for (int i = 0; i < dataSource.getNumberOfElements(); i++) {
JLabel label = new JLabel(dataSource.getTitleOfElement(dataSource.getElementAtPosition(i)));
list.add(label);
}
}
}
In order to do this, I declared an interface called IListViewDataSource that defines the methods required for the list view to obtain its data.
public interface IListViewDataSource<T> {
T getElementAtPosition(int position);
int getNumberOfElements();
String getTitleOfElement(T element);
}
I wanted it to be possible to instantiate a new ListView with whichever DataSource you declare, in order to introduce whichever data in the list. So far so good.
Now, I'm building another class called OfferListView that extends ListView, and in order not to have an inneccessary extra file I wanted it to implement its own ListViewDataSource. The problem is that I can't call super(this, dimension) inside the constructor for this new class, as I'm then told that this can't be used before the superclass constructor has been called.
This "pattern" is what is used when programming with UIKit for iOS, and I think it's quite nice, but I can't get it to work in Java. How could I approach this?
Domain-View-Controller strategy was used in 90s on smaltalk to seperate view from domain and it is still being used in web-development.
Without writing all the classes for views etc, there are two ways for seperating view from domain.
(1st:) When view passes something to domain object then it keep polling to check for any additional changes. That means once a view object(a textfield, frame or anything else) has forwaded a request to domain it keeps checking after few seconds or minutes if something has changed. However this approach is not good.
(2nd:) The observer design pattern. When one thing changes it notifies automatically all listeners. Your view has to implement an interface and domain should provide a method for subscription for all objects which implement that interface. Here is an example and i did not compile it, However it clearly seperates view from domain.
public class View implements PropertyChangeListener {
private DomainObject object;
public View(DomainObject object) {
assert(object != null);
this.setObject(object);
}
public void enterText(String text) {
this.getObject().update(text);
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals("string_updated"))
System.out.println("New value is " + evt.getNewValue());
}
public DomainObject getObject() {
return object;
}
public void setObject(DomainObject object) {
this.object = object;
}
}
Here is the domain class:
public class DomainObject {
private String text;
public DomainObject(String test) {
this.setText(test);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void update(String string) {
this.setText(string);
this.getListener().stream().forEach(e -> e.propertyChange(new PropertyChangeEvent(this,"string_updated","",this.getText())));
}
private ArrayList<PropertyChangeListener> listener;
public void subscribe(PropertyChangeListener listener) {
this.getListener().add(listener);
}
public ArrayList<PropertyChangeListener> getListener() {
return listener;
}
public void setListener(ArrayList<PropertyChangeListener> listener) {
this.listener = listener;
}
}
As i see, You are trying to have many views, if they are contained within eachother then use also Composite design pattern.
My question is conceptual about synchronizing data and events in programming a gui. (This example shows batch state being the facilitator of taking classes that implement the same interface and dynamical updating cells in two different frames.This code is where I got my idea. )
I am assuming that I will create new instances of this batch state object specifically in the classes where an event is triggered(panel) and the reaction to that event(another panel) . I will do this by adding the classes that need to communicate to the a list of bsListeners. Then call the batch state function like "setSelectedCell()" to iterate over each class to synchronize them.
The Problem
This would work perfect if the object both shared the same arrayList but since they are both new instances they don't. I tried changing things to static and it is freaking out especially in the interface. Is this approach logical I am brand new to programming gui's? Sorry this is a novel.
interface BatchStateListener {
public void valueChanged(Cell cell, String newValue);
public void selectedCellChanged(Cell newSelectedCell)
}
class BatchState {
private String[][] values;
private Cell selectedCell;
private List<BatchStateListener> listeners;
public BatchState(int records, int fields) {
values = new String[records][fields];
selectedCell = null;
listeners = new ArrayList<BatchStateListener>();
}
public void addListener(BatchStateListener l) {
listeners.add(l);
}
public void setValue(Cell cell, String value) {
values[cell.record][cell.field] = value;
for (BatchStateListener l : listeners) {
l.valueChanged(cell, value);
}
}
public String getValue(Cell cell) {
return values[cell.record][cell.field];
}
public void setSelectedCell(Cell selCell) {
selectedCell = selCell;
for (BatchStateListener l : listeners) {
l.selectedCellChanged(selCell);
}
}
public Cell getSelectedCell() {
return selectedCell;
}
}
My questions was a bit confusing, but I came to my answer. I was just wondering how to implement this BatchState class in my code. I found that if I make it in main and pass it to the constructors frames/panels that need to communicate with each other they all can share reference to it.
I have an object, Supply, that can either be an ElecSupply or GasSupply (see related question).
Regardless of which subclass is being edited, they all have a list of BillingPeriods.
I now need to instantiate N number of BillingPeriodEditors based on the contents of that list, and am pretty baffled as to how I should do it.
I am using GWTP. Here is the code of the SupplyEditor I have just got working:
public class SupplyEditor extends Composite implements ValueAwareEditor<Supply>
{
private static SupplyEditorUiBinder uiBinder = GWT.create(SupplyEditorUiBinder.class);
interface SupplyEditorUiBinder extends UiBinder<Widget, SupplyEditor>
{
}
#Ignore
final ElecSupplyEditor elecSupplyEditor = new ElecSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor> elecSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor>(
elecSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof ElecSupply);
if(!(value instanceof ElecSupply))
{
showGasFields();
}
else
{
showElecFields();
}
}
};
#Ignore
final GasSupplyEditor gasSupplyEditor = new GasSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor> gasSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor>(
gasSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof GasSupply);
if(!(value instanceof GasSupply))
{
showElecFields();
}
else
{
showGasFields();
}
}
};
#UiField
Panel elecPanel, gasPanel, unitSection;
public SupplyEditor()
{
initWidget(uiBinder.createAndBindUi(this));
gasPanel.add(gasSupplyEditor);
elecPanel.add(elecSupplyEditor);
}
// functions to show and hide depending on which type...
#Override
public void setValue(Supply value)
{
if(value instanceof ElecSupply)
{
showElecFields();
}
else if(value instanceof GasSupply)
{
showGasFields();
}
else
{
showNeither();
}
}
}
Now, as the list of BillingPeriods is a part of any Supply, I presume the logic for this should be in the SupplyEditor.
I got some really good help on the thread How to access PresenterWidget fields when added dynamically, but that was before I had implemented the Editor Framework at all, so I think the logic is in the wrong places.
Any help greatly appreciated. I can post more code (Presenter and View) but I didn't want to make it too hard to read and all they do is get the Supply from the datastore and call edit() on the View.
I have had a look at some examples of ListEditor but I don't really get it!
You need a ListEditor
It depends of how you want to present them in your actual view, but the same idea apply:
public class BillingPeriodListEditor implements isEditor<ListEditor<BillingPeriod,BillingPeriodEditor>>, HasRequestContext{
private class BillingPeriodEditorSource extends EditorSource<BillingPeriodEditor>{
#Override
public EmailsItemEditor create(final int index) {
// called each time u add or retrive new object on the list
// of the #ManyToOne or #ManyToMany
}
#Override
public void dispose(EmailsItemEditor subEditor) {
// called each time you remove the object from the list
}
#Override
public void setIndex(EmailsItemEditor editor, int index) {
// i would suggest track the index of the subeditor.
}
}
private ListEditor<BillingPeriod, BillingPeriodEditor> listEditor = ListEditor.of(new BillingPeriodEditorSource ());
// on add new one ...
// apply or request factory
// you must implement the HasRequestContext to
// call the create.(Proxy.class)
public void createNewBillingPeriod(){
// create a new one then add to the list
listEditor.getList().add(...)
}
}
public class BillingPeriodEditor implements Editor<BillingPeriod>{
// edit you BillingPeriod object
}
Then in you actual editor edit as is in the path Example getBillingPeriods();
BillingPeriodListEditor billingPeriods = new BillingPeriodListEditor ();
// latter on the clickhandler
billingPeriods.createNewBillingPeriod()
You are done now.
After adding data into the database, there is no changes to the JComboBox unless I execute the program again. Do I need to call any specific methods to refresh the values? Thanks!
New Code:
class ComboModel extends AbstractListModel implements ComboBoxModel
{
// array? treeset?
public Object getElementAt(int index) {
}
public int getSize() {
}
public Object getSelectedItem() {
}
public void setSelectedItem(Object anItem) {
}
}
final JComboBox stockListComboBox = new JComboBox();
ComboModel model = new ComboModel();
stockListComboBox.setModel(model);
try
{
// Database Stuffs
}
catch(Exception e)
{
e.printStackTrace();
}
Not sure if I got second part of the question, however, regarding values added to DefaultComboBoxModel, you have to call a method to let the combobox know the model elements changed.
You can use fireContentsChanged method or fireIntervalAdded one.
Working with a traditional listener callback model. I have several listeners that collect various stuff. Each listener's collected stuff is inside the listener in internal structures.
The problem is that I want some of the listeners to be aware of some of the "stuff" in the other listeners.
I enforce listener registration order, so if I knowingly register events in some order a later listener can be sure that a previously listener updated its stuff and somehow access it to do more stuff.
My first attempt at this is to have each listener store a reference to the listeners upon which it depends. So I register listeners in the order of those without dependencies to those with prior-registered dependencies, and then set the references between the listeners in various methods.
I am starting to realize how bad this feels and I was wondering if somehow has been down this road before. What would be a more appropriate pattern when one of the listeners needs to access stuff in another?
Here is some pseudocode to illustrate:
interface Listener { onEvent(char e); }
class A implements Listener {
private int count;
public void onEvent(char e) { if(e == 'a') count++; }
public int getCount() { return count; }
}
class B implements Listener {
private int count;
// private A a;
// private void setA(A a) { this.a = a; }
public void onEvent(char e) { if(e == 'b') count++; }
public int getCount() { return count; }
public int getAPlusBCount() {
// We know B count, but we don't know A so how would we change this
// so B is A aware? Or not even aware, just somehow coupled? This
// is the question
// return a.getCount() + count;
}
public void doConditionalHere() {
// Do some condition in B that relies on the state of data in A
int acount = 0; // a.getCount(); ???
if(acount % 2 == 0) {
this.count--;
}
}
}
class Run {
A a = new A();
B b = new B();
List listeners = new List();
listeners.add(a);
listeners.add(b);
// The ugly way I add coupling right now is to keep a reference to A
// inside B. It's commented out because I am hoping there is a more intelligent approach
// b.setA(a);
for(char c : "ababbabab") {
for(listener : listeners) {
listener.onEvent(c);
}
}
}
You've describing a lot of coupling here. Best would be to eliminate all this back-channel dependency, but failing that maybe you could have those with dependencies listening not on the initial listener list, but on whatever they are dependent on. Or you could have them wait till they have all the signals.
You could automate the dependency management by having the listeners identify who they are dependent upon. The listener list would be ordered not by insertion order, but to insure dependent objects follow their dependency. Your listener interface would look something like this:
interface Listener {
String getId();
Collection<String> getDependencies();
onEvent(char e);
}
Or just have the references, like so:
interface Listener {
Collection<Listener> getDependencies();
onEvent(char e);
}
Why not have a central object that will keep track of how many times the onEvent method was fired for all the listener classes
public interface CountObserver {
public void updateCount(String className);
public int getCount(String className);
}
public class CentralObserver implements CountObserver {
private int aCount;
private int bCount;
public void updateCount(String className) {
//There's probably a better way to do this than using
//all these if-elses, but you'll get the idea.
if (className.equals("AclassName")) {
aCount++;
}
else if (className.equals("BclassName")) {
bCount++;
}
}
public int getCount(String className) {
if (className.equals("AclassName")) {
return aCount;
}
else if (className.equals("BclassName")) {
return bCount;
}
}
class A implements Listener {
CountObserver countObserver;
public void registerObserver (CountObserver countObserver) {
this.countObserver = countObserver;
}
public void onEvent(char e) {
if(e == 'a') {
countObserver.updateCount (this.getClass.getName);
}
}
}
//Same thing for B or any other class implementing Listener. Your Listener interface should, of
//course, have a method signature for the registerObserver method which all the listener classes
//will implement.
class Run {
private A a;
private B b;
private CountObserver centralObserver;
public runProgram () {
centralObserver = new CentralObserver();
a.registerObserver(centralObserver);
b.registerObserver(centralObserver);
//run OnEvent method for A a couple of times, then for B
}
public int getAcount () {
return centralObserver.getCount(a.getClass.getName());
}
public int getBcount () {
return centralObserver.getCount(b.getClass.getName());
}
}
//To get the sum of all the counts just call getAcount + getBcount. Of course, you can always add more listeners and more getXCount methods
"How would we change this so that Listener B is Listener A aware? Or not even aware, just somehow coupled?"
You don't often want to couple two "peer" objects like this. You want two peers to depend on something common.
The deeper question is what does Listener A or Listener B do with all the information they collect?
A Listener often does two things: it collects data and it takes action. Often these two things need to be separated. Listeners should listen and collect and do little more. Some other object(s) can be activated by a Listener.
What you may have is just one listener which has several actions (A and B). The listener can then provide appropriate counts to A as well as B. It provides an 'a' count to A. It provides an 'a' or 'b' count to B.