Creating dynamic buttons on codenameone - codenameone

I am trying to make it so when i click a button another is created, and you can do this as many times as you want too. But I haven't been able to find a way to make it work, any ideas? I have tried creating a for loop but that just ends up overwriting the other buttons and deleting the tags.

Try something like this:
Form f = new Form(BoxLayout.y());
f.add(createButton("Click Me"));
f.show();
Then the method createButton():
private Button createButton(String title) {
Button b = new Button(title);
b.addActionListener(e -> {
Container c = b.getParent();
c.add(createButton(title));
c.revalidate();
});
return b;
}
I'm guessing the thing you missed is the call to revalidate() which must be invoked when you change a Form after it was already shown. Notice the first addition occurs before the form is shown and doesn't invoke revalidate().

Related

Update CodenameOne sidemenu command when a property value changes

I want to be able to change the title of my Side menu command based on the size of a ListProperty which is dynamically updated. I have tried to do this via a changeListener, but i can not get this to work.
Command cmdWishlist = tb.addMaterialCommandToRightSideMenu("Wishlist(" + Shop.getInstance().wishList.size() + ")", FontImage.MATERIAL_FAVORITE, e -> {
....
});
Shop.getInstance().wishList.addChangeListener(pl -> {
tb.revalidate();
});
If however, I open another form, and check the sidemenu, the change that I need is reflecting. How can I get this to work? By the way, I get the desired behavior if i put, say a label on the toolbar and setText("Wishlist(" + Shop.getInstance().wishList.size() + ") in the change listener.
Please point me in right direction
When we add a command to the side menu or a button we extract its values but don't automatically reflect updates as that can cause a potential memory leak by binding commands to components. The workaround is to modify the original underlying component too e.g.:
Button ui = tb.findCommandComponent(cmd);
ui.setText(newLabelForCommand);

Codename One - Start editing in the search bar programmatically

I need to start editing in the search bar programmatically when the Form is shown. Because I didn't find any API for that, I wrote this code inside the Form:
addShowListener(l -> {
for (int i = 0; i <= getToolbar().getComponentCount(); i++) {
if (getToolbar().getComponentAt(i) instanceof Button) {
Button btn = (Button) getToolbar().getComponentAt(i);
if (btn.getUIID().equals("TitleCommand")) {
btn.pressed();
btn.released();
}
if (btn.getUIID().equals("BackCommand")) {
btn.addActionListener(ev -> {
backForm.showBack();
});
}
}
}
});
The problems of this code:
it relies on the current implementation of the method Form.getToolbar().addSearchCommand, that created in the toolbar a button with UIID TitleCommand (the search icon on the right) and another button with UIID BackButton (the arrow on the left).
my listener added to the back button doesn't work: instead of show the backForm, it shows the toolbar without the search bar.
So... my question is how to implement what I need with a better coding. Is it necessary to do an RFE to expose an API like Toolbar.startSearchEditingAsync()? And how can I change the default actionListener of backButton?
If you need to initiate it before it's shown you might need something more elaborate similar to Form.setEditOnShow().
This seemed a bit simpler in my head when I started it but once I started I had to finish so I implemented this here: https://github.com/codenameone/CodenameOne/commit/86fea99196dd5a453988ede8217e0809e529469a
It should work, let me know if it has issues.

remove event listener as3

I'm almost finished with a quiz of mine. I've encountered an error which I have finally pinpointed. But first I'll tell you some background info on the code.
Background
On stage, there exist 4 button components registered as movie clips. These are later stored in an array. When a certain icon is clicked on stage, these buttons are to be activated by adding event listeners to all of them. When a button is pressed, it checks if it's the 'correct' answer and removes the event listeners.
Now I have done extensive checks and narrowed down the problem to the following.
Code
This function will add button listeners to each button recursively. Note that the variable 'num' is a fixed integer between 1 - 4 which is generated earlier into the code and used for many 'if' cases.
function addButtonListener(num:int):void
{
for (var obj:Object in _buttons)
{
_buttons[obj].addEventListener(MouseEvent.CLICK, checkans(num));
}
}
This function is basically the opposite and also disables the buttons
function removeButtonListener(num:int):void
{
for (var obj:Object in _buttons)
{
_buttons[obj].removeEventListener(MouseEvent.CLICK, checkans(num));
_buttons[obj].enabled = false;
}
}
Now one thing I noticed through the use of trace functions is that the code correctly adds the button listeners but it does not remove them.
This function calls for each button to be removed.
function checkans(num:int):Function
{
return function(e:MouseEvent):void
{
if (e.currentTarget.label == xmlNodes)
{
points = points + (2 * num);
scoreBox.text = points.toString();
}
else
{
trace("Incorrect!");
}
if(myText.parent){
myText.parent.removeChild(myText)
}
closeShowQuestion(num);//closes a previous function
removeButtonListener(num);//Should I pass this variable into the end function?
GoFishing.addEventListener(MouseEvent.CLICK, fish);//Starts the process again.
}
}
So am I removing the event listeners incorrectly?
Do you need to see more code to be sure?
Thanks in advance!
removeEventListener must use the SAME function that was used in addEventListener.
Your checkans function always returns a NEW function, so it will not be the same for add and remove.
If you have to pass a num into your listener function, do it other way. Make it a property of a button or store externally etc.

Swapping Buttons in array

I have an array of my custom made buttons:
Button buttons[5]
Now I want to swap two elements of this array, for example buttons[1] and buttons[2]. How do I do this? Just stating the following, doesnt work:
Button help = buttons[1];
buttons[1] = buttons[2];
buttons[2] = help;
Can anybody help me with this?
I have solved using a pointer array:
Button *pntArray[5];
Button *help;
pntArray[0]=&buttons[0];
pntArray[1]=&buttons[1];
help=pntArray[0];
pntArray[0]=pntArray[1];
pntArray[1]=help;
QObject base class does not allow the assignment operator or the copy constructor. Unless you have manually created these (which is usually unwise), declare your instances on the heap and use pointers in the array instead.
// Instantiate the buttons however you like, if you were just creating them
// on the stack before, a default initialisation should suffice. Though
// normally in Qt you would at least pass the 'owning' widget as the parent
// so you don't need to worry about deleting the buttons.
QVector<Button*> buttons(5);
for ( Button* button : buttons ) { // C++11 only!
button = new Button();
}
// Then whenever you need to swap two entries:
std::swap( buttons[1], buttons[2] );

ExtJS form creating help

I'm using extJS 4.
I have a form pop up every time you click edit profile.
The problem is that every time you click edit Profile another form pops up so you can just keep clicking.
Is there a way to make the form only pop up if there isn't one already up.
Thanks for the help!!!
The problem sounds like you are creating a new window on every click of the "edit profile" button/link.
What you need to do is put a check in at the beginning of your form code to check to see if it exists first. If it doesn't, create the window and .show() it... Otherwise, you will just need to .show() it. Be sure to also reset the form if need be. You will also want to try and hide the window instead of destroying it. Otherwise, you will be creating new objects every time.
You can make your form modal, so to block entire interface until you close it, or you can use something like this to your controller to create form:
editProfile: function(button) {
var me = this;
if (!me.win) {
me.win = Ext.widget('editProfile');
// delete the me.win reference if the window gets destroyed
me.win.on('destroy', function() {
delete me.win;
return;
});
}
me.win.show();
}

Resources