问题
I want to implement a scrollable List which is sorted alphabetically. As a reference I am using the Tree Screen sample which comes delivered with the Eclipse IDE.
I changed the datatemplate to fit my needs and it works like a charm until you want to scroll. The whole UI gets messed up and I don't know what to do. I'm using JRE 7.1 and the Blackberry Simulator 9860 7.0 (I've also tested it on a real device).
Does anybody know if this is a known issue or do I miss something?
package lifeApp;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.table.DataTemplate;
import net.rim.device.api.ui.component.table.RegionStyles;
import net.rim.device.api.ui.component.table.SortedTableModel;
import net.rim.device.api.ui.component.table.TableController;
import net.rim.device.api.ui.component.table.TableModel;
import net.rim.device.api.ui.component.table.TableView;
import net.rim.device.api.ui.component.table.TemplateColumnProperties;
import net.rim.device.api.ui.component.table.TemplateRowProperties;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.Border;
import net.rim.device.api.ui.decor.BorderFactory;
import net.rim.device.api.util.StringComparator;
public class ProductsScreen extends MainScreen
{
private SortedTableModel _tableModel;
private static final int ROW_HEIGHT = 40;
public ProductsScreen()
{
super(Manager.NO_VERTICAL_SCROLL | Manager.HORIZONTAL_SCROLL);
setTitle("Alle Produkte A-Z");
add(new LabelField("BlackBerry Devices", LabelField.FIELD_HCENTER));
add(new SeparatorField());
_tableModel = new SortedTableModel(StringComparator.getInstance(true), 0);
_tableModel.addRow(new Object[] {"A", "Produkt1"});
_tableModel.addRow(new Object[] {"b", "Produkt2"});
_tableModel.addRow(new Object[] {"c", "Produkt3"});
_tableModel.addRow(new Object[] {"c", "Produkt4"});
_tableModel.addRow(new Object[] {"b", "Produkt5"});
_tableModel.addRow(new Object[] {"c", "Produkt6"});
_tableModel.addRow(new Object[] {"c", "Produkt7"});
_tableModel.addRow(new Object[] {"r", "Produkt8"});
_tableModel.addRow(new Object[] {"t", "Produkt9"});
_tableModel.addRow(new Object[] {"c", "Produkt10"});
_tableModel.addRow(new Object[] {"b", "Produkt11"});
_tableModel.addRow(new Object[] {"u", "Produkt12"});
_tableModel.addRow(new Object[] {"v", "Produkt13"});
_tableModel.addRow(new Object[] {"t", "Produkt14"});
_tableModel.addRow(new Object[] {"c", "Produkt15"});
_tableModel.addRow(new Object[] {"b", "Produkt16"});
_tableModel.addRow(new Object[] {"u", "Produkt17"});
_tableModel.addRow(new Object[] {"v", "Produkt18"});
RegionStyles style = new RegionStyles(BorderFactory.createSimpleBorder(new XYEdges(1, 1, 1, 1), Border.STYLE_SOLID), null, null,
null, RegionStyles.ALIGN_LEFT, RegionStyles.ALIGN_TOP);
TableView tableView = new TableView(_tableModel);
TableController tableController = new TableController(_tableModel, tableView);
tableController.setFocusPolicy(TableController.ROW_FOCUS);
tableController.setCommand(new Command(new CommandHandler()
{
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Dialog.alert("Command Executed");
}
}));
tableView.setController(tableController);
DataTemplate dataTemplate = new DataTemplate(tableView, 1, 1)
{
/**
* @see DataTemplate#getDataFields(int)
*/
public Field[] getDataFields(int modelRowIndex)
{
final Object[] data = (Object[]) ((TableModel) getView().getModel()).getRow(modelRowIndex);
Field[] fields = new Field[1];
fields[0] = new LabelField((String)data[1], Field.USE_ALL_WIDTH | Field.FOCUSABLE | DrawStyle.HCENTER);
return fields;
}
};
dataTemplate.createRegion(new XYRect(0, 0, 1, 1), style);
dataTemplate.setColumnProperties(0, new TemplateColumnProperties(100, TemplateColumnProperties.PERCENTAGE_WIDTH));
dataTemplate.setRowProperties(0, new TemplateRowProperties(ROW_HEIGHT));
tableView.setDataTemplate(dataTemplate);
dataTemplate.useFixedHeight(true);
add(tableView);
}
}
回答1:
Well, I loaded up the JDE 7.1 UI/TableAndListDemo sample app, and ran it on the JDE 9900.
That sample (unmodified by me) exhibits the exact same screwy behaviour as the code you posted.
So, unfortunately, I would say that either there is a bug, or a valid example of how to use the relatively new SortedTableModel
has not been produced (I couldn't find any better ones).
Of note: if you remove the sorting, and simply replace SortedTableModel
with TableModel
, the visual corruption goes away for me. Of course, you lose the important feature of the sorting, and the grouping (column 0 in your table model).
Another option would be to implement the sorting behaviour yourself. Sorting the data outside of the TableModel
is undesirable, but also not too difficult. Then, you could add an extra row to the repeating pattern, as a placeholder for the separator row that you currently have showing the single character (the sort criterion). You would also change the data template to not be fixed height.
Also, in the data template, you would define a region that can hold the separator row. Whether or not that region will show anything or not depends on whether the data row to follow has the same single character as the last row, or not. So, here's what the code might look like
DataTemplate dataTemplate = new DataTemplate(tableView, 2, 1) // 2 "rows", not 1
{
public Field[] getDataFields(int modelRowIndex)
{
final Object[] data = (Object[]) _tableModel.getRow(modelRowIndex);
Field[] fields = new Field[2];
String rowGroup = (String)data[0];
// we're in a new group if this is the very first row, or if this row's
// data[0] value is different from the last row's data[0] value
boolean isNewGroup = (modelRowIndex == 0) ||
(rowGroup.compareTo((String) ((Object[])_tableModel.getRow(modelRowIndex - 1))[0]) != 0);
if (isNewGroup) {
// make a separator row
fields[0] = new LabelField((String)data[0],
Field.USE_ALL_WIDTH | Field.NON_FOCUSABLE);
} else {
// this is in the same group as the last product, so don't add anything here
fields[0] = new NullField();
}
// now, add the actual product information
fields[1] = new LabelField((String)data[1],
Field.USE_ALL_WIDTH | Field.FOCUSABLE | DrawStyle.HCENTER);
return fields;
}
};
dataTemplate.createRegion(new XYRect(0, 0, 1, 1), style); // group separator (maybe a null field)
dataTemplate.createRegion(new XYRect(0, 1, 1, 1), style); // actual rows with product information
dataTemplate.setColumnProperties(0, new TemplateColumnProperties(100, TemplateColumnProperties.PERCENTAGE_WIDTH));
dataTemplate.setRowProperties(0, new TemplateRowProperties(ROW_HEIGHT)); // separator
dataTemplate.setRowProperties(1, new TemplateRowProperties(ROW_HEIGHT)); // product data
dataTemplate.useFixedHeight(false);
In the above code, I chose to make the separator rows the same height and style as the product data rows. Of course, you could change that if you like.
One problem that this still doesn't solve is that of focus drawing. When you highlight the first row under the separator row, it draws focus on the product row, and the separator row above it.
You may need to implement some custom focus drawing. I'll leave that for the next question ... not sure if you even want to go this route. Hopefully I'm wrong, but it kind of looks like a bug in the RIM libraries to me :(
来源:https://stackoverflow.com/questions/11189109/blackberry-tablemodel-gets-messed-up-when-scrolling