I am writing an application in BlackBerry, where I want to do some custom painting at the top portion of the screen in the paint method of FullScreen and at the same time, I want a RichtextField positioned at the lower portion of the screen. I tried using setPosition methods in the Field class, but to no avail. So how do I set the position of the RichtextField that is added to the FullScreen class?
You can use a SpacerField for that purpose:
class SpacerField extends Field {
int localWidth, localHeight;
SpacerField(int width, int height) {
super(Field.NON_FOCUSABLE);
localWidth = width;
localHeight = height;
}
protected void layout(int width, int height) {
// TODO Auto-generated method stub
setExtent(localWidth, localHeight);
}
protected void paint(Graphics graphics) {
}
public int getPreferredWidth() {
return localWidth;
}
public int getPreferredHeight() {
return localHeight;
}
}
and add it to your Screen before your RichTextField. Be sure to give a suitable width (Display.getWidth() ?) and height when constructing the SpacerField.
Note: I had found the code at this forum discussion a few months ago when I needed to do something similar.
The best way to position objects is to extend a Manager and use it to position and size the objects the way you want. Check the documentation for net.rim.device.api.ui.Manager and net.rim.device.api.ui.Field for information on how manager control their children.
Related
I am an an Android Developer, developing an Blackberry application.
I have created a button of full width of screen. Getting problem in shifting the text to the center of the button area.
Used below code :
ButtonField _contactButton = new ButtonField(Constants.contactButtonTitle,Field.FIELD_HCENTER|Field.USE_ALL_WIDTH |
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
protected void layout(int width, int height) {
super.layout(width, height);
HARD_CODED_HEIGHT = this.getHeight()/2 + 6;
this.setExtent(contactButtonWidth, HARD_CODED_HEIGHT);
}
public int getPreferredWidth() {
return contactButtonWidth;
}
};
Now using the below code :
ButtonField _contactButton = new ButtonField(Constants.contactButtonTitle,Field.FIELD_VCENTER|Field.USE_ALL_WIDTH |
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
protected void layout(int width, int height) {
super.layout(getPreferredWidth(), height);
}
public int getPreferredWidth() {
return (Display.getWidth()-60);
}
};
Still getting the issue .. text of my button align to right corner. Please suggest
ButtonField appears to be a little 'broken'. But it also appears to be consistently broken in all the OS Levels that I have tested (OS 5.0 to OS 7.1), so I think we can achieve what you want by working round the broken bits and be confident the workaround will work in all levels you want.
As has been noted, ButtonField ignores USE_ALL_WIDTH, but does respect preferredWidth. So if you want to set the width of your ButtonField, then just override getPreferredWidth(). You should not do anything with width in layout.
Now you are using the styles for ButtonField already. Given that we have discarded USE_ALL_WIDTH as a useful style, I note that you also use FIELD_HCENTER. You should be aware that this is actually a directive to the Manager that is positioning this Field - telling the Manager to position the Field in the centre of the width the Manager has available. This style does not relate to how the contents of the ButtonField are drawn.
For that, you can look to use DrawStyle. By default, ButtonField uses DrawStyle.RIGHT. And it respects DrawStyle.Left - the text will be drawn on the left. It does not however, respect DrawStyle.HCENTER. So to get centred text, we need to paint the text ourselves.
There is one more complication. ButtonField passes a Context area into its paint() method, not the full Field canvas - presumably it does not pass in the edges because these are painted by a border. So to centre the text appropriately, we have to use the clipping region that has been passed in.
Here is the final, hopefully working, ButtonField. I appreciate you will have to spend some time creating a class for this, I'm sorry, I've been lazy and done in it 'in-line'. Please publish your CenteredTextButtonField class if you create one....
final String buttonText = "Test";
ButtonField _contactButton = new ButtonField(" ",
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
public int getPreferredWidth() {
return contactButtonWidth;
}
protected void paint(Graphics graphics) {
super.paint(graphics);
XYRect clippingRect = graphics.getClippingRect();
int centreY = (clippingRect.height - graphics.getFont().getHeight()) / 2;
graphics.drawText(buttonText, 0, centreY, DrawStyle.HCENTER, clippingRect.width);
}
};
USE_ALL_WIDTH is our instruction to the field. Surprisingly, ButtonField ignores such instructions. Even more surprisingly, it honors its own getPreferredWidth (as illogical as it sounds).
So drop that USE_ALL_WIDTH and define your ButtonField like this:
ButtonField testBtn = new ButtonField("Button") {
public int getPreferredWidth() {
return Display.getWidth();
}
};
I have a singleline EditText, and I am interested in the size of the content vs the size of the EditText, to see if the content fits the size of the EditText or not. How can I do this?
Thanks
I'm not really sure what you are asking here:
You can measure the text width like this: (taken from Alan Jay Weiner here:Auto Scale TextView Text to Fit within Bounds)
// Set the text size of the text paint object and use a static layout to render text off screen before measuring
private int getTextWidth(CharSequence source, TextPaint paint, int width, float textSize) {
// Update the text paint object
paint.setTextSize(textSize);
// Draw using a static layout
StaticLayout layout = new StaticLayout(source, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
layout.draw(sTextResizeCanvas);
return layout.getWidth();
}
and you can measure the text as its changed with a watcher like this:
yourEditText.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
//measure your stuff here
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
Developing on the blackberry (OS 7.0) and I have an extended Vertical Field manager created as such:
_myVFM = new MyViewManager(Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT | Manager.VERTICAL_SCROLL){};
However, when I scroll the view, the virtual scroll view size appears way too big.
i.e, I can scroll quite alot further down than is needed and I cant work out why?
Any body any quick ideas? I do have a background image in there that is created as such:
public void paint(Graphics graphics)
{
Bitmap backgroundBitmap = Bitmap.getBitmapResource("bg.png");
Bitmap newBackground = new Bitmap(Display.getWidth(), Display.getHeight());
backgroundBitmap.scaleInto(newBackground, Bitmap.FILTER_LANCZOS, Bitmap.SCALE_TO_FILL);
graphics.clear();
graphics.drawBitmap(0, 0, Display.getWidth(),
Display.getHeight(), newBackground, 0, 0);
super.paint(graphics);
}
Please and thanks,
Burrows
You can redefine the method to define the height of the manager
protected void setExtent(int width, int height) {
super.setExtent(width, myHeight);
}
To not repeat the background image is necessary to redefine the following method, returning false
protected boolean isScrollCopyable() {
return false;
}
Another comment is that it is a bad practice to obtain an image from the paint method. What you are doing is every time you call the paint method is going to get this image.
It's best to get the image once and then use it.
public MyScreen() {
super(NO_VERTICAL_SCROLL);
I managed to fix the issue in my extension of MainScreen using 'NO_VERTICAL_SCROLL' style parameter
Combined with Rupak's suggestion of setting the Background in the constructor of my Vertical Field Manager rather than overriding paint (
https://gist.github.com/3248319)
everything seems Good now - thanks all for your help.
Burrows
No need to USE_ALL_HEIGHT in your constructor.
// instead use this
_myVFM = new MyViewManager(Manager.USE_ALL_WIDTH | Manager.VERTICAL_SCROLL){};
please check it
BasicEditField demo = ew BasicEditField("", number, 15,
BasicEditField.FILTER_NUMERIC
| BasicEditField.FIELD_LEFT) {
public int getPreferredWidth() {
int Width = Graphics.getScreenWidth() - 180;
return Width;
}
public int getPreferredHeight() {
return 30;
}
public void paint(Graphics g) {
g.setColor(Color.LINEN);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.BLUE);
g.drawText(getText(), 0, 0);
super.paint(g);
}
protected void layout(int arg0, int arg1) {
super.layout(getPreferredWidth(), getPreferredHeight());
super.setExtent(getPreferredWidth(), getPreferredHeight());
}
};
this is my code help me out?
Kalpana, I checked your code. Yes, It is not showing cursor. I suggest you to use EditField instead of BasicEditField. You can override these methods for Editfield also. I tried it and it is showing cursor.
I think I may have solved this by adding another field to the manager before this custom BasicEditField. Add a field that doesn't do anything. Something like this:
BitmapField bugFix = new BitmapField(Bitmap.getBitmapResource("empty_image.png"));
myFieldManager.add(bugFix);
myFieldManager.add(demo);
However, what I found is that the size of the dummy field (BitmapField in this case) matters. If your "empty_image.png" image is only 2px high, only the top 2px of the cursor will display. So, if you can deal with the extra padding, add a field that has at least 20px or so and the entire cursor should display. I should also add that this bug does not seem to show up on any subsequent custom BasicEditFields that you add to the manager... only the first one. Hmmm...
I am adding fields to a VerticalFieldManager. Is there a method of adding vertical spacing between fields?
There's several solutions to this, one being that you can create a custom field to be used as a spacer between your other fields.
private static class SpacerField extends Field
{
private int spacerWidth;
private int spacerHeight;
private SpacerField(int width, int height) {
spacerWidth = width;
spacerHeight = height;
}
protected void layout(int width, int height) {
setExtent(getPreferredWidth(), getPreferredHeight());
}
protected void paint(Graphics g) {
// nothing to paint; this is a blank field
}
public int getPreferredHeight() {
return spacerHeight;
}
public int getPreferredWidth() {
return spacerWidth;
}
}
//...
// Usage
add(new LabelField("Before Spacer"));
add(new SpacerField(0, 100));
add(new LabelField("After Spacer"));
Setting the padding or margins of your contained fields is another solution. It's up to you on what you think is the best way of managing things.
There are more elogant ways of doing this using the setPositionChild() methods but a simple work around is to give your fields padding using the setPadding(int top, int right, int bottom, int left) method.
myField.setPadding(5, 0, 5, 0);
I actually find that most times, what you want to do is call setMargin() on the vertical field manager's child fields, not sePadding(). I certainly think creating a SpacerField is now unnecessarily complex.
myField.setMargin(5, 0, 5, 0);
It depends on which kind of child field we're talking about, and how its size is specified, but in general, setPadding() will actually make the field bigger, which could have a visual impact, depending on how the field's background and border are drawn. setMargin() does not make the field any bigger, which I think is more consistent with what the question is asking.
See Mr Vincenzo's answer here, with pictures!
Note: setMargin() and setPadding() were officially added to the Field API relatively late in the BlackBerry Java evolution, but were available as undocumented methods before that.
Another Note: I have seen strange problems when using setMargin(), like the one described in this question. In that case, I did have to resort to one of the other two solutions here.