Dart StageXL activate mouse event on overlapping sprites - dart

Is it possible to have a mouse event be called for two sprites overlapping? I have attempted to use getObjectsUnderPoint however it does not seem to be working.
class Line extends Sprite
{
int x;
int y;
int type;
var tempLine = new Shape();
bool isClicked = false;
Line(int xPos, int yPos, int type)
{
this.x = xPos;
this.y = yPos;
this.type = type;
if(type == 1)
{
graphics.beginPath();
graphics.moveTo(x, y);
graphics.lineTo(x+300, y);
graphics.closePath();
graphics.strokeColor(Color.LightGray,19);
addEventListener(MouseEvent.CLICK, react);
tempLine.graphics.beginPath();
tempLine.moveTo(x,y);
tempLine.graphics.lineTo(x+300,y);
tempLine.graphics.closePath();
}
else if(type == 2)
{
graphics.beginPath();
graphics.moveTo(x, y);
graphics.lineTo(x, y+300);
graphics.closePath();
graphics.strokeColor(Color.LightGray,19);
addEventListener(MouseEvent.CLICK, react);
tempLine.graphics.beginPath();
tempLine.moveTo(x,y);
tempLine.graphics.lineTo(x,y+300);
tempLine.graphics.closePath();
}
addChild(tempLine);
}
react(MouseEvent event)
{
Point tempPoint = new Point(event.localX, event.localY);
graphics.strokeColor(Color.Black,19);
isClicked = true;
var subShape = getObjectsUnderPoint(tempPoint);
for(Shape i in subShape)
{
i.parent.userData.isClicked = true;
}
}
}
I have two Line objects overlapping and when one is clicked I want the boolean for both objects to be true. I have read that the getObjectsUnderPoint does not return a Sprite, could this be the issue?

MouseEvents are only dispatched to the top most display object that extends the InteractiveObject class (which is true for all DisplayObjectContainers and Sprites). So only one display object can receive the MouseEvent.CLICK event. You are right that the getObjectsUnderPoint does only return the children of DisplayObjectContainers but there is an open issue on the GitHub repository (https://github.com/bp74/StageXL/issues/209) talking about this. One of the next versions of StageXL (greater than version 0.13) may change this behavior.

Related

How to take damage from enemies (bullets)

Hello fellow programmers! I am sorry to bother you, but I have a school project which is to create a game. I am almost finish all I have to do is to make my character (player) take damage from the enemy bullets.
Here is my enemy class where I have my bullet list which makes the enemies shoot bullets. You can see that Ive tried to track the position of the bullets by temp.(I followed these tutorials on making the enemies https://www.youtube.com/watch?v=_TlnUM-uhSI and https://www.youtube.com/watch?v=tfiKwOo_4xo)
Before you jump on me I just wanna say I have searched everywhere for an answer but since XNA is very limited on what I wanna create it makes it very hard for me.
class Enemies
{
public Texture2D texture;
public Vector2 position;
public Vector2 velocity;
public bool isVisible = true;
Random random = new Random();
int randX, randY;
float temp_bulletenemyX;
float temp_bulletenemyY;
// bullets
private List<Bullets> bullets = new List<Bullets>();
Texture2D bulletTexture;
public Enemies(Texture2D NewTexture, Vector2 NewPosition, Texture2D newBulletTexture)
{
texture = NewTexture;
position = NewPosition;
randY = random.Next(-4, 4);
randX = random.Next(-4, -1);
velocity = new Vector2(randX, randY);
bulletTexture = newBulletTexture;
}
float shoot = 0;
public void update(GraphicsDevice graphics, GameTime gameTime)
{
KeyboardState keyboardState = Keyboard.GetState();
position += velocity;
if (position.Y <= 0 || position.Y >= graphics.Viewport.Height - texture.Height)
velocity.Y = -velocity.Y;
if (position.X < 0 - texture.Width)
isVisible = false;
shoot += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (shoot > 1)
{
shoot = 0;
Shootbullet();
}
updateBullets();
}
public void updateBullets()
{
foreach (Bullets bullet in bullets)
{
bullet.position += bullet.velocity;
temp_bulletenemyX = bullet.position.X;
temp_bulletenemyY = bullet.position.Y;
if (bullet.position.X < 0)
bullet.isVisible = false;
}
for (int i = 0; i < bullets.Count; i++)
if(!bullets[i].isVisible)
{
bullets.RemoveAt(i);
i--;
}
}
public void Shootbullet()
{
Bullets newBullet = new Bullets(bulletTexture);
newBullet.velocity.X = velocity.X - 3f;
newBullet.position = new Vector2(position.X + newBullet.velocity.X, position.Y + (texture.Height / 2) - (bulletTexture.Height / 2));
newBullet.isVisible = true;
if (bullets.Count() < 3) // hur många skott den skall skjuta
bullets.Add(newBullet);
}
public void draw(SpriteBatch spriteBatch)
{
foreach (Bullets bullet in bullets)
bullet.Draw(spriteBatch);
spriteBatch.Draw(texture, position, Color.White);
}
public float PosX
{
get
{
return position.X;
}
}
public Vector2 Pos
{
get
{
return position;
}
}
public float PosY
{
get
{
return position.Y;
}
}
public List<Bullets> GetbulletList
{
get{
return bullets;
}
}
public Texture2D text
{
get
{
return texture;
}
}
public Texture2D BulletText
{
get
{
return bulletTexture;
}
heres the fundamental Game1 code which I have tried to make so my character can take damage.
player.rectangle = new Rectangle(Convert.ToInt32(player.PosX), Convert.ToInt32(player.PosY), player.text.Width, player.text.Height);
foreach (Enemies bullet in enemies.ToList())
{
rec_bullet = new Rectangle(Convert.ToInt32(bullet.GetbulletList.ElementAt(i).position.X), Convert.ToInt32(bullet.GetbulletList.ElementAt(i).position.Y), nyenemy.BulletText.Width, nyenemy.BulletText.Height);
hit = CheckCollision(rec_bullet, player.rectangle);
if (hit == true)
{
player.health -= 10;
hit = false;
}
i++;
I am very sorry if everything is a mess, Ive have put everything together through following many tutorials and some of my own coding. I am also very sorry if I am violating forum rules, I am new here.
Best Regards Kiar.
I'm going to be brave and suggest the following - looking at the snippets of code supplied.
In Game1 code - you are working you way through the enemies, however it looks like you are not searching through the list of bullets for each enemy. You are getting the ElementAt(..) with 'i' - adding one to it, then going to the next enemy and then only getting the ElementAt(..) with the incremented 'i'.
From my understanding - the flow of the code should be:
for each enemy in enemy list
for each bullet in enemy bullet list
Check Collision with Player
if collision then adjust player health
There are a few things wrong with your code. For starters, your Bullet class should contain the bulletUpdate() method, which should be called in a foreach loop.
foreach (Bullet b in bullets)
{
b.update(/*parameters here*/);
}
Your bullets List should be a public list stored in your Game1.cs or an EnemyManager class, not in each enemy. Pass each enemy a reference to that list, so that when they fire, they can add the bullet to the list.
On top of that, your collision test should be nothing more than an Intersection test between each bullet and yourself. Again, another foreach loop.
foreach(Bullet b in bullets)
{
//where playerRect is the hitbox for your player and b.Rect is the hitbox for your bullet
if(playerRect.Intersects(b.Rect)
player.healh-=damage;
}
Hope that helps.

Dart StageXL sprite color change on mouse click

I am relatively new to both StageXL and Dart and I am having difficulty changing the color of a Sprite on a mouse click. Currently I am just referencing the sprite and calling the graphics fillColor() method however nothing changes. Any ideas on how to change individual Sprite lines by mouse click?
class GameBoard
{
Stage stage;
int xPos;
int yPos;
var circle;
var line;
GameBoard(Stage s)
{
this.stage = s;
this.xPos = 100;
this.yPos = 100;
this.circle = new Sprite();
this.line = new Sprite();
}
Sprite generateDots(int x, int y, int size)
{
circle.graphics.circle(x,y,size);
circle.graphics.fillColor(Color.Black);
circle.addEventListener(MouseEvent.CLICK, reactCircle);
return circle;
}
Sprite generateHorzLines(int x, int y)
{
line.graphics.beginPath();
line.graphics.moveTo(x, y);
line.graphics.lineTo(x+100, y);
line.graphics.closePath();
line.graphics.strokeColor(Color.Gray);
line.addEventListener(MouseEvent.CLICK, reactHorzLine);
return line;
}
Sprite generateVertLines(int x, int y)
{
line.graphics.beginPath();
line.graphics.moveTo(x, y);
line.graphics.lineTo(x, y+100);
// this.line.graphics.closePath();
line.graphics.strokeColor(Color.Gray);
line.addEventListener(MouseEvent.CLICK, reactVertLine);
return line;
}
void generateBoard()
{
for(int i = 0; i < 5;i++)
{
for(int j = 0; j< 5;j++)
{
//render horizontal lines
if(j < 4)
{
stage.addChild(generateHorzLines(xPos,yPos));
}
//render vertical lines
if(i<4)
{
stage.addChild(generateVertLines(xPos,yPos));
}
//render points
stage.addChild(generateDots(xPos,yPos,5));
xPos+=100;
}
yPos+=100;
xPos = 100;
}
}
void reactHorzLine(MouseEvent event)
{
line.graphics.fillColor(Color.Red);
}
void reactVertLine(MouseEvent event)
{
line.graphics.fillColor(Color.Green);
}
void reactCircle(MouseEvent event)
{
circle.graphics.fillColor(Color.Blue);
}
}
The current version of StageXL (0.12) has no support for vector graphics when using the WebGL renderer only the Canvas2D renderer is supported. This will change with the next versions where vector graphics are also supported with the WebGL renderer. In the meantime you can opt-out of the WebGL renderer to use the Canvas2D renderer.
// do this before you construct the Stage
StageXL.stageOptions.renderEngine = RenderEngine.Canvas2D;
Btw. you will get best performance by using Bitmaps/BitmapDatas in StageXL. They are based on textures which will be rendered much faster than vector graphics.

To attach a ButtonField on every row of CustomListField in BlackBerry [duplicate]

i m writing one application in which i have created custom list field for displaying listview.
my CustomListField contains one image and text in a row. i m gettiing field change listener on click of listfield row but i want to put fieldchange listener on image too..
can anyone tell me how can i do that.
here is my code.
public class CustomListField extends ListField implements ListFieldCallback {
private Vector _listData;
private int _MAX_ROW_HEIGHT = 60;
public CustomListField(Vector data) {
_listData = data;
setSize(_listData.size());
setSearchable(true);
setCallback(this);
setRowHeight(_MAX_ROW_HEIGHT);
}
protected void drawFocus(Graphics graphics, boolean on) {
XYRect rect = new XYRect();
graphics.setGlobalAlpha(150);
graphics.setColor(Color.BLUE);
getFocusRect(rect);
drawHighlightRegion(graphics, HIGHLIGHT_FOCUS, true, rect.x, rect.y, rect.width, rect.height);
}
public int moveFocus(int amount, int status, int time) {
this.invalidate(this.getSelectedIndex());
return super.moveFocus(amount, status, time);
}
public void onFocus(int direction) {
super.onFocus(direction);
}
protected void onUnFocus() {
this.invalidate(this.getSelectedIndex());
}
public void refresh() {
this.getManager().invalidate();
}
public void drawListRow(ListField listField, Graphics graphics, int index, int y, int w) {
listField.setBackground(BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("listing_bg.png")));
ListRander listRander = (ListRander) _listData.elementAt(index);
graphics.setGlobalAlpha(255);
graphics.setFont(Font.getDefault().getFontFamily().getFont(Font.PLAIN, 24));
final int margin = 5;
final Bitmap thumb = listRander.getListThumb();
final String listHeading = listRander.getListTitle();
final Bitmap nevBar = listRander.getNavBar();
// list border
graphics.setColor(Color.GRAY);
graphics.drawRect(0, y, w, _MAX_ROW_HEIGHT);
// thumbnail border & thumbnail image
graphics.setColor(Color.BLACK);
// graphics.drawRoundRect(margin-2, y+margin-2,thumb.getWidth()+2, thumb.getHeight()+2, 5, 5);
graphics.drawBitmap(margin, y + margin, thumb.getWidth(), thumb.getHeight(), thumb, 0, 0);
// drawing texts
// graphics.setFont(Font.BOLD);
graphics.drawText(listHeading, margin + thumb.getWidth(), y + margin);
graphics.setColor(Color.GRAY);
// graphics.setFont(Font.smallFont); // graphics.drawText(listDesc, 2*margin+thumb.getWidth(), y+ margin+20); // //
// graphics.drawText(listDesc2, 2*margin+thumb.getWidth(), y+ margin+32);
// draw navigation button
final int navBarPosY = y + (_MAX_ROW_HEIGHT / 2 - nevBar.getHeight() / 2);
final int navBarPosX = Graphics.getScreenWidth() - nevBar.getWidth() + margin;
graphics.drawBitmap(navBarPosX, navBarPosY, nevBar.getWidth(), nevBar.getHeight(), nevBar, 0, 0);
}
public Object get(ListField listField, int index) {
String rowString = (String) _listData.elementAt(index);
return rowString;
}
public int indexOfList(ListField listField, String prefix, int start) {
for (Enumeration e = _listData.elements(); e.hasMoreElements();) {
String rowString = (String) e.nextElement();
if (rowString.startsWith(prefix)) {
return _listData.indexOf(rowString);
}
}
return 0;
}
public int getPreferredWidth(ListField listField) {
return 3 * listField.getRowHeight();
}
/*
protected boolean trackwheelClick(int status, int time) {
invalidate(getSelectedIndex());
Dialog.alert(" U have selected :" + getSelectedIndex());
return super.trackwheelClick(status, time);
}
*/
}
i want to put click listner on star image of listfield row
and following is output of abbove code.
I did something very similar to this on a past project:
Background
As Arhimed said in his answer, and as you can read about on the BlackBerry forums here, you can't have full-fledged Field objects within the ListField. The content of ListField rows is just drawn directly in drawListRow() as text, and Bitmaps, etc. The contents aren't Field instances, and therefore, are not focusable.
So, what I did was to replace ListField with a subclass of Manager. Originally, I used a VerticalFieldManager, but I ran into problems with that. I've also been seeing a lot of issues on stack overflow, where people subclass VerticalFieldManager, customize just one small behaviour, and everything starts breaking. It seems to me that VerticalFieldManager works well if you accept its normal behaviour, and if you need something more, just extend Manager directly. Performing layout for vertically stacked rows is pretty easy.
I then made each row its own Manager, and implemented custom layout in sublayout() to place the row's Fields where I wanted them. I could then also make the row focusable, and then a bitmap/button on the row separately focusable (like your star). Clicking the row invokes one action, and clicking the star invokes another one.
I will note, however, that in my app, performance was not an issue, because I only had 10-20 rows. Also, I did have to modify my code to match your example, so consider this code only lightly tested. However, I did build it into an app, so it should perform fine as long as my assumptions, and your description were valid.
Implementation
First, it wasn't clear to me what your ListRander is (you didn't show that code). However, in my code, I need a data class to contain details about one row. It looked like that's how you used ListRander, so that's what I used:
public class ListRander {
private String _title;
private Bitmap _thumb;
public ListRander(String title, Bitmap thumb) {
_title = title;
_thumb = thumb;
}
public String getTitle() {
return _title;
}
public Bitmap getThumb() {
return _thumb;
}
}
Then, I replaced your CustomListField class with my own:
public class CustomListField extends Manager implements FocusChangeListener {
private int _MAX_ROW_HEIGHT = 60;
private boolean _searchable = false;
private Vector _listData;
private FieldChangeListener _fieldListener;
public CustomListField(Vector data) {
super(FOCUSABLE | VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
setSearchable(true);
setEditable(false);
setListData(data);
}
public void setChangeListener(FieldChangeListener listener) {
// we need to save this listener, because we set it to listen to all new rows
_fieldListener = listener;
int numFields = getFieldCount();
for (int f = 0; f < numFields; f++) {
getField(f).setChangeListener(listener);
}
super.setChangeListener(listener);
}
public int getRowHeight() {
return _MAX_ROW_HEIGHT;
}
public void setSearchable(boolean searchable) {
_searchable = searchable;
}
public int getSelectedIndex() {
return getFieldWithFocusIndex(); // TODO??
}
public Object get(int index) {
return _listData.elementAt(index);
}
public int indexOfList(String prefix, int start) {
if (start >= _listData.size() || !_searchable) {
return -1;
} else {
int result = getSelectedIndex(); // the default result if we find no matches
for (Enumeration e = _listData.elements(); e.hasMoreElements(); ) {
String rowString = (String) e.nextElement();
if (rowString.startsWith(prefix)) {
return _listData.indexOf(rowString);
}
}
return result;
}
}
protected boolean navigationClick(int status, int time) {
CustomListRow focus = (CustomListRow) getFieldWithFocus();
if (focus != null) {
// see if the row wants to process this click
if (!focus.navigationClick(status, time)) {
// let our FieldChangeListener know that this row has been clicked
fieldChangeNotify(getFieldWithFocusIndex());
}
return true;
} else {
return false;
}
}
protected void sublayout(int width, int height) {
int w = Math.min(width, getPreferredWidth());
int h = Math.min(height, getPreferredHeight());
int rowHeight = getRowHeight();
int numRows = getFieldCount();
setExtent(w, h);
setVirtualExtent(w, rowHeight * numRows);
for (int i = 0; i < numRows; i++) {
Field f = getField(i);
setPositionChild(f, 0, rowHeight * i);
layoutChild(f, w, rowHeight);
}
}
public int getPreferredWidth() {
return Display.getWidth();
}
public int getPreferredHeight() {
return Display.getHeight();
}
public void setListData(Vector listData) {
_listData = listData;
if (listData != null) {
int listSize = listData.size();
int numRows = getFieldCount();
for (int s = 0; s < listSize; s++) {
if (s < numRows) {
// we can reuse existing CustomListRows
CustomListRow row = (CustomListRow) getField(s);
row.setData((ListRander) listData.elementAt(s));
} else {
CustomListRow row = new CustomListRow((ListRander) listData.elementAt(s));
row.setChangeListener(_fieldListener);
row.setFocusListener(this);
add(row);
}
}
if (listSize < numRows) {
// delete the excess rows
deleteRange(listSize, numRows - listSize);
}
} else {
deleteAll();
}
invalidate();
}
public void focusChanged(Field field, int eventType) {
// we handle scrolling here, when focus changes between rows
if (eventType == FOCUS_GAINED) {
if (field.getTop() < getVerticalScroll()) {
// field is off the top of the screen, so scroll up
setVerticalScroll(field.getTop());
} else if (field.getTop() >= getVerticalScroll() + getVisibleHeight()) {
// field is off the bottom of the screen, so scroll down
setVerticalScroll(field.getTop() - getVisibleHeight() + getRowHeight());
}
}
}
}
Finally, one row is represented by my CustomListRow class:
public class CustomListRow extends Manager implements FieldChangeListener {
private static final int _MAX_ROW_HEIGHT = 60;
private ListRander _data;
private BitmapField _thumb;
private LabelField _title;
private FocusableBitmapField _star;
private static final Bitmap _starImg = Bitmap.getBitmapResource("star.png");
private static final Bitmap _bgImg = Bitmap.getBitmapResource("listing_bg.png");
private SeparatorField _separator;
private int _fontColor = Color.BLACK;
private boolean _highlighted = false;
private int _width;
// subclass exists to expose focus methods (make public)
private class FocusableBitmapField extends BitmapField {
public FocusableBitmapField() {
super(_starImg, BitmapField.FOCUSABLE | BitmapField.EDITABLE);
}
public void onFocus(int direction) {
super.onFocus(direction);
}
public void onUnfocus() {
super.onUnfocus();
}
}
public CustomListRow(ListRander data) {
super(Field.FOCUSABLE | Manager.NO_VERTICAL_SCROLL | Manager.NO_VERTICAL_SCROLLBAR);
setBackground(BackgroundFactory.createBitmapBackground(_bgImg));
_width = Display.getWidth();
long labelStyle = (DrawStyle.LEFT | DrawStyle.TOP | DrawStyle.ELLIPSIS);
_title = new LabelField("", labelStyle) { // custom anonymous class to change font color
protected void paint(Graphics g) {
int c = g.getColor();
g.setColor(_fontColor);
super.paint(g);
g.setColor(c);
}
};
_title.setFont(Font.getDefault().getFontFamily().getFont(Font.PLAIN, 24));
_thumb = new BitmapField();
_star = new FocusableBitmapField();
_star.setChangeListener(this);
_separator = new SeparatorField() { // custom anonymous class to change separator color
protected void paint(Graphics g) {
int c = g.getColor();
g.setColor(Color.GRAY);
super.paint(g);
g.setColor(c);
}
};
setData(data);
add(_thumb);
add(_title);
add(_star);
add(_separator);
}
public ListRander getData() {
return _data;
}
public void setData(ListRander value) {
if (value != _data) {
_data = value;
_title.setText(value.getTitle());
_thumb.setBitmap(value.getThumb());
}
}
private void onStarClicked() {
Dialog.alert("Star has been clicked or tapped!");
}
private void onRowClicked() {
Dialog.alert("Row has been clicked or tapped!");
}
public void fieldChanged(Field field, int context) {
if (field == _star) {
onStarClicked();
}
}
public boolean navigationClick(int status, int time) {
if (_star.isFocus()) {
onStarClicked();
return true;
} /* else {
onRowClicked();
return true;
} */
return false; // we will not consume this event
}
protected void highlight(boolean onRow) {
_fontColor = onRow ? Color.WHITE : Color.BLACK; // change font color for contrast
_highlighted = onRow;
invalidate();
}
protected void onFocus(int direction) {
// called when focus first transfers to this row, from another Field
if (direction == 1) {
// coming from top to bottom, we highlight the row first, not the star
highlight(true);
} else if (direction == -1) {
// coming from bottom to top, we highlight the star button first, not the row
_star.onFocus(direction);
highlight(false);
}
}
protected void onUnfocus() {
// remove highlighting of the row, if any
highlight(false);
super.onUnfocus();
}
protected int moveFocus(int amount, int status, int time) {
// called when this row already has focus (either on row, or star button)
if (amount > 0) {
// moving top to bottom
if (!_star.isFocus()) {
// we were on the row, now move to the star button
_star.onFocus(1);
highlight(false);
amount--; // consume one unit of movement
}
} else {
// moving from bottom to top
if (_star.isFocus()) {
// we were on the star button, now move back over to the row
_star.onUnfocus();
highlight(true);
amount++; // consume one unit of movement
}
}
return amount;
}
protected boolean touchEvent(net.rim.device.api.ui.TouchEvent event) {
// We take action when the user completes a click (a.k.a. unclick)
int eventCode = event.getEvent();
if ((eventCode == TouchEvent.UNCLICK) || (eventCode == TouchEvent.DOWN)) {
// Get the touch location, within this Manager
int x = event.getX(1);
int y = event.getY(1);
if ((x >= 0) && (y >= 0) && (x < _width) && (y < _MAX_ROW_HEIGHT)) {
int field = getFieldAtLocation(x, y);
if ((field >= 0) && (getField(field) == _star)) {
// Let event propagate to (star) button field
return super.touchEvent(event);
} else {
if (eventCode == TouchEvent.UNCLICK) {
// A completed click anywhere else in this row should popup details for this selection
fieldChangeNotify(1);
onRowClicked();
} else {
// This is just a soft touch (TouchEvent.DOWN), without full click
setFocus();
}
// Consume the event
return true;
}
}
}
// Event wasn't for us, let superclass handle in default manner
return super.touchEvent(event);
}
protected void sublayout(int width, int height) {
height = Math.min(getPreferredHeight(), height);
setExtent(_width, height);
final int margin = 5;
int thumbWidth = _thumb.getPreferredWidth();
layoutChild(_thumb, thumbWidth, _thumb.getPreferredHeight());
setPositionChild(_thumb, margin, margin);
int starWidth = _star.getPreferredWidth();
int starHeight = _star.getPreferredHeight();
layoutChild(_star, starWidth, starHeight);
setPositionChild(_star, width - starWidth - margin, (height - starHeight) / 2);
// this assumes you want margin between all fields, and edges
layoutChild(_title, width - thumbWidth - starWidth - 4 * margin, _title.getPreferredHeight());
setPositionChild(_title, margin + thumbWidth /* + margin */, margin); // TODO?
}
protected void paintBackground(Graphics g) {
super.paintBackground(g);
if (_highlighted) {
// you can't override drawFocus() for a Manager, so we'll handle that here:
int oldColor = g.getColor();
int oldAlpha = g.getGlobalAlpha();
XYRect rect = new XYRect();
g.setGlobalAlpha(150);
g.setColor(Color.BLUE);
getFocusRect(rect);
drawHighlightRegion(g, HIGHLIGHT_FOCUS, true, rect.x, rect.y, rect.width, rect.height);
g.setGlobalAlpha(oldAlpha);
g.setColor(oldColor);
}
}
public int getPreferredWidth() {
return _width;
}
public int getPreferredHeight() {
return _MAX_ROW_HEIGHT;
}
}
Usage
This is how you might use the whole list field (maybe in a Screen class):
public class ListScreen extends MainScreen implements FieldChangeListener {
public ListScreen() {
try {
Vector data = new Vector();
Bitmap icon = Bitmap.getBitmapResource("list_icon.png");
for (int i = 0; i < 15; i++) {
ListRander lr = new ListRander("Product Name " + i, icon);
data.addElement(lr);
}
CustomListField list = new CustomListField(data);
add(list);
list.setChangeListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
public void fieldChanged(Field field, int context) {
if (field instanceof CustomListRow) {
CustomListRow row = (CustomListRow) field;
Dialog.alert(row.getData().getTitle() + " was selected!");
}
}
}
In my app, it made sense for the CustomListRow itself to handle the equivalent of your star click. However, for me, it did not make sense to have the row click handled that way. So, I let you set a FieldChangeListener on the CustomListField itself, which is called back when any row is selected. See the example above in my screen class. If you want to handle the row click inside the CustomListRow class, too, that's fine. I laid out a onRowClicked() method there. Search in the code for where that's commented out, and you can reactivate, an implement that method (onRowClicked()).
Issues
My app didn't require list searching. I laid out a sample implementation of that, like ListField has. But, I didn't test it. That's your job, if you need it. I just got you started with the CustomListField implementation (see indexOfList()).
I didn't see what your "nav bar" was for. A bar is usually a full-width item, like a status bar, or toolbar. I don't see anything like that in your screenshot. A nav item might be a little arrow at the right side of each row, to bring up details. But, I didn't see that in your screenshot either. So, I ignored that code. If you need a nav bar, you obviously know what it should be, and can add that to my code above.
I couldn't tell whether or not you just added the star as part of the row's background image, or if you had a separate image for that. I added a separate star.png to represent the star. I would assume that clicking the star fills it in, or highlights it, or something. But, you didn't describe that problem, so I assume you can handle that. If you need a custom field to represent the star, that can have selected and unselected images, just post that as a new question.
You had some code that appeared like it was trying to set the row width to 3x the row height, but that didn't match your screen shot. Most lists are full-screen width anyway. So, I remove that code. My CustomListRow class implements getPreferredWidth() and requests the full screen width. Change if you like.
Unlike Android's ListView the BB's ListField is not designed to have a focusable/clickable fields inside of list items. So any attempt to workaround this will have some negative side effects.
A relatively easy/quick workaround would be to switch to VerticalFieldManager (check this other stack overflow question). But if the list is too long (more than several hundreds, I believe) you risk to "eat" too much memory.
If the app is designed for touch screens only, then you can try to stay with ListField + do some manual tracking of touch event coordinates. So when you detect a list field click (in a way you would normally do it) you can check whether the touch coordinates correspond to the star image area (at least on the X axis). I am not going to invent/provide an implementation, but just giving an idea.

Blackberry UI Hint Box

I am very much new to the blackberry UI development and want to know that is there any way you can add a hint box on bitmap? just like a title attribute in an element of HTML
You can use the following TooltipScreen and add fields to the screen in the following way
add(new ButtonField(“myButton”), “My Tooltip text”);
TooltipScreen
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.container.MainScreen;
public class TooltipScreen extends MainScreen {
TooltipScreen screen = this;
boolean doRedraw = false;//prevent infinte redrawing
Vector tooltips = new Vector();//vector to hold tooltip strings
private Timer tooltipTimer = new Timer();
private TimerTask tooltipTask;
boolean alive = false;//is the tooltip alive? used to pop it after our timeout
int count = 0;//used to calculate time tooltip is displayed
//tooltip popup colours:
int backgroundColour = 0xeeeeee;
int borderColour = 0xaaaaaa;
int fontColour = 0x666666;
//the tooltip:
String tooltip;
int tooltipWidth;
int yCoord;
int xCoord;
//region parameters:
XYRect contentArea;
int contentBottom;
int contentRight;
public TooltipScreen() {
super();
//when timeout reaches 100ms*20 ie. 2seconds set alive to false and redraw screen:
tooltipTask = new TimerTask() {
public void run() {
if (alive) {
count++;
if (count == 20) {
alive = false;
invalidate();
}
}
}
};
tooltipTimer.scheduleAtFixedRate(tooltipTask, 100, 100);
}
//override add method adds an empty string to tooltip vector:
public void add(Field field) {
tooltips.addElement("");
super.add(field);
}
//custom add method for fields with tooltip: add(myField, "myTooltip");
public void add(Field field, String tooltip) {
super.add(field);
tooltips.addElement(tooltip);
}
public void setColours(int backgroundColour, int borderColour, int fontColour) {
this.backgroundColour = backgroundColour;
this.borderColour = borderColour;
this.fontColour = fontColour;
}
//reset everything when user changes focus,
//possibly needs logic to check field has actually changed (for listfields, objectchoicefields etc etc)
protected boolean navigationMovement(int dx, int dy, int status, int time) {
count = 0;
alive = true;
doRedraw = true;
return super.navigationMovement(dx, dy, status, time);
}
protected void paint(Graphics graphics) {
super.paint(graphics);
if (alive) {
Field focusField = getFieldWithFocus();
tooltip = (String) tooltips.elementAt(screen.getFieldWithFocusIndex());
//don't do anything outside the norm unless this field has a tooltip:
if (!tooltip.equals("")) {
//get the field content region, this may fall inside the field actual region/coordinates:
contentArea = focusField.getContentRect();
contentBottom = contentArea.y + contentArea.height;
contentRight = contentArea.x + contentArea.width;
//+4 to accomodate 2 pixel padding on either side:
tooltipWidth = graphics.getFont().getAdvance(tooltip) + 4;
yCoord = contentBottom - focusField.getManager().getVerticalScroll();
//check the tooltip is being drawn fully inside the screen height:
if (yCoord > (getHeight() - 30)) {
yCoord = getHeight() - 30;
}
//check the tooltip doesn't get drawn off the right side of the screen:
if (contentRight + tooltipWidth < getWidth()) {
xCoord = contentRight;
} else {
xCoord = getWidth() - tooltipWidth;
}
//draw the tooltip
graphics.setColor(backgroundColour);
graphics.fillRect(xCoord, yCoord, tooltipWidth, 30);
graphics.setColor(borderColour);
graphics.drawRect(xCoord, yCoord, tooltipWidth, 30);
graphics.setColor(fontColour);
graphics.drawText(tooltip, xCoord + 2, yCoord);
}
}
//doRedraw logic prevents infinite loop
if (doRedraw) {
//System.out.println("redrawing screen: " + System.currentTimeMillis());
screen.invalidate();
doRedraw = false;
}
}
}

is it possible to move the map on touch in blackberry by using MapField.

I am using mapField to create a custom map.I am using the code in this link.
How to show more than one location in Blackberry MapField?.
But the map position is fixed. i am not able to drag the map as we can do in google maps or when we invoke the maps like
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments());
}
Here's some code that should get you going on the correct path. I've taken it from a project of mine that had some special requirements, so there could be some remnants of that left in there inadvertently. There will be some undefined variables in there -- they're member variables that are declared in the class and should all start with an underscore. This is also part of a class that extends MapField, so you would have to create a custom map class and then use that rather than the default.
protected boolean touchEvent(TouchEvent message) {
boolean ret = super.touchEvent(message);
//mark that we're starting to interact
if(message.getEvent() == TouchEvent.DOWN) {
_startTouchTracking = true;
_clicking = true;
_touchX = message.getX(1);
_touchY = message.getY(1);
}
//user is wanting to move the map
else if(message.getEvent() == TouchEvent.MOVE) {
int dx = _touchX - message.getX(1);
int dy = _touchY - message.getY(1);
_clicking = false;
_touchX = message.getX(1);
_touchY = message.getY(1);
//perform checks to make sure we don't move outside of the map's range
int lat = getLatitude() - dy*(int)MathUtilities.pow(2, (double)getZoom());
if(lat < -9000000) {
lat = -9000000;
}
else if (lat > 9000000) {
lat = 9000000;
}
int lon = getLongitude() + dx*(int)MathUtilities.pow(2, (double)getZoom());
if(lon < -18000000) {
lon = -18000000;
}
else if (lon > 18000000) {
lon = 18000000;
}
moveTo(lat, lon);
}
//if the person just touches and releases, we want to move to that spot
else if (message.getEvent() == TouchEvent.UNCLICK && _clicking) {
int dx = message.getX(1) - getWidth()/2;
int dy = message.getY(1) - getHeight()/2;
move(dx, dy);
_clicking = false;
}
//touch has been released
else if (message.getEvent() == TouchEvent.UP) {
_startTouchTracking = false;
}
//we handled the click
return true;
}
As said, this might need tweaking for your use, but in general should get you started. The MathUtilities.pow() calls were my way of coming up with an appropriate amount of motion depending on the zoom level.
Edit for Comments
Letting a Bitmap move with the map:
protected Coordinates _bitmapCoordinates;
protected Bitmap _bitmap;
public YourMapField() {
//we're going to put the bitmap at -38.43, 20.32
_bitmapCoordinates = new Coordinates(-38.43, 20.32, 0.0);
_bitmap = YOUR_CODE_TO_GET_THE_BITMAP;
}
protected void paint(Graphics g) {
super.paint(g);
XYPoint placeToPaintBitmap = new XYPoint();
convertWorldToField(_bitmapCoordinates, placeToPaintBitmap);
//perform a check here to make sure that field will be seen. This code would depend
//on how you're painting the image. Just check the placeToPaintBitmap.x and placeToPaintBitmap.y
//against 0 and the map's width and height, along with some adjustment for how you paint
if(bitmap will be visible on the screen) {
//The code I have here is drawing the bitmap from the top left of the image, but if
//you need to draw from some other place you may have to offset the x and y
g.drawBitmap(placeToPaintBitmap.x, placeToPaintBitmap.y, _bitmap.getWidth(), _bitmap.getHeight(), 0, 0);
}
}
I didn't test any of that code, so it might be buggy but should give you the general idea.

Resources