implementing next and previous buttons using a LinkedList - java

This might be a stupid question, but I'm having trouble thinking this through.
I wrote a method that uses a LinkedList to move through loaded MIDI instruments. I want to make a next and a previous button so that every time you click the button you traverse through the LinkedList.
If I hardcode itr.next(); or itr.previous(); multiple times I can traverse through the LinkedList
public void setInsturment(Synthesizer start,MidiChannel currentChannel[])
{
try
{
start.open();
Soundbank bank = start.getDefaultSoundbank();
start.loadAllInstruments(bank);
LinkedList<Instrument> currentInstrument = new LinkedList<Instrument>();
Instrument instrs[] = start.getLoadedInstruments();
currentInstrument.add(instrs[0]);
currentInstrument.add(instrs[1]);
currentInstrument.add(instrs[2]);
currentInstrument.add(instrs[3]);
currentInstrument.add(instrs[4]);
ListIterator itr = currentInstrument.listIterator();
itr.next();
itr.next();
itr.next();
// nextInstrument();
currentChannel[1].programChange(0,itr.nextIndex());
}
catch(MidiUnavailableException e)
{
System.out.print("error");
}
}
I'm having a lot of trouble making a button that can traverse through the list. Is there an efficient way to do this? I tried something like this with no success.
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == nextButton)
{
sound.nextInstrument();
}
public void nextInstrument()
{
itr.next();
}
Thanks in advance guys!

Well, hmm, a linked list is a List and its items can be accessed by index, this is not the optimal structure to access items by index but I really don't know if you can have a cursor on that kind of collection but you can store the current index on an instance variable.
If you really want random access, then you should consider using ArrayList instead of linked list.
Example:
class NextPrevList {
private int index = 0;
private List currentList; //initialize it with some list
public Object next() {
return list.get(++index);
}
public Object prev() {
//maybe add a check for out of bounds
if (index == 0) return null;
return list.get(--index);
}
}
Personally I think it would be more performant with an ArrayList rather than a LinkedList

The ListIterator#next() method returns the object of interest. If it were my project, I'd assign what is returned from that method to a class field and then notify the GUI of the change.
someInstrument = itr.next();
// fire notify observers method.

Code to the interface: List<Instrument>. This related example navigates a List<ImageIcon>, but the implementation could be changed as required.

MIDI instruments .. next and a previous button
Use an array (e.g. Instrument[]). It might be displayed in a JComboBox, a JList or a JSpinner to allow the user to select an instrument. Here is an example using a combo with renderer.
import java.awt.Component;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.*;
import javax.sound.midi.*;
class InstrumentSelector {
public static void main(String[] args) throws MidiUnavailableException {
Synthesizer synthesizer = MidiSystem.getSynthesizer();
synthesizer.open();
final Instrument[] orchestra = synthesizer.getAvailableInstruments();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JComboBox orchestraSelector = new JComboBox(orchestra);
orchestraSelector.setRenderer(new InstrumentRenderer());
JOptionPane.showMessageDialog(null, orchestraSelector);
}
});
}
}
class InstrumentRenderer extends BasicComboBoxRenderer {
#Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel && value instanceof Instrument) {
JLabel l = (JLabel)c;
Instrument i = (Instrument)value;
l.setText(i.getName());
}
return c;
}
}

Related

GWT Editors - how to add N sub-editors of the same type based on a Collection

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.

ComboBox database value doesn't refresh after Adding New Data

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.

ComboBoxModel events not working

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
}

Help making a JTree with a JCheckBox

I have an unusual situation where I need to have a JTree with each node containing 2 checkboxes and a label (with the ability to add a listener to tell when any of the potential checkboxes are checked). I also need the root node to have the same layout (which I'm assuming means creating a JPanel with 2 JCheckBoxes and a JLabel), with the ability to select all the checkboxes down the tree if one in the root is checked.
Any guidance or examples? I've checked out previous questions on here and associated examples...some of which allowed me to get to the point of having the tree "look" but without giving me a direction for implementing the action behind it.
Thanks!
This might be a good time to look at the old JTreeTable code, which will give you a tree rendered in the first column, and the freedom to render the cells for each column to the right of the tree node as you wish, in your case putting in checkboxes and a label, and allowing you to have TableCellEditors working with your JTable as you are used to. A warning is that, while the code in that link works, it is a little convoluted.
There is an alternative. I have demoed below a Tree Table implementation that is supposed to be better, called Outline, provided by NetBeans (though you don't need to develop with the NetBeans IDE, you just need the jar). This article indicates how easy it is to be to get started.
I was able to mock up a quick example of the Outline tree table in Eclipse (with the org-netbeans-swing-outline.jar imported to my project) in about 30 minutes (I am slow at typing):
private void buildFrame() {
frame = new JFrame("Demo");
frame.setSize(300, 300);
addStuffToFrame();
frame.setVisible(true);
}
private void addStuffToFrame() {
MyTreeNode top = new MyTreeNode("top");
createNodes(top);
DefaultTreeModel model = new DefaultTreeModel(top);
//here are the netBeans tree table classes
OutlineModel outlineModel =
DefaultOutlineModel.createOutlineModel(model, new MyRowModel());
Outline outline = new Outline();
outline.setRootVisible(true);
outline.setModel(outlineModel);
frame.getContentPane().add(new JScrollPane(outline));
}
private void createNodes(MyTreeNode top) {
MyTreeNode child = new MyTreeNode("child 2");
top.add(new MyTreeNode("child 1"));
child.add(new MyTreeNode("g-child1"));
child.add(new MyTreeNode("g-child2"));
child.add(new MyTreeNode("g-child3"));
top.add(child);
top.add(new MyTreeNode("child3"));
top.add(new MyTreeNode("child4"));
}
I create a TreeNode to hold the Booleans that will interoperate well with the JTable's built-in checkbox rendering mechnanism.
public class MyTreeNode extends DefaultMutableTreeNode {
Boolean data1 = null;
Boolean data2 = null;
String name = null;
MyTreeNode (String name) {
this.name=name;
}
void setData1(Boolean val) {data1=val;}
void setData2(Boolean val) {data2=val;}
Boolean getData1() {return data1;}
Boolean getData2() {return data2;}
String getName() {return name;}
}
The netBeans RowModel is the key to making this a table instead of a simple JTree:
public class MyRowModel implements RowModel {
public Class getColumnClass(int col) {
switch (col) {
case 0: return String.class;
case 1: return Boolean.class; //these return class definitions will
case 2: return Boolean.class; //trigger the checkbox rendering
default:return null;
}
}
public int getColumnCount() {
return 3;
}
public String getColumnName(int col) {
return "";
}
public Object getValueFor(Object node, int col) {
MyTreeNode n = (MyTreeNode)node;
switch (col) {
case 0: return n.getName();
case 1: return n.getData1();
case 2: return n.getData2();
default:return null;
}
}
public boolean isCellEditable(Object node, int col) {
return col > 0;
}
public void setValueFor(Object node, int col, Object val) {
MyTreeNode n = (MyTreeNode)node;
if (col == 1) {n.setData1((Boolean)val);}
else if (col == 2) {n.setData2((Boolean)val);}
//EDIT: here is a recursive method to set all children
// selected for one of the two checkboxes as it is
// checked by the parent
for (Enumeration children = n.children();
children.hasMoreElements(); ) {
MyTreeNode child = (MyTreeNode) children.nextElement();
setValueFor(child, col, val);
}
}
}
here is the finished, albeit simplistic, product:
alt text http://img17.imageshack.us/img17/6643/picture1hz.png
I have updated the setValueFor method to iterate over a node's children and set the checkboxes as selected or deselected when a parent has been modified.
Take a look at http://www.java2s.com/Code/Java/Swing-JFC/CheckBoxNodeTreeSample.htm
It wasn't clear where the buildFrame(), addStuffToFrame() and createNodes() methods go. I put them all into an OutlineJFrame class I created that extends JFrame, and deleted the 'frame.' preface where-ever it appeared. Then in my project's main() method, it just created one of those OutlineJFrame objects and set its visible to true. When it ran, I got a resizable but empty window. Where were the rows? Where were the nodes?
Then I asked Geertjan, the NetBeans guru, what I was doing wrong, and he sent me a re-write. But it had the same behaviour.
But I know that my java is fine, because another demo project I did (FileTreeJFrame) displays outline.java objects just fine.

Java Swing: Set member which is displayed in JListBox

Is there a comparable mechanism to the .NET "set DisplayMember" for the JListBox Swing component?
Overriding the toString() method is not sufficient because I also want to be able to change the display member at runtime.
I also looked into implementing my own ListCellRenderer, but found it not very convenient.
Ist there a easier or more elegant approach?
Thanks for your time.
You should create a wrapper class around your business object that overrides toString(). This way you keep your own object clean and can at runtime swap wrappers.
public class MyWrapper()
{
private MyBusinessObject object;
public String toString()
{
return object.getImportantString();
}
}
I came up with a satisfying solution based on implementing a custom ListCellRenderer.
import java.awt.Component;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class DynamicCellRenderer implements ListCellRenderer {
private final ListCellRenderer listCellRenderer;
private String displayMember;
public DynamicCellRenderer(String displayMember) {
this(displayMember, new DefaultListCellRenderer());
}
public DynamicCellRenderer(String displayMember, ListCellRenderer wrapped) {
listCellRenderer = wrapped;
this.displayMember = displayMember;
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Object displayMemberValue = getDisplayMemberValue(value);
return listCellRenderer.getListCellRendererComponent(list, displayMemberValue, index, isSelected, cellHasFocus);
}
private Object getDisplayMemberValue(Object value) {
// value is the domain class
// only works if display member is a method, TODO: fallback to field
// displayMember is something like "getName" -> value.getName() gets called
try {
return value.getClass().getMethod(displayMember).invoke(value);
} catch (Exception ex) {
// if anything went wrong it is the programmers fault -> propagate exception
throw new RuntimeException(ex);
}
}
public String getDisplayMember() {
return displayMember;
}
public void setDisplayMember(String displayMember) {
this.displayMember = displayMember;
}
}
In your client GUI code you can do something like this:
jListBox1.setCellRenderer(new DynamicCellRenderer("getName"));
...
...
// and later at some point
((DynamicCellRenderer) jListBox1.getCellRenderer()).setDisplayMember("getEmail");

Categories