how to implement a horizontal list view

[moved from how to section - I think this is the appropriate section]

I have a chart to implement that needs to list medicines that are administered over a certain period of time. The time administered needs to be plotted out across the medicine row with 24+ boxes indicating whether the medicine for that given hour is a) not scheduled to be given, b) scheduled to be given, or c) has been given.

I’ve thought of 3 possible implementations, and am working on a 4th. I would really like to hear any suggestions for the best way to do this in Servoy.

POSSIBLE IMPLEMENTATIONS

  1. At first I thought I would overlay a number of named elements, store their states in a JSON array, and display them onLoad. Alas, I learned the element array applies to the record view, not the list view, so this method won’t work.

  2. Then I thought I would add another list view to my medicine list view that grew horizontally - but this does not seem to be possible, either.

  3. Finally, I got the desired behavior by adding 24+ media data providers to my medicine list view, which returned a media resource location through a calculation. So that’s 24+ numbered columns in a single table with 24+ corresponding calculations. Obviously, not an elegant solution.

  4. I’m currently working with the JTable Bean to see if I can implement something more programatic.

Thanks for any tips.

  1. One calculated html display field using table cells as your markers over time.

Thanks for the reply, David.

I did think about using some HTML, but I couldn’t figure out how to persist the data from the HTML field.

So if I’ve got a bunch of treatment_time records relating to a medicine record, I understand how you could calculate the appropriate display of checked, un-checked or hidden check-boxes, but how would you grab the mouse clicks on the table cells and populate the treatment_time records (e.g. insert/update columns like time=1/2/3/4/…, display=hidden/un-checked/checked).

Tony

You could also have a look at our Table-Bean. You could create a dataset that fits your needs and let the bean display that.

yekinabud:
I did think about using some HTML, but I couldn’t figure out how to persist the data from the HTML field.

Yea, outputting html with a calculation is not a trivial thing. Most times it’s just easier to punch in the html into the html column at the form.onShow() event.

You can speed this process up by making this column data local so it’s not stored back to the server. Just set the html display column to have no data provider.

Easier than a calc to script but you have to manage the display when the data shows up. So you’re exchanging tradeoffs.

yekinabud:
So if I’ve got a bunch of treatment_time records relating to a medicine record, I understand how you could calculate the appropriate display of checked, un-checked or hidden check-boxes, but how would you grab the mouse clicks on the table cells and populate the treatment_time records (e.g. insert/update columns like time=1/2/3/4/…, display=hidden/un-checked/checked).

You can fire methods from within html using a special javascript call in an href tag:

<a href="javascript:methodName(argument1, argument2...)">Run Servoy method</a>

html code in Servoy is generally a frustrating thing to deal with when coming up with complex displays. The default java html renderer has its issues. But once you’ve figured out the limits you can do some fairly impressive things with html.

So my recommendation if you want to save yourself time and frustration would be to use Patrick’s table bean. If you want to get adventurous, here’s the html output for the attached pic to give you some ideas.

<html>
	<head>

<style type="text/css" media="screen">

</style>
		<title></title>
	</head>
	<body>
		<table>
			<tr>
				<td width="126" align="left">
					<a href="javascript:REC_row_selected(1)">Rentfield Enterpri</a>
				</td>
				<td width="56" align="left">
					<a href="javascript:REC_row_selected(1)">Active  </a>
				</td>
				<td width="21" align="left">
					<a href="javascript:REC_row_selected(1)">1  </a>
				</td>
				<td></td>
			</tr>
			<tr>
				<td class="rowSelected" width="126" align="left">
					<a href="javascript:REC_row_selected(2,1)">Servoy            </a>
				</td>
				<td class="rowSelected" width="56" align="left">
					<a href="javascript:REC_row_selected(2,1)">Active  </a>
				</td>
				<td class="rowSelected" width="21" align="left">
					<a href="javascript:REC_row_selected(2,1)">7  </a>
				</td>
				<td class="rowSelected"></td>
			</tr>
			<tr>
				<td width="126" align="left">
					<a href="javascript:REC_row_selected(3,1)">Cibex Central Corp</a>
				</td>
				<td width="56" align="left">
					<a href="javascript:REC_row_selected(3,1)">Inactive</a>
				</td>
				<td width="21" align="left">
					<a href="javascript:REC_row_selected(3,1)">8  </a>
				</td>
				<td></td>
			</tr>
			<tr>
				<td width="126" align="left">
					<a href="javascript:REC_row_selected(4,1)">ABC Company       </a>
				</td>
				<td width="56" align="left">
					<a href="javascript:REC_row_selected(4,1)">Active  </a>
				</td>
				<td width="21" align="left">
					<a href="javascript:REC_row_selected(4,1)">26 </a>
				</td>
				<td></td>
			</tr>
			<tr>
				<td width="126" align="left">
					<a href="javascript:REC_row_selected(5)">Data Mosaic       </a>
				</td>
				<td width="56" align="left">
					<a href="javascript:REC_row_selected(5)">Inactive</a>
				</td>
				<td width="21" align="left">
					<a href="javascript:REC_row_selected(5)">33 </a>
				</td>
				<td></td>
			</tr>
		</table>
	</body>
</html>

Thanks for your replies, David and Patrick.

Patrick - I looked at the Dr. Maison & Partner GmbH Table-Bean. It looks like a very nice bean, but I think it might be a little much for what I’m trying to implement, and it’s non-free.

David - Thank you very much for the implementation idea and the code snippet! I may have to go this route, as it seems I’m having difficulty with my JTable implementation. For some reason I can’t get Booleans to render as check-boxes - I thought this was the default behavior. I can add a cell editor of type JCheckBox by simply instantiating a new DefaultCellEditor, but adding a cell renderer doesn’t look so easy - I think I actually have to create my own implementation class and access that as a plugin or a bean.

Here’s my code. Any thoughts or suggestions would be greatly appreciated. (Note: I’m not sure exactly what kinds of objects JSDataSet.getAsTableModel() returns to the JTable model, but creating my own JTable with a vector of vectors of Boolean objects, or setting a Boolean in the cell after the fact doesn’t work either.)

// convert dataset into JTable
var table = elements.monitoring;
table.model = treatments.getAsTableModel();

// modify column headers
var columns = table.columnModel;
columns.getColumn(0).setHeaderValue('Quantity');
columns.getColumn(0).setPreferredWidth(60);
columns.getColumn(1).setHeaderValue('Repeats/hr.');
columns.getColumn(1).setPreferredWidth(75);
columns.getColumn(2).setHeaderValue('TREATMENT');
columns.getColumn(2).setPreferredWidth(225);

// start treatment times at 8am
var j=8;
for (i=3;i<44;++i) {
	var j_int = Packages.java.lang.Integer(j);
	columns.getColumn(i).setHeaderValue(j_int);
	columns.getColumn(i).setPreferredWidth(10);
	if (j == 12) {
		j=0;
	}
	++j;
}

// center cell data
var cell_class = Packages.java.lang.String;
var table_renderer = table.getDefaultRenderer(cell_class);
table_renderer.setHorizontalAlignment(0);

// add JTable to JScrollPane viewport (necessary to display headers)
var viewport = elements.monitoring_pane.viewport;
viewport.add(table);

Tony

Hi Tony,

Happened to be glancing through the Forum and came across your post. I have done something related along the lines of what you outlined in No. 1:

POSSIBLE IMPLEMENTATIONS

  1. At first I thought I would overlay a number of named elements, store their states in a JSON array, and display them onLoad. Alas, I learned the element array applies to the record view, not the list view, so this method won’t work.

I did this in record view with a series of named elements to get the same effect. In my case it has to do with an inventory system for tracking specimens in a freezer box. What is different is that the size of the ‘box’ is always the same with 9 rows and 9 columns. In your case it sounds like the number of columns will be the same (24) but the number of rows might vary depending on the number of medicines. However that could easily be adjusted dynamically for each case.

How I did it is to run a query for a particular box number we are looking at. In that query I retrieve the locations (A1, B3, C8, etc.) of stored material in that box and then compare those active location results against my standard named elements in that grid. Whenever there is a match I change the text of that element to reflect what is actually there. I’ve attached a couple of images to show the form in Designer mode (with ungrouped elements and one of them ‘selected’) and also an active box where all of the slots are occupied except ‘H8’.

For us this works really well: fast, accurate and everything updated, entered or deleted with just a couple of clicks. There are a number of methods to achieve this but pretty straightforward stuff. In your case the query would, presumably, compare what is stored for a particular medicine on a particular hour. When a new patient/medicine is entered perhaps you would auto-populate the elements/hours with the standard entries for the particular drug. Then the data entry staff would simply click on the slot they want to update. I’m happy to supply the methods I use for this if it something you might be interested in.

Bingo!

How much do I win?

:D

david:
Bingo!

How much do I win?

:D

Sorry, you are missing one number. You won nothing. :cry:

;)

Thanks for your reply, John.

I’ve been able to move forward with the JTable implementation - at least as far as getting my check-boxes to render properly. It appears that, although the default renderer for Booleans is indeed a check-box, the getColumnClass method default return value is Object, so that just renders as a string. I had to override this method and specify the classes I wanted returned for specific columns.

What is different is that the size of the ‘box’ is always the same with 9 rows and 9 columns. In your case it sounds like the number of columns will be the same (24) but the number of rows might vary depending on the number of medicines. However that could easily be adjusted dynamically for each case.

Are you suggesting that I could dynamically add elements to a form? How do you do that?

Are you suggesting that I could dynamically add elements to a form? How do you do that?

Not so much suggesting that you dynamically ADD elements, simply that you change the VISIBILITY of elements (along with other properties if you wish such as location, font, text, color, etc. as I do with our inventory solution).

In your case it sounds as though the number of tracked ‘medicines’ can vary (from patient to patient perhaps?). So those are the ‘rows’. However the columns will always be 24. So you could have a form with 24 column elements and how ever many the maximum number of rows/medicines would be possible. I’m presuming that it isn’t that many that the user would be wanting to see/handle at any one time - maybe 20 max? Then when you show that form for a particular patient/medicine combination you fill and show (via query) however many rows/medicines are being tracked for that patient. Does that make any sense? In our case the size of the ‘grid’ (rows and columns) is fixed and so we show all of them and just alter dynamically the text, color and font based on the value for each ‘slot’. But it would work just as well showing/hiding each slot (or medicine/row in your case).

John

Sounds like you are rebuilding the InMemDataGrid bean that ships with Servoy…

That bean allows you to load a dataset (you determine the no of rows and columns) into a Grid (It’s an implementation of a JTable) and what the heck, it allready has support for checkbox column rendering…

Paul

Don’t know that bean. In my latest 3.5 install I have the following jars in my bean directory:
datagrid.jar
dbtreeview.jar
htmlbean.jar
IClock.jar
molecule.jar
s11_chart.jar
swingbeans.jar

Presumably it is the ‘datagrid.jar’. I’ll have to take a look at that. Wasn’t included at the time I made my inventory solution back with 3.0. Damn, all that effort! Actually just kidding, it was really pretty simple but naturally Servoy just keeps getting better and better! I’m sure I know at most 20% of the things I can do with it!

You have methods attached to each grid element John – not so straight forward to do with the InMemDataGrid bean. So not necessarily a replacement for what you did.

Which is one of the reasons (I suspect) Patrick created his table bean. Easy to create buttons, event methods, and right-click contextual menu actions from the bean to the cell level.

Now that would have saved you some work :)

It’s indeed teh datagrid.jar, but it shows up in Servoy in the beans list as InMemDataGrid.

Thought it was allready shipped with 3.0, but I might be wrong there

Paul

Hi David and Paul,

I loved it when I saw Patrick’s demo of the table bean at the last Servoy World. I knew I just needed some time to play with it. Kind of like Marcel’s Analyzer: if I had the time I know that time invested would save me a bunch down the road but so far just haven’t gotten around to either of them in any detail. With my inventory solution it did take me a little time to draw the objects, name them and attach the methods. There were really though not that many methods: a few onShow to ‘fill’ the slots and a few onAction when clicking on a slot (filling it, emptying it or showing more information). So it wasn’t too bad. I think InMemDataGrid must have come about in either 3.1 or 3.5. In looking at it a little today though I can see what you are saying about attaching methods not being so straightforward. Doing what I did I was just using the techniques I already knew pretty well and was just able to expand a bit my use of arrays which is always useful!

John

So, I’m still going with implementation #4 (JTable) - but I’ve run accross an issue. How the heck do you efficiently test custom Java classes in Servoy?

I created my own JTable implementation and put it in a package in the plugins directory so I could access it in the method editor, but now every time I want to try something out, it seems I have to compile, jar and restart Developer.

I guess I could re-create a testing environment in a stand alone Java app (create a data set, Table model, etc.), but is there an easier way to test your own imported classes that need to integrate with Servoy components and methods?

Ran into a problem implementing a table listener so I can fire my servoy methods when a table cell is clicked. Keep getting an ArrayIndexOutOfBoundsException.

Any thoughts on what I could be doing wrong?

Thanks in advance for any tips.

I instantiate the class in the method editor and add the TableModelListener like so:

var table = new Packages.my_classes.MyJTable();
table.model = model; // a working model defined elsewhere
table.getModel().addTableModelListener(table);

Here’s my class:

package my_classes;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;


public class MyJTable extends JTable implements TableModelListener {


	public TableCellRenderer getCellRenderer(int row, int column) {
		Object value = getValueAt(row,column);
  		if (value == null) {
  			return getDefaultRenderer(JCheckBox.class);
  		}  
  		return super.getCellRenderer(row,column);
 	}

	public Class getColumnClass(int column) {
		if (column > 2) {
			return Boolean.class;
		} else {
			return Object.class;
		}
	}

	public void tableChanged(TableModelEvent e) {
		int row = e.getFirstRow();
		int column = e.getColumn();
		TableModel model = (TableModel) e.getSource();
		String columnName = model.getColumnName(column);
		Object data = model.getValueAt(row, column);

	}

}

Another option is to have a look at our Table-Bean. It already does most of what you need and if something is missing we will be glad to look at ways of implementing that. But of course, you can also create your own if you really want to spend the time…

Thanks again for your offer, Patrick. I managed to get around the issue by overriding JTable’s isCellEditable method, which is called on every cell click, and therefore functions very nicely as a listener.