How do I create a RichTextEdit using RIM 4.5 API that contains text with multiple colors?
For example I want to create a RichTextEdit as follows:
The Text is "Hello BB world"
"Hello" should be blue
"BB world" should be red
"BB" should be ITALIC
"Hello" should be BOLD
The main problem is getting colors, not the bold and italic.
I have tried overriding RichTextEdit.paint function, but this formats the color of the whole string, not just a substring of it!
Here's the code I implemented to make the text bold and italic and overriding the paint to change the whole string color:
public final class RichTextFieldSample extends UiApplication
{
public static void main(String[] args)
{
RichTextFieldSample theApp = new RichTextFieldSample();
theApp.enterEventDispatcher();
}
public RichTextFieldSample()
{
String richText = "This is how you create text with formatting!!!";
Font fonts[] = new Font[3];
int[] offset = new int[4];
byte[] attribute = new byte[3];
fonts[0] = Font.getDefault();
fonts[1] = Font.getDefault().derive(Font.BOLD);
fonts[2] = Font.getDefault().derive(Font.BOLD | Font.ITALIC);
offset[0] = 0;
attribute[0] = 2;
offset[1] = 4;
attribute[1] = 0;
offset[2] = 33;
attribute[2] = 1;
offset[3] = richText.length();
RichTextField rtField = new RichTextField
(richText, offset, attribute, fonts,
RichTextField.USE_TEXT_WIDTH) {
protected void paint(Graphics graphics) {
graphics.clear();
graphics.setColor(0x0000FF);
super.paint(graphics);
}
};
MainScreen mainScreen = new MainScreen();
mainScreen.setTitle(new LabelField
("RichTextFieldSample Sample",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH));
mainScreen.add(rtField);
pushScreen(mainScreen);
}
}
Unfortunately no easy answer to this one. According to this post, RichTextField doesn't support multiple colors (despite the presence of a getForegroundColors method).
It may be possible to extend RichTextField to support multiple colors, but with the amount of work necessary, it would very likely be easier to implement your own Field from scratch.
Related
I am trying to create a set of FAQ questions and answers using a bunch of LabelFields in a VFM. Issue is that when I try to scroll, it jumps to the bottom of the list and doesn't show the mid-section questions.
public class HelpTab implements ITabAreaLayout, ScrollChangeListener {
public String[] GetQandAs() {
String[] QandAs = new String[22];
QandAs[0] = "Q. ....";
QandAs[1] = "A. ....";
....
....
QandAs[20] = "Q. ...";
QandAs[21] = "A. ....";
return QandAs;
}
VerticalFieldManager _vfm;
public VerticalFieldManager GetLayout() {
_vfm = new VerticalFieldManager(Field.FIELD_LEFT
| Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR);
_vfm.add(UIElements.GetTitleArea(" ? FAQ"));
String[] QandAs = GetQandAs();
for (int i = 0; i < QandAs.length; i++) {
LabelField lblQandA = null;
if ((i % 2) == 0) {
lblQandA = UIElements.GetQuestionLabel(QandAs[i]);
} else {
lblQandA = UIElements.GetAnswerLabel(QandAs[i]);
}
_vfm.add(lblQandA);
}
_vfm.add(new NullField(NullField.FOCUSABLE)); // for scrolling
return _vfm;
}
public void scrollChanged(Manager manager, int newHorizontalScroll,
int newVerticalScroll) {
if (_vfm != null){
_vfm.setVerticalScroll(newVerticalScroll);
}
}
public class HomeScreen extends MainScreen
{
public HomeScreen() {
super(Manager.FIELD_HCENTER | Screen.NO_VERTICAL_SCROLL);
_vfmMain = new VerticalFieldManager();
// add header image
_vfmMain.add(UIElements
.GetBitmapField(UIElements.IMG_HEADER, false));
// add tab strip
_vfmMain.add(MakeTabStrip());
add(_vfmMain);
_vfmTabArea = new HelpTab().GetLayout();
add(_vfmTabArea);
}
}
I was not able to find much help on setVerticalScroll usage, maybe that is the reason for this issue.
Please advise.
Thanks
In your code, you added the focusable null field at the end position of the loop. so if you scroll, it will goto the last element. If you add the focusable field to- After first question, then after second question, ..... so it will scroll one by one.
Try This code -
for (int i = 0; i < QandAs.length; i++) {
LabelField lblQandA = null;
if ((i % 2) == 0) {
lblQandA = UIElements.GetQuestionLabel(QandAs[i]);
} else {
lblQandA = UIElements.GetAnswerLabel(QandAs[i]);
}
_vfm.add(lblQandA);
_vfm.add(new NullField(NullField.FOCUSABLE)); //after each element, add a focusable null field.
}
As Signare has pointed out, the issue here is probably related to your LabelFields not being focusable, which are they are not by default. One answer is to add NullFields as has been suggested. However I suspect you actually want these to be focusable, so the user can click on the one they would like more information on. So make your LabelFields Focusable, by setting the style, for example
LabelField lab = new LabelField("Label", LabelField.FOCUSABLE);
Alternatively, and to my mind preferably, use RichTextField instead of LabelField. This will give you scrolling line by line, LabelField focuses on the whole text.
I am trying to achieve a flat look for blackberry controls, namely objectchoicefield and buttonfield.
The following code does not seem to do the trick. (The width setting does work, but not the border setting.)
public static ObjectChoiceField GetDropdownList(String label, String[] data)
{
ObjectChoiceField ocf = new ObjectChoiceField(null, data, 0, Field.FIELD_LEFT);
ocf.setBorder(BorderFactory.createSimpleBorder(new XYEdges(0,0,0,0)));
ocf.setMinimalWidth(Display.getWidth()-61);
return ocf;
}
I get the same appearance with or without the setBorder statement. Basically I do not want any 3D look or shadow or shine or rounded corners.
Thanks
This might not do everything you want, but you can try looking at this custom ObjectChoiceField that I built for OS 4.6 and lower devices. I wanted to add a glossy, 3D look, but you could change the custom paint() code I used to make a simpler, flatter look.
Taking my example, changing the rounded corner radius to 1, and removing the call to super.paint(g) gives something like this:
public class CustomChoiceField extends ObjectChoiceField {
private int _bgWidth = 0;
private int _bgHeight = 0;
private int _numChoices = 0;
private boolean _hasFocus = false;
private static final int HIGHLIGHT_COLOR = 0xFF185AB5; // blue-ish
private static final int RADIUS = 1; // rounded corner radius in pixels
private static final int DFLT_PADDING = 20;
public CustomChoiceField(Object[] choices, int initialIndex) {
super("", choices, initialIndex);
_numChoices = choices.length;
}
public int getPreferredHeight() {
return _bgHeight;
}
public int getPreferredWidth() {
return _bgWidth;
}
protected void layout(int width, int height) {
if (_bgWidth == 0 || _bgHeight == 0) {
if (height <= Display.getHeight()) {
// probably using custom Manager to specify size
_bgWidth = width;
_bgHeight = height;
} else {
// use default sizing
_bgHeight = DFLT_PADDING + getHeightOfChoices();
for (int i = 0; i < _numChoices; i++) {
_bgWidth = Math.max(_bgWidth, DFLT_PADDING + getWidthOfChoice(i));
}
}
}
super.layout(_bgWidth, _bgHeight);
super.setExtent(_bgWidth, _bgHeight);
}
protected void applyTheme(Graphics arg0, boolean arg1) {
// do nothing
}
protected void drawFocus(Graphics g, boolean on) {
// do nothing .. handled manually in paint(g)
}
protected void onFocus(int direction) {
_hasFocus = true;
super.onFocus(direction);
invalidate();
}
protected void onUnfocus() {
_hasFocus = false;
super.onUnfocus();
invalidate(); // required to clear focus
}
protected void paint(Graphics g) {
int oldColor = g.getColor();
// field color depends on whether we have focus or not
int bgColor = (_hasFocus) ? HIGHLIGHT_COLOR : Color.BLACK;
// when the field has focus, we make it a little less transparent
int alpha = (_hasFocus) ? 0xDD : 0xBB;
g.setColor(bgColor);
g.setGlobalAlpha(alpha);
g.fillRoundRect(0, 0, _bgWidth, _bgHeight, RADIUS, RADIUS);
// draw a plain white line as a border
g.setColor(Color.WHITE);
g.setGlobalAlpha(0xFF);
g.drawRoundRect(0, 0, _bgWidth, _bgHeight, RADIUS, RADIUS);
// draw the currently selected choice's text (also in white)
String text = (String)getChoice(getSelectedIndex());
int y = (_bgHeight - getFont().getHeight()) / 2;
g.drawText(text, 0, y, DrawStyle.HCENTER | DrawStyle.TOP, _bgWidth);
g.setColor(oldColor);
}
}
And you use the CustomChoiceField like this:
private ObjectChoiceField[] ocf = new ObjectChoiceField[3];
public ObjectChoiceScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
Object[] choices1 = new Object[] { "one", "two", "three" };
ocf[0] = new CustomChoiceField(choices1, 0);
Object[] choices2 = new Object[] { "ichi", "ni", "san" };
ocf[1] = new CustomChoiceField(choices2, 0);
Object[] choices3 = new Object[] { "uno", "dos", "tres" };
ocf[2] = new CustomChoiceField(choices3, 0);
for (int i = 0; i < ocf.length; i++) {
ocf[i].setMargin(new XYEdges(10, 10, 10, 10));
}
getMainManager().addAll(ocf);
This isn't production code, so you'll need to test it yourself. For example, it doesn't handle changing the choices with setChoices(). But, it's a start, and will get you something like this:
You'll notice the difference in color between the first two object choice fields, and the bottom one, which is focused.
My code has the same popup for selecting choices as the normal ObjectChoiceField. So, you still may get rounded corners that way. In my case, I didn't need to change that look and feel, so I'm not sure how you might change that, too.
I have an issue with Blackberry 5 & 6 Os on simulator
The label field becomes clumsy when i set the font
the same runs fine in Blackberry 7
here is my sample code
LabelField _lblTitle3 =
new LabelField(offerStatus,
USE_ALL_WIDTH | Field.FIELD_VCENTER |
LabelField.ELLIPSIS | Field.NON_FOCUSABLE) {
protected void drawFocus(Graphics graphics, boolean on) {
};
protected void paintBackground(Graphics graphics) {
String offerStatus = _offerObj.getCategoryStatus();
int color;
if (offerStatus.equalsIgnoreCase("Saved"))
color = Color.BLUE;
else if (offerStatus.equalsIgnoreCase("Accepted!"))
color = Color.GREEN;
else
color = Color.BLACK;
if (_isFocus) {
graphics.setColor(Color.WHITE);
} else {
graphics.setColor(color);
}
super.paint(graphics);
};
};
Font myFont = Font.getDefault();
FontFamily typeface = FontFamily.forName("Times New Roman");
int fType = Font.BOLD
int fSize = 12
myFont = typeface.getFont(fType, fSize);
_lblTitle3.setFont(myFont);
Image is below
What are you trying to do? Just change the font color?
If so, you probably don't want to override paintBackground().
Inside your implementation of paintBackground(), you are calling super.paint(). I'm not sure what that would do, but it wouldn't surprise me if that was wrong.
paint() and paintBackground() are two separate things.
If you just want to change the font color, depending on the text and the focus state, just put that logic in the paint() method, and leave paintBackground() alone (don't override it).
Also, when you change the Graphics context, to do things like set a new color, it's usually safer to store the old color first, and reset it later. Something like this:
protected void paint(Graphics graphics) {
int oldColor = graphics.getColor();
String offerStatus = _offerObj.getCategoryStatus();
int color;
if (offerStatus.equalsIgnoreCase("Saved"))
color = Color.BLUE;
else if (offerStatus.equalsIgnoreCase("Accepted!"))
color = Color.GREEN;
else
color = Color.BLACK;
if (_isFocus) {
graphics.setColor(Color.WHITE);
} else {
graphics.setColor(color);
}
super.paint(graphics);
graphics.setColor(oldColor);
};
I took one custom text box image, in that text box I want to show "Enter password" and when I focus on to that text box field and enter any charectors it converts to asterisk symbols like password edit field.
I want like this below Image:
I think it is possible by only overriding paint(..) of the Editfield. May be following steps can achieve the desired behaviour:
Store original text to a local variable.
Generate fake text depending on focus status, original text etc.
Call super.paint(..), it will paint the field with fake text.
Use setText(..) to set original text back.
Draft implementation:
class MyEditField extends EditField {
private final static String INIT_TEXT = "Enter Password";
protected void paint(Graphics graphics) {
String originalText = getText();
String fakeText = originalText;
if (originalText.equalsIgnoreCase("")) {
fakeText = isFocus() ? originalText : INIT_TEXT;
} else {
fakeText = "";
for (int i=0;i<originalText.length();i++) {
fakeText += '*';
}
}
setText(fakeText);
super.paint(graphics);
setText(originalText);
}
}
Above code doesn't paint a border.
We need to set a monochrome font for the problem you have mentioned in comment. Here is a sample code:
MyEditField me = new MyEditField();
try {
Font font = null;
FontFamily fontFamily[] = FontFamily.getFontFamilies();
for (int i=0;i<fontFamily.length; i++) {
if (fontFamily[i].getName().equalsIgnoreCase("Courier New")) {
font = fontFamily[i].getFont(FontFamily.SCALABLE_FONT,
Font.getDefault().getHeight());
me.setFont(font);
break;
}
}
} catch (Exception e) {
}
If I understand you correctly, you need to use a PasswordEditField.
Implement it just like any LabelField, and it will do what you need.
I see you wanted the background text too - I would use drawText() from within the paint() method to draw that. The other answer that shows a full implementation by using EditField is also good.
here is my code and through the source code is not available exception. in the code we require that popup screen that show but the value of the average speed is not show.
class popUpScreen extends PopupScreen
{
private EditField _sp;
// Speed s = new Speed();
//public double _averageSpeed =s._averageSpeed ;
StringBuffer sb = new StringBuffer();
popUpScreen()
{
super(new VerticalFieldManager(),Field.FOCUSABLE);
Speed s = new Speed();
double _averageSpeed =s._averageSpeed ;
_sp = new EditField(" The Average Speed is: ",""+_averageSpeed );
add(_sp);
//Speed._averageSpeed=sb.;
//sb.append("\n_averageSpeed : ");
//sb.append(_averageSpeed);
}
}
you should save that VerticalFieldManager you passed to the super; add your label to the manager.
It is not necessary to override the whole class you could do like this:
DialogFieldManager dfm = new DialogFieldManager();
dfm.add(_sp);
PopupScreen popUpScreen = new BasePopupScreen(dfm, Manager.VERTICAL_SCROLL);