Expanding one field while others are collapsed in blackberry java - java

I am developing an app in which i am adding and deleting fields based on setting flag to true or false.but what i am trying to do is if i click on field that particular field should expand while others are collapsed(even if it is expanded)
i googled it but i didnt get solution please help me i am new to blackberry java
i have used below code
public final class MyScreen extends MainScreen implements
FieldChangeListener
{
/**
* Creates a new MyScreen object
*/
private VerticalFieldManager main_manager;
private HorizontalFieldManager parentNodes;
private LabelField parent_lables[];
private Bitmap bitmap,upbitmap;
private BitmapField bitmap_field[];
private VerticalFieldManager submanager[];
private int sizeOfParentNodes=3;
private int sizeOfChildNodes=5;
private static boolean flag[];
public MyScreen()
{
// Set the displayed title of the screen
bitmap=Bitmap.getBitmapResource("arrow.png");
upbitmap=Bitmap.getBitmapResource("uparrow.png");
main_manager=new
VerticalFieldManager(Manager.VERTICAL_SCROLL|VERTICAL_SCROLLBAR){
protected void sublayout(int maxWidth, int maxHeight) {
super.sublayout(Display.getWidth(), Display.getHeight());
setExtent(Display.getWidth(), Display.getHeight());
};
};
parent_lables=new LabelField[sizeOfParentNodes];
flag=new boolean[sizeOfParentNodes];
submanager=new VerticalFieldManager[sizeOfParentNodes];
bitmap_field=new BitmapField[sizeOfParentNodes];
for(int i=0;i<sizeOfParentNodes;i++)
{
submanager[i]=new VerticalFieldManager();
updateGUI(i);
main_manager.add(submanager[i]);
}
add(main_manager);
}
public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
synchronized (UiApplication.getEventLock()) {
for(int i=0;i<sizeOfParentNodes;i++)
{ if(field==parent_lables[i])
{
if(flag[i]==true){
flag[i]=false;
submanager[i].deleteAll();
updateGUI(i);
parent_lables[i].setFocus();
}else{
flag[i]=true;
bitmap_field[i].setBitmap(upbitmap);
submanager[i].invalidate();
}
}
}
}
}
public void updateGUI(int index)
{
parentNodes=new HorizontalFieldManager(USE_ALL_WIDTH);
bitmap_field[index]=new BitmapField(bitmap);
parentNodes.add(bitmap_field[index]);
parent_lables[index]=new LabelField("Day"+index,Field.FOCUSABLE){
protected boolean navigationClick(int status, int time) {
fieldChangeNotify(1);
return true;
};
};
parentNodes.add(parent_lables[index]);
parent_lables[index].setChangeListener(this);
submanager[index].add(parentNodes);
}
}

I knocked this together, and will likely need some tweaks by you to get it exactly how you want it, but it should be something you can work from. Assuming I've understood your question correctly.
You'll need to create a base field, a helper able to manage a list of them, and a callback. The fact that you need a base field is the biggest downfall, because it immediately excludes all other widgets you have, as they need to be made from scratch with the paint method. You can use a VerticalFieldManager instead of field by extending VerticalFieldManager instead of Field.
On to the java classes.
My CollapsableField.java looks as follows:
public abstract class CollapsableField extends Field
{
// We make use of a different listener than the FieldChangeListener, since you can only attach one and we will most likely want to do so, we can't "occupy" the listener.
private CollapseListener listener;
private boolean collapsed;
protected int collapsedWidth;
protected int collapsedHeight;
public CollapsableField()
{
collapsed = true;
// Field is completely collapsed by default
collapsedWidth = 0;
collapsedHeight = 0;
}
public void setCollapseListener(CollapseListener listener)
{
this.listener = listener;
}
public final boolean isCollapsed()
{
return collapsed;
}
public final void collapse()
{
this.collapsed = true;
if (listener != null)
{
listener.onCollapse(this);
}
fieldChangeNotify(0); // Notify that the field has changed, so that attached field change listeners will fire
updateLayout(); // re-call layout
}
public final void expand()
{
this.collapsed = false;
if (listener != null)
{
listener.onExpand(this);
}
fieldChangeNotify(0); // Notify that the field has changed, so that attached field change listeners will fire
updateLayout(); // re-call layout
}
protected void layout(int width, int height)
{
if (collapsed)
{
// Set dimensions to collapsed
setExtent(collapsedWidth, collapsedHeight);
}
else
{
// Set dimensions to what the extending class specified
setExtent(width, height);
}
}
protected final void paint(Graphics graphics)
{
if (collapsed)
{
paintCollapsed(graphics);
}
else
{
paintExpanded(graphics);
}
}
protected abstract void paintCollapsed(Graphics graphics);
protected abstract void paintExpanded(Graphics graphics);
}
The Group then takes a list of these, applies a listener to each field as it's added. When a field signals that it has expanded, the group will tell all other fields to collapse themselves.
CollapsableGroup.java:
public class CollapsableGroup
{
private Vector fields;
private CollapseListener listener;
public CollapsableGroup()
{
fields = new Vector();
listener = new CollapseListener()
{
public void onExpand(CollapsableField source)
{
for (int i = 0; i < fields.size(); i++)
{
CollapsableField field = (CollapsableField) fields.elementAt(i);
if ((!field.isCollapsed()) && (field != source))
{
field.collapse();
}
}
}
public void onCollapse(CollapsableField source)
{
// Don't need to handle this. Method is here just for completeness
}
};
}
public void add(CollapsableField field)
{
field.setCollapseListener(listener);
fields.addElement(field);
}
public void remove(CollapsableField field)
{
field.setCollapseListener(null);
fields.removeElement(field);
}
/**
* Returns the currently expanded field. Returns <b>null</b> if all fields are collapsed.
*
* #return
*/
public CollapsableField getExpandedField()
{
for (int i = 0; i < fields.size(); i++)
{
CollapsableField field = (CollapsableField) fields.elementAt(i);
if (!field.isCollapsed())
{
return field;
}
}
return null;
}
public void expand(CollapsableField field)
{
field.expand(); // Listeners should take care of the rest
}
public void collapseAll()
{
for (int i = 0; i < fields.size(); i++)
{
CollapsableField field = (CollapsableField) fields.elementAt(i);
if (!field.isCollapsed())
{
field.collapse();
}
}
}
}
And finally the listener interface.
CollapseListener.java:
interface CollapseListener
{
public void onExpand(CollapsableField source);
public void onCollapse(CollapsableField source);
}
Those three classes should be all that you need. The classes that follow are my example/test classes.
TestLabel.java is an example of an extended class:
public class TestLabel extends CollapsableField
{
private String text;
private String collapsedText;
public TestLabel(String text, String collapsedText)
{
this.text = text;
this.collapsedText = collapsedText;
// Tells the layout method to collapse to the size of this text
collapsedWidth = getFont().getAdvance(collapsedText);
collapsedHeight = getFont().getHeight();
}
public int getPreferredWidth()
{
return getFont().getAdvance(text);
}
public int getPreferredHeight()
{
return getFont().getHeight();
}
protected void layout(int width, int height)
{
super.layout(getPreferredWidth(), getPreferredHeight());
}
protected void paintCollapsed(Graphics graphics)
{
// Paints only the collapsedText
graphics.drawText(collapsedText, 0, 0);
}
protected void paintExpanded(Graphics graphics)
{
// Paints the full Text
graphics.drawText(text, 0, 0);
}
protected boolean touchEvent(TouchEvent message)
{
// Toggle on mouse press
if (message.getEvent() == TouchEvent.CLICK)
{
if (isCollapsed())
{
expand();
}
else
{
collapse();
}
return true;
}
return super.touchEvent(message);
}
}
The following screen contains some of the fields to show that both the widgets themselves and the group can manipulate the fields.
MyScreen.java:
public final class MyScreen extends MainScreen
{
public MyScreen()
{
// Set the displayed title of the screen
setTitle("MyTitle");
final CollapsableGroup group = new CollapsableGroup();
final TestLabel label1 = new TestLabel("Label1", "L1");
label1.setBackground(BackgroundFactory.createSolidBackground(0x999999));
group.add(label1);
final TestLabel label2 = new TestLabel("Label2", "L2");
label2.setBackground(BackgroundFactory.createSolidBackground(0xBBBBBB));
group.add(label2);
final TestLabel label3 = new TestLabel("Label3", "L3");
label3.setBackground(BackgroundFactory.createSolidBackground(0xDDDDDD));
group.add(label3);
ButtonField collapseAll = new ButtonField("Collapse All")
{
protected boolean navigationClick(int status, int time)
{
group.collapseAll();
return true;
}
};
add(collapseAll);
ButtonField expand1 = new ButtonField("Expand1")
{
protected boolean navigationClick(int status, int time)
{
group.expand(label1);
return true;
}
};
add(expand1);
ButtonField expand2 = new ButtonField("Expand2")
{
protected boolean navigationClick(int status, int time)
{
group.expand(label2);
return true;
}
};
add(expand2);
ButtonField expand3 = new ButtonField("Expand3")
{
protected boolean navigationClick(int status, int time)
{
group.expand(label3);
return true;
}
};
add(expand3);
add(label1);
add(label2);
add(label3);
}
}

Related

Custom JSpinner Model not working

I tried to implement my own JSpinner model to accept an enumeration (including I18N), so I did like that:
searchSpinner.setModel(new AbstractSpinnerModel() {
int index = 0;
int minIndex = 0;
int maxIndex = MY_ENUM.values().length - 1;
Object selected = MY_ENUM.values()[index];
#Override
public Object getValue() {
return selected;
}
#Override
public void setValue(Object value) {
selected = value;
fireStateChanged();
}
#Override
public Object getNextValue() {
if (index < maxIndex) {
index++;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public Object getPreviousValue() {
if (index > minIndex) {
index--;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public void addChangeListener(ChangeListener l) {
}
#Override
public void removeChangeListener(ChangeListener l) {
}
});
The problem is that did not work, and even the spinner list looks like disabled. What am I doing wrong?
UPDATE: Based on first answer
You should extend from AbstractSpinnerModel (note to folks new to his question -- note that his original question had the class implementing the SpinnerModel interface. He later changed his code to reflect my recommendation) and be sure to call the fireStateChanged() method when appropriately. Also you've not taken into account edge cases and beyond edge cases.
e.g.,
import javax.swing.*;
import javax.swing.JSpinner.DefaultEditor;
public class MySpinnerPanel extends JPanel {
public static void main(String[] args) {
JSpinner spinner = new JSpinner(new MyEnumSpinnerModel());
JSpinner.DefaultEditor editor = (DefaultEditor) spinner.getEditor();
editor.getTextField().setColumns(5);
JPanel panel = new JPanel();
panel.add(spinner);
JOptionPane.showMessageDialog(null, panel);
}
}
enum MyEnum {
FE, FI, FO, FUM, FOO, FUBAR, SPAM
}
class MyEnumSpinnerModel extends AbstractSpinnerModel {
private int index = 0;
#Override
public Object getValue() {
return MyEnum.values()[index];
}
#Override
public void setValue(Object value) {
if (value instanceof MyEnum) {
index = ((MyEnum) value).ordinal();
fireStateChanged();
} else {
String text = value.toString() + " is not a valid enum item";
throw new IllegalArgumentException(text);
}
}
#Override
public Object getNextValue() {
if (index >= MyEnum.values().length - 1) {
return null;
} else {
return MyEnum.values()[index + 1];
}
}
#Override
public Object getPreviousValue() {
if (index <= 0) {
return null;
} else {
return MyEnum.values()[index - 1 ];
}
}
}
Edit
Note that the model itself should not require a listener to notify the view (as per the other answer to this question) as that's what the AbstractSpinnerModel does internally. It's fireStateChange() method is what the model itself should call to trigger this notification, same as most all other similar model structures in Swing such as any TableModel object that you create that derives from the AbstractTableModel. For details, please see the source code for the SpinnerListModel. Your code should emulate this class.
You should use ChangeListener to notify the view of changes in the model.
spinner = new JSpinner(new SpinnerModel() {
private ChangeListener l;
#Override
public void setValue(Object value) {
...
if(l != null) {
l.stateChanged(new ChangeEvent(this));
}
}
...
#Override
public void addChangeListener(ChangeListener l) {
this.l = l;
}
#Override
public void removeChangeListener(ChangeListener l) {
if(this.l == l) {
this.l = null;
}
}
});
Edit: You can use List to register many listeners.

Windows alignment in SWING-based GUI

My goal is to display several views of one object. For each view I create a thread. Also, I have a class which controls those views, e.g. send a command to align them. However, it is not always I get correct alignment. So there is a data races, and I cannot understand what I am doing wrong.
Here there is a piece of code showing the problem I have. It has a simple idea: create a main view window, and then align the second window of the same size near its right border.
First, I have an abstract class to create a thread:
public abstract class ViewWindow implements Runnable{
private Thread thread;
private boolean terminate = false ;
private Controller controller;
private UpdateTask currentUpdateTask = null;
private class UpdateTask {
boolean alignWindows = true;
}
public ViewWindow(Controller controller, String title) {
this.title = title;
this.controller = controller;
}
public void startThread() {
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
UpdateTask updateTask = null;
synchronized (thread) {
while (terminate == false) {
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
updateTask = currentUpdateTask;
currentUpdateTask = null;
if(updateTask.alignWindows) {
controller.getLock().lock();
setLocationRelativeTo(controller.getMainWindow());
controller.getLock().unlock();
}
}
}
}
public void alignWindowsUsingThread() {
synchronized (thread) {
currentUpdateTask = new UpdateTask();
thread.notify();
}
}
public abstract void setLocationRelativeTo(ImageViewWindow imageWindow);
}
Then I extend it to create an abstraction for the window views:
public abstract class ImageViewWindow extends ViewWindow {
private JFrame frame;
public ImageViewWindow(Controller controller, String title) {
super(controller, title);
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel(title);
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(300,500));
frame.pack();
frame.setVisible(true);
}
public JFrame getFrame() {
return frame;
}
synchronized public void setLocation(int x, int y) {
frame.setLocation(x, y);
}
synchronized public Point getLocation() {
return frame.getLocation();
}
}
Finally, I override a function to set relative location for each window:
public class FirstWindow extends ImageViewWindow {
public FirstWindow(Controller controller, String title) {
super(controller, title);
this.setLocation(50, 50);
this.startThread();
}
#Override
public void setLocationRelativeTo(ImageViewWindow imageWindow) { }
}
public class SecondWindow extends ImageViewWindow {
public SecondWindow(Controller controller, String title) {
super(controller, title);
this.startThread();
}
#Override
public void setLocationRelativeTo(ImageViewWindow imageWindow) {
Point location = imageWindow.getLocation();
int xOffSet = imageWindow.getFrame().getWidth();
int yOffSet = 0;
this.setLocation(xOffSet + location.x, yOffSet + location.y);
}
}
Here there is a class which is responsible for the control:
public class Controller {
private Lock controlLock;
private List<ImageViewWindow> windows = new ArrayList<ImageViewWindow>();
private ImageViewWindow mainWindow;
public Controller() {
controlLock = new ReentrantLock();
}
public ImageViewWindow getMainWindow() {
return mainWindow;
}
public Lock getLock() {
return controlLock;
}
public void addMainWindow(ImageViewWindow mainViewWindow) {
this.mainWindow = mainViewWindow;
this.addWindow(mainViewWindow);
}
public void addWindow(ImageViewWindow imageWindow) {
windows.add(imageWindow);
}
public void updateWindowPositions() {
for(ImageViewWindow window : windows) {
window.alignWindowsUsingThread();
}
}
}
And do run everything:
public class Start {
public static void main(String[] args) {
Controller controller = new Controller();
ImageViewWindow window1 = new FirstWindow(controller, "FirstWindow");
controller.addMainWindow(window1);
ImageViewWindow window2 = new SecondWindow(controller, "SecondWindow");
controller.addWindow(window2);
controller.updateWindowPositions();
}
}
UPD: I updated the code based on the answer below, but the problem still remains!
You don’t specify how you want to “align” your windows but from your code
public void setLocationRelativeTo(ImageViewWindow imageWindow) {
Point location = imageWindow.getLocation();
int xOffSet = this.getFrame().getWidth();
int yOffSet = 0;
this.setLocation(xOffSet + location.x, yOffSet + location.y);
}
I suppose you want this to be placed to the right of imageWindow. In this case you have to use imageWindow.x + imageWindow.width rather than imageWindow.x + this.width:
| imageWindow | this
x ← width → x ← width →
↳=imageWindow.x+imageWindow.width
So the correct method would be:
public void setLocationRelativeTo(ImageViewWindow imageWindow) {
Point location = imageWindow.getLocation();
int xOffSet = imageWindow.getFrame().getWidth();
int yOffSet = 0;
this.setLocation(xOffSet + location.x, yOffSet + location.y);
}
By the way, I don’t get why you are making such a simple task that complicated and even multi-threaded. There’s no benefit from multi-threading here, only a complication that obstructs the view on the simplest things…

Java JTable detect Column re-sized by user

I have a JTable that is using a TableColumnModelListener() to detect when the column has been re-sized and I have some code I want to execute in the columnMarginChanged() method.
How do I determine whether the column was re-sized by the user or as a result of other code?
I am thinking I have to start with ChangeEvent.getSource() but I don't know where to go from there.
Thank you.
I can give you one possible approach. I was trying to solve the same problem, because I wanted to serialize information about column widths to disk, so that the next time the table opened up in my application, I could restore the column widths appropriately. Here goes:
Step 1 - Override your JTable and add a boolean property to it
class MyTable extends JTable {
private boolean isColumnWidthChanged;
public boolean getColumnWidthChanged() {
return isColumnWidthChanged;
}
public void setColumnWidthChanged(boolean widthChanged) {
isColumnWidthChanged = widthChanged;
}
}
Step 2 - Add a TableColumnModelListener() to the table
private class TableColumnWidthListener implements TableColumnModelListener
{
#Override
public void columnMarginChanged(ChangeEvent e)
{
/* columnMarginChanged is called continuously as the column width is changed
by dragging. Therefore, execute code below ONLY if we are not already
aware of the column width having changed */
if(!tableObj.hasColumnWidthChanged())
{
/* the condition below will NOT be true if
the column width is being changed by code. */
if(tableObj.getTableHeader.getResizingColumn() != null)
{
// User must have dragged column and changed width
tableObj.setColumnWidthChanged(true);
}
}
}
#Override
public void columnMoved(TableColumnModelEvent e) { }
#Override
public void columnAdded(TableColumnModelEvent e) { }
#Override
public void columnRemoved(TableColumnModelEvent e) { }
#Override
public void columnSelectionChanged(ListSelectionEvent e) { }
}
Step 3 - Add a mouse listener to the table header
private class TableHeaderMouseListener extends MouseAdapter
{
#Override
public void mouseReleased(MouseEvent e)
{
/* On mouse release, check if column width has changed */
if(tableObj.getColumnWidthChanged())
{
// Do whatever you need to do here
// Reset the flag on the table.
tableObj.setColumnWidthChanged(false);
}
}
}
NOTE: In my application, the TableHeaderMouseListener and TableColumnWidthListener classes were private inner classes of my main application class. My main application class held on to a reference of the table being observed. Therefore, these inner classes had access to the table instance. Obviously, depending on your setup, you need to do the appropriate thing to make the table instance available to these other classes. Hope this helps!
Typically you want to be notified of a completed column drag, or a completed column resize. E.g.
interface SGridModel {
public void columnMoved(int oldLocation, int newLocation);
public void columnResized(int column, int newWidth);
}
This isn't pretty but it will do what you want:
class SColumnListener extends MouseAdapter implements TableColumnModelListener {
private final Logger log = Logger.getLogger(getClass());
private final SGridModel model;
private int oldIndex = -1;
private int newIndex = -1;
private boolean dragging = false;
private boolean resizing = false;
private int resizingColumn = -1;
private int oldWidth = -1;
SColumnListener(SGridModel model){
this.model = model;
}
#Override
public void mousePressed(MouseEvent e) {
// capture start of resize
if(e.getSource() instanceof JTableHeader) {
TableColumn tc = ((JTableHeader)e.getSource()).getResizingColumn();
if(tc != null) {
resizing = true;
resizingColumn = tc.getModelIndex();
oldWidth = tc.getPreferredWidth();
} else {
resizingColumn = -1;
oldWidth = -1;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
// column moved
if(dragging && oldIndex != newIndex) {
model.columnMoved(oldIndex, newIndex);
log.info("column moved: " +oldIndex+" -> "+newIndex);
}
dragging = false;
oldIndex = -1;
newIndex = -1;
// column resized
if(resizing) {
if(e.getSource() instanceof JTableHeader) {
TableColumn tc = ((JTableHeader)e.getSource()).getColumnModel().getColumn(resizingColumn);
if(tc != null) {
int newWidth = tc.getPreferredWidth();
if(newWidth != oldWidth) {
model.columnResized(resizingColumn, newWidth);
log.info("column resized: " +resizingColumn+" -> "+newWidth);
}
}
}
}
resizing = false;
resizingColumn = -1;
oldWidth = -1;
}
#Override
public void columnAdded(TableColumnModelEvent e) {
}
#Override
public void columnRemoved(TableColumnModelEvent e) {
}
#Override
public void columnMoved(TableColumnModelEvent e) {
// capture dragging
dragging = true;
if(oldIndex == -1){
oldIndex = e.getFromIndex();
}
newIndex = e.getToIndex();
}
#Override
public void columnMarginChanged(ChangeEvent e) {
}
#Override
public void columnSelectionChanged(ListSelectionEvent e) {
}
}
add it to the table as follows:
table.getColumnModel().addColumnModelListener(cl);
table.getTableHeader().addMouseListener(cl);
A simpler solution might just be to listen on the mouse release event (which happens only once in this user interaction) and check if the column-sizes changed in the meantime ? I'm using the code below to listen for column reordering and size changes.
getTableHeader().addMouseListener( new MouseAdapter() {
public void mouseReleased(MouseEvent arg0)
{
String colNamesAndSizes = "";
for( int i=0;i<getColumnModel().getColumnCount();i++ ) {
if( i>0 ) colNamesAndSizes += ",";
TableColumn column = getColumnModel().getColumn(i);
colNamesAndSizes += column.getHeaderValue();
colNamesAndSizes += ":";
colNamesAndSizes += column.getWidth();
}
// check if changed, if yes, persist...
}});
You can also add PropertyChangeListener on each TableColumn to capture changes on width and preferredWidth properties.

Selection and hover overrides Cell background color in an SWT Table component

I'm using SWT (and Eclipse RCP) to render a table. My problem is that if I change the background of a cell (a ViewerCell in fact) I can see that it has the new color.
My problem is that if I select a row in my Table or if I hover over the row containing my cell in question then the selection/hover background overrides my cell color. How can I override this?
Problem solved with StyledCellLabelProvider. Tell me if you want to see some code.
Edit:
We use it do display validation errors so ignore the validation stuff here:
public class ValidationCellLabelProvider extends StyledCellLabelProvider {
private static final int DELAY = 200;
private static final int SHIFT_X = 5;
private static final int SHIFT_Y = 5;
private static final int DISPLAY = 5000;
private CellLabelProvider provider;
private String propertyName;
private final StyleRange[] styleRanges = new StyleRange[1];
/**
* Default constructor.
* #param provider provider
* #param propertyName propertyName
*/
public ValidationCellLabelProvider(CellLabelProvider provider, String propertyName) {
super(StyledCellLabelProvider.COLORS_ON_SELECTION);
this.provider = provider;
this.propertyName = propertyName;
this.setOwnerDrawEnabled(true);
}
#Override
public void initialize(ColumnViewer viewer, ViewerColumn column) {
super.initialize(viewer, column);
final StyleRange styleRange = new StyleRange();
styleRange.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
styleRange.background = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
styleRanges[0] = styleRange;
}
#Override
public void update(ViewerCell cell) {
provider.update(cell);
if (cell.getStyleRanges() == null) {
cell.setStyleRanges(styleRanges);
}
if (cell.getElement() instanceof IValidable) {
IValidable model = (IValidable) cell.getElement();
if (!ControllerRegistry.getCurrentViolations().getViolations(model.getModelId(), propertyName).isEmpty()) {
if (cell.getText().isEmpty()) {
cell.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
cell.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage());
} else {
if (styleRanges[0].length < cell.getText().length()) {
styleRanges[0].length = cell.getText().length();
}
}
} else {
if (cell.getImage() != null) {
cell.setImage(null);
}
cell.setStyleRanges(null);
}
}
super.update(cell);
}
//mine
#Override
protected void paint(Event event, Object element) {
if (element instanceof IValidable) {
IValidable model = (IValidable) element;
if (!ControllerRegistry.getCurrentViolations().getViolations(model.getModelId(), propertyName).isEmpty()) {
int width = 1000;
int x = event.x;
int y = event.y;
int height = event.height - 1;
GC gc = event.gc;
Color oldBackground = gc.getBackground();
gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
gc.fillRectangle(x, y, width, height);
gc.setBackground(oldBackground);
}
}
super.paint(event, element);
}
//-----
#Override
public String getToolTipText(Object element) {
String ret = null;
if (element instanceof IValidable) {
List<ConstraintViolation> constraintViolations = ControllerRegistry.getCurrentViolations().getViolations(
((IValidable) element).getModelId(), propertyName);
if (!constraintViolations.isEmpty()) {
ret = ValidationHelper.getMessage(constraintViolations);
}
}
if (ret != null) {
ret = ret.length() > 0 ? ret.toString() : null;
}
return ret;
}
#Override
public int getToolTipDisplayDelayTime(Object object) {
return DELAY;
}
#Override
public Point getToolTipShift(Object object) {
return new Point(SHIFT_X, SHIFT_Y);
}
#Override
public int getToolTipTimeDisplayed(Object object) {
return DISPLAY;
}
}
The only option I see would be use an OwnerDrawLabelProvider and paint the whole cell yourself.
There is a way to prevent the table from drawing its selection background but the font color will still change to its selection color, so depending on your OS you might end up with white text on white background when a row is selected.

Customize listfield item on BlackBerry

I have a simple list field class which shows the default menu when I select a particular listitem. I want to customize the listfield item, so that when an item is selected a new screen is pushed onto the stack. I am overridding trackwheeel() method, but am not able to make it work.
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import java.util.Vector;
public class TeamListScreen extends UiApplication
{
public static void main(String[] args)
{
TeamListScreen theApp = new TeamListScreen();
theApp.enterEventDispatcher();
}
public TeamListScreen()
{
pushScreen(new ListFieldScreen());
}
}
class ListFieldScreen extends MainScreen
{
private ListField _listField;
private Vector _listElements;
int listFieldIndex = -1;
public ListFieldScreen()
{
setTitle("List Field Sample");
_listElements = new Vector();
_listField = new ListField();
ListCallback _callback = new ListCallback();
_listField.setCallback(_callback);
_listField.setRowHeight(45);
//_listField.setChangeListener(this);
add(_listField);
initializeList();
_listField = new ListField(_listElements.size()) {
protected void drawFocus(Graphics graphics, boolean on) {
}
protected boolean trackwheelClick(int status, int time) {
listFieldIndex = _listField.getSelectedIndex();
if (listFieldIndex < 0) {
listFieldIndex = 0;
}
try {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new LiveScreen());
// UiApplication.getUiApplication().popScreen(getActiveScreen());
}
});
} catch (Exception e) {
}
return true;
}
};
}
private void initializeList()
{
String itemOne = "List item one";
String itemTwo = "List item two";
_listElements.addElement(itemOne);
_listElements.addElement(itemTwo);
reloadList();
}
private void reloadList()
{
_listField.setSize(_listElements.size());
}
private class ListCallback implements ListFieldCallback
{
public void drawListRow(ListField list, Graphics g, int index, int y, int w)
{
String text = (String)_listElements.elementAt(index);
g.drawText(text, 0, y, 0, w);
}
public Object get(ListField list, int index)
{
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string)
{
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list)
{
return Display.getWidth();
}
}
}
trackwheelClick() function is deprecated, you should use navigationClick() instead.
BTW, you don't need to use UiApplication.getUiApplication().invokeLater, because it is already running in the event queue.

Categories