Calling Method by using String instead of ObjectName - Processing in Eclipse - eclipse

I am trying to combine multiple sketches I had, by having them as classes in a single sketch and go through them by pressing keys.
I'm not sure I'm following the right method but I'm basically turning them on and off by using a boolean for each. I have something like:
package combiner;
public class Combiner extends PApplet {
//...
ClassNameOne s1;
ClassNameTwo s2;
//...
ClassNameNine s9;
// AllSketches //
boolean[] sketches;
int totalSketches = 9;
String str_ts = String.valueOf(totalSketches);
char char_ts = str_ts.charAt(0);
public void setup() {
size(1920, 1080);
sketches = new boolean[totalSketches];
for (int i = 0; i < sketches.length; i++) {
sketches[i] = false;
}
s1 = new ClassNameOne(this);
s2 = new ClassNameTwo(this);
//...
s9 = new ClassNameNine(this);
}
public void draw() {
//drawingEachSketchIfItsBoolean==True
if (sketches[0] == true) {
s1.run();
} else if (sketches[1] == true) {
s2.run();
//....
}
}
public void keyPressed() {
if (key >= '1' && key <= char_ts) {
String str_key = Character.toString(key);
int KEY = Integer.parseInt(str_key);
for (int i = 0; i < sketches.length; i++) {
sketches[i] = false;
}
sketches[KEY - 1] = true;
//initializingEachClassIfKeyPressed
if (KEY == 0) {
s1.init();
} else if (KEY == 1) {
s2.init();
}
//....
}
}
As you can see each Class has an .init and a .run method (used to be my setup + draw).
I was wandering if somehow I can loop to .init or .run them without having to write it once for each, something like:
for(int i=0;i<sketches.length;i++){
if(sketches[i]==true){
String str = String.valueOf(i+1);
str="s"+str; //str becomes the Object's name
??? str.run(); ???
}
}

The cleanest solution would be to create an interface Sketch, which must be implemented in your sketch classes then:
Sketch[] sketches;
int activeSketch = 0;
void setup(){
sketches = new Sketch[2];
sketches[0] = new SketchRed();
sketches[1] = new SketchGreen();
sketches[activeSketch].init();
}
void draw(){
sketches[activeSketch].draw();
}
interface Sketch{
void init();
void draw();
}
class SketchRed implements Sketch{
void init(){}
void draw(){
fill(255, 0, 0);
ellipse(width/2, height/2, 30, 30);
}
}
class SketchGreen implements Sketch{
void init(){}
void draw(){
fill(0, 255, 0);
ellipse(width/2, height/2, 30, 30);
}
}
void keyPressed(){
activeSketch++;
if(activeSketch >= sketches.length){
activeSketch = 0;
}
sketches[activeSketch].init();
}

I am not sure if the whole idea of representing different sketches as classes in a new sketch is really that good, but in any case there seems to be a possibilty in Java for obtaining a class from a String! Look for Class.forName() as described here: http://docs.oracle.com/javase/tutorial/reflect/class/classNew.htm
Keep in mind that you will obtain a class from this and not an instance yet!

Related

Item in ScrollView is not seen in Scene, but it shows in hierarchy

I am trying to display a list, generated dinamically. I created a prefab with the things I need in it (a TextView, 3 TMP_InputFields and 2 Buttons.)
To manage the different list items, I created a script (SkillManager, since the items represents skill the player can choose), which I attached to the prefab.
Then, I add every item (currently I am adding only one for testing purposes) to a List, iterate that list, and add the prefab to the Content of a ScrollView:
for(int i = 0; i < listaSkills.Count; i++)
{
GameObject listItem = Instantiate(SkillPrefab) as GameObject;
listItem.GetComponent<SkillManager>().skill = listaSkills[i];
//listItem.transform.SetParent(SkillsContent.transform, false);
listItem.transform.parent = SkillsContent.transform;
}
When I run this, no item is seen in the ScrollView, but I can see the SkillItem added to the hierarchy:
If I move to Scene tab after playing, I see a square with red lines crossing it:
Why is my item not displaying? Why the red cross? How can I populate my ScrollView?
EDIT:
This is the code of SkillManager, the script added to SkillPrefab:
public class SkillManager : MonoBehaviour
{
public TMP_InputField toSpend;
public TMP_InputField rangos;
public TMP_InputField modificadores;
public TMP_InputField total;
public Button plusButton;
public Button minusButton;
public TMP_Text nombre;
public Skill skill;
private int modificador;
private int pointsToSpend;
private int totalPoints;
// Start is called before the first frame update
void Start()
{
print("Start");
if(total!=null)
total.text = "0";
if(modificadores!=null)
modificadores.text = "0";
if (toSpend != null)
{
toSpend.GetComponent<TMP_InputField>().text = GetSkillPoints();
totalPoints = int.Parse(total.GetComponent<TMP_InputField>().text);
pointsToSpend = int.Parse(toSpend.GetComponent<TMP_InputField>().text);
}
else
{
GameObject GameObjectToSpend = GameObject.FindGameObjectWithTag("tospend");
toSpend = GameObjectToSpend.GetComponent<TMP_InputField>();
if (toSpend == null)
{
print("Sigue siendo nulo");
}
else
{
toSpend.text= GetSkillPoints();
//totalPoints = int.Parse(total.GetComponent<TMP_InputField>().text);
if(total!=null)
totalPoints = int.Parse(total.text);
if(toSpend!=null)
pointsToSpend = int.Parse(toSpend.text);
}
}
if (skill != null)
{
modificador = GetModificador(skill);
string sModificador = modificadores.GetComponent<TMP_InputField>().text;
int iModificador = int.Parse(sModificador);
modificadores.GetComponent<TMP_InputField>().text = iModificador.ToString();
}
if (plusButton != null)
{
plusButton.onClick.AddListener(PlusButtonClicked);
minusButton.onClick.AddListener(MinusButtonClicked);
}
}
private string GetSkillPoints()
{
return "1";
}
public void MinusButtonClicked()
{
string ranks = rangos.GetComponent<TMP_InputField>().text;
int ranksInt = int.Parse(ranks);
if (ranksInt > 0)
{
int newRank = ranksInt - 1;
pointsToSpend += 1;
rangos.GetComponent<TMP_InputField>().text = newRank.ToString();
toSpend.GetComponent<TMP_InputField>().text = pointsToSpend.ToString();
total.GetComponent<TMP_InputField>().text = (newRank + modificador).ToString();
skill.Puntos = newRank;
}
}
public void PlusButtonClicked()
{
string ranks=rangos.GetComponent<TMP_InputField>().text;
int ranksInt = int.Parse(ranks);
Character character = Almacen.instance.Character;
int level = character.CharacterLevel;
if (ranksInt < level && pointsToSpend > 0)
{
int newRank = ranksInt + 1;
rangos.GetComponent<TMP_InputField>().text = newRank.ToString();
pointsToSpend -= 1;
toSpend.GetComponent<TMP_InputField>().text = pointsToSpend.ToString();
total.GetComponent<TMP_InputField>().text = (newRank + modificador).ToString();
skill.Puntos = newRank;
}
}
private int GetModificador(Skill skill)
{
int retorno=0;
if (skill.Clasea)
{
retorno += 3;
}
else
{
retorno += 0;
}
retorno += GetModificadorCaracteristica();
return retorno;
}
private int GetModificadorCaracteristica()
{
Utils utils = new Utils();
int retorno = 0;
int characteristic=0;
switch (skill.Caracteristica)
{
case "Fue":
characteristic = Almacen.instance.Character.EffectiveStr;
break;
case "Des":
characteristic = Almacen.instance.Character.EffectiveDex;
break;
case "Con":
characteristic = Almacen.instance.Character.EffectiveCon;
break;
case "Int":
characteristic = Almacen.instance.Character.EffectiveInt;
break;
case "Sab":
characteristic = Almacen.instance.Character.EffectiveWis;
break;
case "Car":
characteristic = Almacen.instance.Character.EffectiveCha;
break;
}
retorno = utils.GetCharModifier(characteristic);
return retorno;
}
}
it looks like you instantiate the object as a GameObject. but this will not be seen in the canvas because it isn't a UI component. you may want to add a sprite or image to the component and instantiate that into the Canvas. it will look something like this:
public class SkillPrefab
{
//put all your variables here!!!
public Sprite skillSprite;
}
public class YourClassName : MonoBehaviour
{
[SerializeField]
public List<SkillPrefab> skills = new List<SkillPrefab>();
private void Update()
{
Sprite listItem = Instantiate(skills[0].skillSprite); //the index is the skill you want to spawn in the list.
}
}
this does take into account that you have made your skills into a list of skills that you can acces.

How to spawn an object using the FlyWeight Pattern

So I've been setting up this test to implement the flyweight pattern. It's where I create an object class and a factory to basically spawn the same kind of object with different properties, in this case, color, size, and shape. So I have a dropdown menu for each property and a button to create the object. I want to use the getobject function in the factory class to create the object, but I can't seem to create it right. I got the shape, but not the color or size. It has something to do with the parameters I set up for the function. I don't want to just do what I'm doing right now to spawn cubes and cylinders. That's just a test. If anyone could come up with a way around this, I appreciate it thank you.
public class FlyWeight : MonoBehaviour
{
public Button CreateButton;
List<string> colors = new List<string>() { "Choose Color", "Red", "Blue", "Green" };
List<string> shapes = new List<string>() { "Choose Shape", "Sphere", "Cube", "Cylinder" };
List<string> sizes = new List<string>() { "Choose Size", "Small", "Medium", "Large" };
public Dropdown Shapes;
public Dropdown Colors;
public Dropdown Sizes;
private void Start()
{
Button button = CreateButton.GetComponent<Button>();
Shapes.AddOptions(shapes);
Colors.AddOptions(colors);
Sizes.AddOptions(sizes);
}
public void TaskOnClick()
{
if (Shapes.value == 1)
{
var sphere= Factory.getObject(GameObject.CreatePrimitive(PrimitiveType.Sphere), getSize(), getColor());
}
else if (Shapes.value == 2)
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.GetComponent<Renderer>().material.color = getColor();
cube.transform.localScale = getSize();
}
else if (Shapes.value == 3)
{
var cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
cylinder.GetComponent<Renderer>().material.color = getColor();
cylinder.transform.localScale = getSize();
}
}
public Color getColor()
{
if (Colors.value == 1) { return Color.red; }
else if (Colors.value == 2) { return Color.blue; }
else if (Colors.value == 3) { return Color.green; }
else return Color.white;
}
public Vector3 getSize()
{
if (Sizes.value == 1) { return gameObject.transform.localScale = new Vector3(1, 1, 1); }
else if (Sizes.value == 2) { return gameObject.transform.localScale = new Vector3(2, 2, 2); }
else { return gameObject.transform.localScale = new Vector3(3, 3, 3); }
}
}
Object Class
public class Object
{
private Color color;
private Vector3 size;
private GameObject shape;
private int x, y;
public Object (GameObject shape, Vector3 size,Color color)
{
this.color = color;
this.size = size;
this.shape = shape;
}
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
}
Factory Class
public class Factory
{
private static List<Object> objects = new List<Object>();
public static Object getObject(GameObject shape,Vector3 size, Color color)
{
Object obj = null;
if (obj == null)
{
obj = new Object(shape, size, color);
objects.Add(obj);
}
return obj;
}
}

Unity 5 Inventory system not working

Hello programmers all around the world. I have made myself an inventory system for my game. Only problem is that when I click on item and then drag it to and empty slot it doesn't move and I kinda don't see the error which I am having and I have tried to debug it but without success any help? Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Inventory : MonoBehaviour {
private RectTransform inventoryRect;
private float inventoryWidth;
private float inventoryHeight;
public int slots;
public int rows;
public float slotPaddingLeft;
public float slotPaddingTop;
public float slotSize;
public GameObject slotPrefab;
private static Slot from;
private static Slot to;
private List<GameObject> allslots;
public GameObject iconPrefab;
private static GameObject hoverObject;
private static int emptySlots;
public Canvas canvas;
private float hoverYOffset;
private bool isPressed;
public EventSystem eventSystem;
public static int EmptySlots{
get{ return emptySlots;}
set{ emptySlots = value;}
}
// Use this for initialization
void Start () {
CreateLayout ();
canvas.enabled = false;
isPressed = false;
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.I)) {
if (Input.GetKeyDown (KeyCode.I)) {
canvas.enabled = false;
}
canvas.enabled = true;
}
if (Input.GetMouseButtonUp (0)) {
if (!eventSystem.IsPointerOverGameObject (-1) && from != null) {
from.GetComponent<Image> ().color = Color.white;
from.ClearSlot ();
Destroy (GameObject.Find ("Hover"));
to = null;
from = null;
hoverObject = null;
}
}
if (hoverObject != null) {
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle (canvas.transform as RectTransform, Input.mousePosition, canvas.worldCamera, out position);
position.Set (position.x, position.y - hoverYOffset);
hoverObject.transform.position = canvas.transform.TransformPoint (position);
}
}
private void CreateLayout(){
allslots = new List<GameObject> ();
hoverYOffset = slotSize * 0.01f;
emptySlots = slots;
inventoryWidth = (slots / rows) * (slotSize + slotPaddingLeft) + slotPaddingLeft;
inventoryHeight = rows * (slotSize + slotPaddingTop) + slotPaddingTop;
inventoryRect = GetComponent<RectTransform> ();
inventoryRect.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, inventoryWidth);
inventoryRect.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, inventoryHeight);
int colums = slots / rows;
for (int y = 0; y < rows; y++) {
for (int x = 0; x < colums; x++) {
GameObject newSlot = (GameObject)Instantiate (slotPrefab);
RectTransform slotRect = newSlot.GetComponent<RectTransform> ();
newSlot.name = "Slot";
newSlot.transform.SetParent (this.transform.parent);
slotRect.localPosition = inventoryRect.localPosition + new Vector3 (slotPaddingLeft * (x + 1) + (slotSize * x), -slotPaddingTop * (y + 1) - (slotSize * y));
slotRect.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, slotSize);
slotRect.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, slotSize);
allslots.Add (newSlot);
}
}
}
public bool AddItem(Item item){
if (item.maxSize == 1) {
PlaceEmpty (item);
return true;
}
else {
foreach (GameObject slot in allslots) {
Slot temporary = slot.GetComponent<Slot> ();
if (!temporary.IsEmpty) {
if (temporary.CurrentItem.type == item.type && temporary.IsAvailable) {
temporary.AddItem (item);
return true;
}
}
}
if (emptySlots > 0) {
PlaceEmpty (item);
}
}
return false;
}
private bool PlaceEmpty(Item item){
if (emptySlots > 0) {
foreach (GameObject slot in allslots) {
Slot temporary = slot.GetComponent<Slot> ();
if (temporary.IsEmpty) {
temporary.AddItem (item);
emptySlots--;
return true;
}
}
}
return false;
}
public void MoveItem(GameObject clicked){
if (from == null) {
if (!clicked.GetComponent<Slot> ().IsEmpty) {
from = clicked.GetComponent<Slot> ();
from.GetComponent<Image> ().color = Color.gray;
hoverObject = (GameObject)Instantiate (iconPrefab);
hoverObject.GetComponent<Image> ().sprite = clicked.GetComponent<Image> ().sprite;
hoverObject.name = "Hover";
RectTransform hoverTransform = hoverObject.GetComponent<RectTransform> ();
RectTransform clickedTransform = clicked.GetComponent<RectTransform> ();
hoverTransform.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, clickedTransform.sizeDelta.x);
hoverTransform.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, clickedTransform.sizeDelta.y);
hoverObject.transform.SetParent (GameObject.Find ("Canvas").transform, true);
hoverObject.transform.localScale = from.gameObject.transform.localScale;
}
}
else if (to = null) {
to = clicked.GetComponent<Slot> ();
Destroy (GameObject.Find ("Hover"));
}
if (to != null && from != null) {
Stack<Item> tmpTo = new Stack<Item> (to.Items);
to.AddItems (from.Items);
if (tmpTo.Count == 0) {
from.ClearSlot ();
}
else {
from.AddItems (tmpTo);
}
from.GetComponent<Image> ().color = Color.white;
to = null;
from = null;
hoverObject = null;
}
}
}
The method which is causing the problem is the MoveItem() sadly it is not a nullreference or nullpointer and I simply am out of ideas been strugling with it for a couple of days... Any advice on how to fix this would be helpfull and much welcomed indeed. Thanks in advance!
I haven't taken a long look at your code but right away I saw this issue:
else if (to = null) {
to = clicked.GetComponent<Slot> ();
Destroy (GameObject.Find ("Hover"));
}
This is causing the end location to be set to null. To fix this, change to double equals like so:
else if (to == null) {
to = clicked.GetComponent<Slot> ();
Destroy (GameObject.Find ("Hover"));
}
If this does not solve your problem, let me know and I'll look at your code harder.

passing method name as parameter for threadpool queuserworkitem

QueUserWorkItem is supposed to accept a delegate but i found exercise that passes instance method name instead of delegate like this:
public class Fibonacci
{
private int _n;
private int _fibOfN;
private ManualResetEvent _doneEvent;
public int N { get { return _n; } }
public int FibOfN { get { return _fibOfN; } }
// Constructor.
public Fibonacci(int n, ManualResetEvent doneEvent)
{
_n = n;
_doneEvent = doneEvent;
}
// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
{
int threadIndex = (int)threadContext;
Console.WriteLine("thread {0} started...with id={1}", threadIndex,Thread.CurrentThread.ManagedThreadId);
_fibOfN = Calculate(_n);
Console.WriteLine("thread {0} result calculated...", threadIndex);
_doneEvent.Set();
}
// Recursive method that calculates the Nth Fibonacci number.
public int Calculate(int n)
{
if (n <= 1)
{
return n;
}
return Calculate(n - 1) + Calculate(n - 2);
}
}
public class Program
{
static void Main()
{
const int FibonacciCalculations = 10;
// One event is used for each Fibonacci object.
ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
Random r = new Random();
// Configure and start threads using ThreadPool.
Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
for (int i = 0; i < FibonacciCalculations; i++)
{
doneEvents[i] = new ManualResetEvent(false);
Fibonacci f = new Fibonacci(r.Next(20, 40), doneEvents[i]);
fibArray[i] = f;
ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback , i);
}
for (int x = 0; x < 10;x++ )
{
Console.WriteLine("x");
}
// Wait for all threads in pool to calculate.
WaitHandle.WaitAll(doneEvents);
Console.WriteLine("All calculations are complete.");
// Display the results.
for (int i = 0; i < FibonacciCalculations; i++)
{
Fibonacci f = fibArray[i];
Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
}
}
}
why does this work? I do not see implicit or explicit delegate being passed

Blackberry how to design the Screen like grid view

I am very new to blackberry development and i don't even know how to start. I already read some part of it from it's official site
http://developer.blackberry.com/devzone/files/design/bb7/UI_Guidelines_BlackBerry_Smartphones_7_1.pdf
and other so many link, but i can not post all the link as it is saying thay if you want to post more links then you must have 10 reputation and i dont have that so sorry for that,
Now my question is i want to design layout like this http://postimg.org/image/we3leycsd/
How can i design exactly this kind of layout. I am using eclipse for Blackberry development.
Please help i already tried many things but i am not able to achieve this.
Your any kind of help would be appreciated. Thank you in advance.
I'd create a custom HorizontalFieldManager with n VerticalFieldManagers inside, then override the add and delete methods. Here is something I made before, that should work for you, it adds the new fields to the shortest column.
StaggeredListView.java:
public class StaggeredListView extends HorizontalFieldManager
{
private int column_spacing = 0;
public StaggeredListView(int columns)
{
super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR | USE_ALL_WIDTH);
if (columns < 1)
{
throw new RuntimeException("Number of columns needs to be larger than 0.");
}
final int width = Display.getWidth() / columns;
for (int i = 0; i < columns; i++)
{
VerticalFieldManager vfm = new VerticalFieldManager(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR)
{
protected void sublayout(int maxWidth, int maxHeight)
{
maxWidth = Math.min(width, getPreferredWidth());
maxHeight = Math.min(maxHeight, getPreferredHeight());
super.sublayout(width, maxHeight);
super.setExtent(width, maxHeight);
}
};
super.add(vfm);
}
}
public int getColumnCount()
{
return getFieldCount();
}
/**
* Sets the spacing between columns.
*
* <p>
* Spacing between fields is <i><b>not</b></i> set.
* </p>
*/
public void setColumnSpacing(int spacing)
{
if (spacing < 0) throw new RuntimeException("Column spacing my not be negative.");
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
((VerticalFieldManager) getField(i)).setPadding(0, 0, 0, spacing);
}
column_spacing = spacing;
}
/**
* Get the value currently assigned via the {#link #setColumnSpacing(int)} method.
*
* #return
*/
public int getColumnSpacing()
{
return column_spacing;
}
/**
* Deletes all fields from each of the columns.
*/
public void clear()
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
((VerticalFieldManager) getField(i)).deleteAll();
}
}
/**
* Delete specified field from the columns.
*
* <p>
* Does <b><i>not</i></b> rearrange fields.
* </p>
*/
public void delete(Field field)
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
try
{
((VerticalFieldManager) getField(i)).delete(field);
break;
} catch (IllegalArgumentException e)
{
// field not in this manager
}
}
}
/**
* Adds the field to the column with the least height.
*/
public void add(Field field)
{
// find the vfm with least height
int index = 0;
int height = ((VerticalFieldManager) getField(index)).getPreferredHeight();
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
int temp_height = ((VerticalFieldManager) getField(i)).getPreferredHeight();
if (temp_height < height)
{
height = temp_height;
index = i;
}
}
((VerticalFieldManager) getField(index)).add(field);
}
}
As for the item's contained in it, I'd create a field with an image and text, then paint it myself (I've had a lot of issues with focus and find it easier just to use paint).
You can use this to make a BaseButton http://developer.blackberry.com/bbos/java/documentation/tutorial_create_custom_button_1969896_11.html
BaseButton.java:
public abstract class BaseButton extends Field
{
// flags to indicate the current visual state
protected boolean _visible = true;
protected boolean _active;
protected boolean _focus;
protected boolean drawfocus = false;
private int touch_top = 0;
private int touch_right = 0;
private int touch_bottom = 0;
private int touch_left = 0;
protected boolean fire_on_click = true; // false fires on unclick
public BaseButton()
{
this(0);
}
public BaseButton(long style)
{
super((style & Field.NON_FOCUSABLE) == Field.NON_FOCUSABLE ? style : style | Field.FOCUSABLE);
}
/**
* Sets the radius around the button to trigger touch events.
* <p>
* (0,0,0,0) by default.
* </p>
*/
public void setTouchRadius(int top, int right, int bottom, int left)
{
touch_top = top;
touch_right = right;
touch_bottom = bottom;
touch_left = left;
}
protected void onFocus(int direction)
{
_focus = true;
invalidate();
super.onFocus(direction);
}
protected void onUnfocus()
{
if (_active || _focus)
{
_focus = false;
_active = false;
invalidate();
}
super.onUnfocus();
}
public void set_visible(boolean visible)
{
_visible = visible;
invalidate();
}
public boolean is_visible()
{
return _visible;
}
protected void drawFocus(Graphics g, boolean on)
{
if (drawfocus) super.drawFocus(g, on);
}
protected void layout(int width, int height)
{
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
protected boolean keyUp(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = false;
invalidate();
return true;
}
return false;
}
protected boolean keyDown(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = true;
invalidate();
}
return super.keyDown(keycode, time);
}
protected boolean keyChar(char character, int status, int time)
{
if (character == Characters.ENTER)
{
clickButton();
return true;
}
return super.keyChar(character, status, time);
}
protected boolean navigationClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean navigationUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean invokeAction(int action)
{
switch (action)
{
case ACTION_INVOKE :
{
clickButton();
return true;
}
}
return super.invokeAction(action);
}
protected boolean touchEvent(TouchEvent message)
{
boolean isOutOfBounds = touchEventOutOfBounds(message);
switch (message.getEvent())
{
case TouchEvent.CLICK :
if (!_active)
{
_active = true;
invalidate();
}
if (!isOutOfBounds)
{
if (fire_on_click) clickButton();
return true;
}
case TouchEvent.DOWN :
if (!isOutOfBounds)
{
if (!_active)
{
_active = true;
invalidate();
}
return true;
}
return false;
case TouchEvent.UNCLICK :
if (_active)
{
_active = false;
invalidate();
}
if (!isOutOfBounds)
{
if (!fire_on_click) clickButton();
return true;
}
case TouchEvent.UP :
if (_active)
{
_active = false;
invalidate();
}
default :
return false;
}
}
private boolean touchEventOutOfBounds(TouchEvent message)
{
int x = message.getX(1);
int y = message.getY(1);
return (x < 0 - touch_left || y < 0 - touch_top || x > getWidth() + touch_right || y > getHeight() + touch_bottom);
}
public void setDirty(boolean dirty)
{
}
public void setMuddy(boolean muddy)
{
}
public void clickButton()
{
if (_visible) fieldChangeNotify(0);
}
}
ImageSubtitleButton.java:
public class ImageSubtitleButton extends BaseButton
{
private static final int FOCUS_THINKNESS = 2;
String title;
Bitmap image_default;
int height;
public ImageSubtitleButton(String title, String image_default)
{
this.image_default = Bitmap.getBitmapResource(image_default);
setTitle(title);
}
public void setTitle(String title)
{
this.title = title;
height = image_default.getHeight() + getFont().getHeight() + (FOCUS_THINKNESS * 2);
updateLayout();
invalidate();
}
public int getPreferredWidth()
{
return Math.max(getFont().getAdvance(title), image_default.getWidth());
}
public int getPreferredHeight()
{
return height;
}
protected void paint(Graphics graphics)
{
int x = (getWidth() - image_default.getWidth()) / 2;
int y = 0;
graphics.drawBitmap(x, y, image_default.getWidth(), image_default.getHeight(), image_default, 0, 0);
if (_focus)
{
graphics.setColor(Color.BLUE); // your focus colour
for (int i = 0; i < FOCUS_THINKNESS; i++)
{
graphics.drawRect(x + i, y + i, image_default.getWidth() - (i * 2), image_default.getHeight() - (i * 2));
}
}
graphics.setColor(Color.BLACK);
y = image_default.getHeight();
graphics.drawText(title, x, y);
}
}
Now you can add these to your screen as follows:
StaggedListView listview = new StaggedListView(2);
ImageSubtitleButton button = new ImageSubtitleButton("test", "test.png");
listview.add(button);
add(listview);
You'll need to set the preferred width and height of the ImageSubtitleButton to keep it uniform, as in the example image you posted.
Apologies, I don't have time to create a full answer, but I personally would not use the HFM/VFM combination to do this. Instead use one Manager that provides the Grid. If you are using a late enough level OS you have GridFieldManager that does this,
GridFieldManager
but I have had mixed experiences with that Manager. So I generally use this Manager:
TableLayoutManager
I hope this gets you going.