I'm very new to CodenameOne, and I'm developing an app with a toolbar menu. It works just the first time, I click the menu entry and when I come back to the main class toolbar stops working until I rotate or stop/resume the app.
Thank's in advance.
My code:
public class FDRMobileApp {
private Form current;
public static Form hi;
private Resources theme;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
}
public void start() {
if(current != null){
current.show();
return;
}
hi = new Form("FDR", BoxLayout.y());
Toolbar tb = hi.getToolbar();
tb.addMaterialCommandToSideMenu("Home", FontImage.MATERIAL_HOME, e->{});
tb.addMaterialCommandToSideMenu("Orari e Turni", FontImage.MATERIAL_MEMORY, e-> new OrariTurniForm(theme).show());
tb.addMaterialCommandToSideMenu("Contatti", FontImage.MATERIAL_INFO, e-> new ContattiForm(theme).show());
tb.addMaterialCommandToSideMenu("Dove siamo", FontImage.MATERIAL_MAP, e-> new MapForm(theme).show());
hi.show();
}
public void stop() {
current = getCurrentForm();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = getCurrentForm();
}
}
public void destroy() {
}
}
And a Form:
class MapForm extends Form {
public MapForm(Resources theme) {
super("Dove siamo");
getToolbar().setBackCommand("", e -> {
FDRMobileApp.hi.showBack();
});
}
}
There is a bug in the current update due to the switch to the on-top menu. We'll release an update later today which should fix the navigation issue in the app.
Related
Until today, my code has been working great. However, I've just started getting NPE when using the Crisp CN1lib. It turns out that BrowserComponent.setProperty() is the culprit. Here is my stacktrace
java.lang.NullPointerException
at com.codename1.impl.javase.JavaSEPort.setBrowserProperty(JavaSEPort.java:11340)
at com.codename1.ui.BrowserComponent.setProperty(BrowserComponent.java:607)
Looks like the JavaSEPort.setBrowserProperty() is causing it. Github shows the code was edited 2 days ago so maybe something broke.
My code is pretty basic:
import static com.codename1.ui.CN.*;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.BrowserComponent;
import com.codename1.ui.Toolbar;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.layouts.BorderLayout;
/**
* This file was generated by Codename One for the purpose
* of building native mobile applications using Java.
*/
public class MyApplication {
private Form current;
private Resources theme;
public void init(Object context) {
// use two network threads instead of one
updateNetworkThreadCount(2);
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
addNetworkErrorListener(err -> {
// prevent the event from propagating
err.consume();
if(err.getError() != null) {
Log.e(err.getError());
}
Log.sendLogAsync();
Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null);
});
}
public void start() {
if(current != null){
current.show();
return;
}
BrowserComponent browser = new BrowserComponent();
browser.addWebEventListener(BrowserComponent.onLoad, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
}
});
browser.setProperty("UseWideViewPort", true);
browser.setProperty("LoadWithOverviewMode", true);
browser.setProperty("DatabaseEnabled", true);
browser.setProperty("BuiltInZoomControls", true);
browser.setProperty("DisplayZoomControls", false);
browser.setProperty("WebContentsDebuggingEnabled", true);
browser.setFireCallbacksOnEdt(true);
browser.setURL("https://www.instagram.com/brianabette/");
Form hi = new Form("Hi World", new BorderLayout());
hi.add(BorderLayout.CENTER, browser);
hi.show();
}
public void stop() {
current = getCurrentForm();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = getCurrentForm();
}
}
public void destroy() {
}
}
Any pointers? Bug maybe?
We just made some performance improvements to BrowserComponent. Looks like we missed a spot here, so there is a regression. It is already fixed in Git and will be included in the next update next Friday.
I want to change the text of the command in title bar programmatically but it is not happening. Why doesn't the command name "aaa" changes to "bbb" in the following code?
labourChargeSumCommand = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
}
};
labourChargeSumCommand.setCommandName("aaa");
getToolbar().addCommandToRightBar(labourChargeSumCommand);
cb1.addActionListener(e -> {
if (cb1.isSelected()) {
labourChargeSumCommand.setCommandName("bbb");
getToolbar().revalidate();
}
});
Update: all my code
public class MyApplication {
private Form current;
private Resources theme;
Command labourChargeSumCommand;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
}
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("Hi World"));
hi.show();
labourChargeSumCommand = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
}
};
labourChargeSumCommand.setCommandName("aaa");
hi.getToolbar().addCommandToRightBar(labourChargeSumCommand);
Button bb = new Button("bb");
bb.addActionListener(e -> {
if (true) {
labourChargeSumCommand.setCommandName("bbb");
System.out.println(labourChargeSumCommand.getCommandName());
hi.getToolbar().revalidate();
hi.getToolbar().repaint();
}
});
hi.add(bb);
}
}
Here I have added a btn and kept code inside its action listener, that's all.
change command text programatically
I just comment this code //hi.show(); add it at the end. Becuase of this
revalidate() not worked, So that labourChargeSumCommand.setCommandName("bbb"); text not updated.
public class MyApplication {
private Form current;
private Resources theme;
Command labourChargeSumCommand;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
}
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("Hi World"));
//hi.show();
labourChargeSumCommand = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
}
};
labourChargeSumCommand.setCommandName("aaa");
hi.getToolbar().addCommandToRightBar(labourChargeSumCommand);
Button bb = new Button("bb");
bb.addActionListener(e -> {
if (true) {
labourChargeSumCommand.setCommandName("bbb");
System.out.println(labourChargeSumCommand.getCommandName());
hi.getToolbar().revalidate();
hi.getToolbar().repaint();
}
});
hi.add(bb);
hi.show();
}
}
Setting the command name after adding it to the Toolbar doesn't change the text.
What I do is creating a new command and look for the index of the added command, and replace it with the new one.
This is not so efficient nor is it the best way, but it's a hack that works for me.
Let's say we added the command to the right bar and its the last component in the ToolBar container (You can find it's position through Component Inspector):
private void switchCommand(Toolbar t, Command cmd) {
try {
int pos = t.getComponentCount() - 1;
Button cmdButton = new Button(cmd.getCommandName());
cmdButton.setUIID("TitleCommand");
cmdButton.setCommand(cmd);
t.replaceAndWait(t.getComponentAt(pos), cmdButton, null);
t.getComponentForm().revalidate();
} catch (Exception ex) {
}
}
Then I do this:
labourChargeSumCommand = Command.create("aaa", null, evt -> {});
getToolbar().addCommandToRightBar(labourChargeSumCommand);
cb1.addActionListener(e -> {
if (cb1.isSelected()) {
labourChargeSumCommand = Command.create("bbb", null, evt -> {});
switchCommand(getToolbar(), labourChargeSumCommand);
}
});
public class MyApplication {
private Form current;
private Resources theme;
Command labourChargeSumCommand;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
}
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("Hi World"));
hi.show();
labourChargeSumCommand = Command.create("aaa", null, evt -> {});
hi.getToolbar().addCommandToRightBar(labourChargeSumCommand);
Button bb = new Button("bb");
bb.addActionListener(e -> {
if (true) {
labourChargeSumCommand = Command.create("bbb", null, evt -> {});
switchCommand(getToolbar(), labourChargeSumCommand);
System.out.println(labourChargeSumCommand.getCommandName());
}
});
hi.add(bb);
}
}
I hand-coded my app using CN1 (based on CN1's standard form template). Mostly for using Calendar for appointment app (I have reason not to use Picker).
Here's my main Form class
public class celebriesta {
private Form current;
private Resources theme;
private Form home;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
}
public void start() {
if (current != null) {
current.show();
return;
}
home = new Form("Home", BoxLayout.y());
mainCalendar Calendar = new mainCalendar();
home.addComponent(Calendar);
Calendar.setUIID("Calendar");
//Create Form1 and Form2 and set a Back Command to navigate back to the home Form
Form form1 = new Form("Form1");
setBackCommand(form1);
Form form2 = new Form("Form2");
setBackCommand(form2);
Form form3 = new Form("Form3");
setBackCommand(form3);
//Add navigation commands to the home Form
NavigationCommand cmd1 = new NavigationCommand("Form1");
cmd1.setNextForm(form1);
home.getToolbar().addCommandToSideMenu(cmd1);
NavigationCommand cmd2 = new NavigationCommand("Form2");
cmd2.setNextForm(form2);
home.getToolbar().addCommandToSideMenu(cmd2);
NavigationCommand cmd3 = new NavigationCommand("Form3");
cmd3.setNextForm(form3);
Calendar.createDay().pressed();
Calendar.createDay().released();
Calendar.createDay().setCommand(cmd3);
//Add Edit commands to the home Form context Menu
Image im = FontImage.createMaterial(FontImage.MATERIAL_MODE_EDIT, UIManager.getInstance().getComponentStyle("Command"));
Command edit = new Command("", im) {
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Editing");
}
};
home.getToolbar().addCommandToRightBar(edit);
home.show();
}
protected void setBackCommand(Form f) {
Command back = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
home.showBack();
}
};
Image img = FontImage.createMaterial(FontImage.MATERIAL_ARROW_BACK, UIManager.getInstance().getComponentStyle("TitleCommand"));
back.setIcon(img);
f.getToolbar().addCommandToLeftBar(back);
f.getToolbar().setTitleCentered(true);
f.setBackCommand(back);
}
public void stop() {
current = getCurrentForm();
}
public void destroy() {
}}
I've override Calendar class accordingly
public class mainCalendar extends Calendar { #Override
protected Button createDay(){ Button day = new Button();
Image im = FontImage.createMaterial(FontImage.MATERIAL_MODE_EDIT, UIManager.getInstance().getComponentStyle("Command"));
day.setIcon(im);
return day;
}
#Override
protected void updateButtonDayDate(Button dayButton, int currentMonth, int day) {
//Customize day values
dayButton.setText("" +day);
}}
The main Form manages to get to Form 1 & 2 (sidemenu). I know Form 3 does exist but not sure why it didn't managed to be 'reached' from createDay(). And I suspect it's something wrong somewhere around this code in main Form
Calendar.createDay().pressed();
Calendar.createDay().released();
Calendar.createDay().setCommand(cmd3);
Need advise and/or help.
Have a look at a sample code here that creates a custom calendar day component. You don't need the below code:
Calendar.createDay().pressed();
Calendar.createDay().released();
Calendar.createDay().setCommand(cmd3);
Calendar day pressing and releasing is handled through an actionListener which you can implement through overriding the bindDayListener() if you're using a custom day component or addDayActionListener() if you're using the default day button. An example will be:
Calendar.addDayActionListener(evt -> {
//show your next form here
});
Unless you need a high-level customization, I don't see a point subclassing the Calendar class.
i am trying to make an app in Codename one where i want to create a handburger menu on the right side at the top of the screen and a back button on the left side, but cannot get it to work I know it can be done where you have a handburger menu on the left side and a button on the right side. I made a picture of how I want it to look like. The back button is added in paint and not through the code.
Picture of app example
below is the code that I have used to get the menu on the right side.
public class MainForm {
public static Form mainForm;
Command cmd_back, cmd_AboutTheApp;
private enum SideMenuMode {
SIDE, RIGHT_SIDE {
public String getCommandHint() {
return SideMenuBar.COMMAND_PLACEMENT_VALUE_RIGHT;
}
};
public String getCommandHint() {
return null;
}
public void updateCommand(Command c) {
String h = getCommandHint();
if(h == null) {
return;
}
c.putClientProperty(SideMenuBar.COMMAND_PLACEMENT_KEY, h);
}
};
SideMenuMode mode = SideMenuMode.RIGHT_SIDE;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
UIManager.getInstance().setThemeProps(theme.getTheme theme.getThemeResourceNames()[0]));
UIManager.getInstance().getLookAndFeel().setMenuBarClass(SideMenuBar.class);
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
}
public void start() {
if(mainForm != null){
mainForm.show();
return;
}
mainForm = new Form();
mainForm.setTitleComponent(title);
mainForm.setLayout(new BorderLayout());
addCommands(mainForm);
}
private void addCommands(Form f){
cmd_Back = new Command("Back");
final Button btn_Back = new Button("Back");
cmd_Back.putClientProperty("TitleCommand", btn_Back);
btn_BackButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//do some thing
}
});
cmd_AboutTheApp = new Command("About the app");
final Button btn_AboutTheApp = new Button("About the app");
cmd_AboutTheApp.putClientProperty("SideComponent", btn_AboutTheApp);
btn_AboutTheApp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//do some thing
}
});
mode.updateCommand(cmd_Back);
f.addCommand(cmd_Back);
mode.updateCommand(cmd_AboutTheApp);
f.addCommand(cmd_AboutTheApp);
}
}
if I move the back button so that it is added after AboutTheApp button then the back button is displayed on the right side of the screen but also to the right of the menu, which is also on the right side. I've tried a lot of different ways but none seems to be working
We supported a right side menu bar in the SideMenuBar but not in the Toolbar API. We support placing components/commands in the left/right side of the title area in the Toolbar API but not in the SideMenuBar.
I guess the solution is to add support for the right menu bar into the Toolbar API but I'm not sure what the complexities are for such a change.
I suggest filing an RFE in the issue tracker asking for this but it probably won't be soon as we are closing the features for 3.3 right now.
I have an app that does this. Search Google Play (or App Store) for "Torquepower Diesel Cummins Engine" app.
in the theme Constants I set my own rightSideMenuImage and rightSideMenuPressImage, but the default hamburger menu may be OK for you.
On the beforeXXXX of each form I do something like this:
super.beforePartNumberForm(f);
Toolbar tb = createToolbar(f);
createBackCommand(f, tb);
addHelpX(tb);
addViewCartX(tb);
addCallTorquepowerX(tb);
addReverseSwipe(f);
create the toolbar
Toolbar createToolbar(Form f) {
Toolbar tb = new Toolbar();
f.setToolBar(tb);
Label l = new Label();
l.setIcon(res.getImage("tpd_logoZZ.png"));
tb.setTitleComponent(l);
return tb;
}
create the back button
void createBackCommand(Form f, Toolbar tb) {
Command c = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
back();
}
};
c.setIcon(res.getImage("black_left_arrow-512.png"));
c.setPressedIcon(res.getImage("grey_left_arrow-512.png"));
// MUST set this before adding to toolbar, else get null pointer
f.setBackCommand(c);
tb.addCommandToLeftBar(c);
}
add whatever commands are needed to the sidemenu
void addHelpX(Toolbar tb) {
Command c = new Command("Help") {
#Override
public void actionPerformed(ActionEvent evt) {
showForm("HelpForm", null);
}
};
c.putClientProperty(SideMenuBar.COMMAND_PLACEMENT_KEY, SideMenuBar.COMMAND_PLACEMENT_VALUE_RIGHT);
c.putClientProperty("SideComponent", new SideMenuItem(fetchResourceFile(), c.toString(), "very_basic_about.png"));
c.putClientProperty("Actionable", Boolean.TRUE);
tb.addCommandToSideMenu(c);
}
I use my own SideMenuItem which is:
public class SideMenuItem extends Button {
SideMenuItem() {
this("");
}
SideMenuItem(String s) {
super(s);
setUIID("SideMenuItem");
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(h);
}
SideMenuItem(Resources res, String s, String icon) {
super();
setIcon(res.getImage(icon));
setText(s);
setUIID("SideMenuItem");
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(h);
}
}
I'm trying to implement an Android style side menu and I'm having an issue implementing the rounded icon on top and labels below it before the sideCommands are added.
How do I implement this please?
You can use Toolbar API which allows you to add components to the Sidemenu.
Have a look at Flickr demo.
Instead of using tool.addCommandToSideMenu(Command) you should use tool.addComponentToSideMenu(yourComponent, CommandToPerform)
Example:
#Override
protected void beforeMain(Form f) {
//Store your commands before setting toolbar
List<Command> cmds = new ArrayList();
for (int i = 0; i < f.getCommandCount(); i++) {
cmds.add(f.getCommand(i));
}
Toolbar toolbar = new Toolbar();
f.setToolBar(toolbar);
Label lblTitle = new Label("My Form", "Title");
lblTitle.setEndsWith3Points(false);
toolbar.setTitleComponent(lblTitle);
// Use your stored commands after setting toolbar
for (Command cmd : cmds) {
toolbar.addCommandToSideMenu(cmd);
}
Container CustomContainer = ...
toolbar.addComponentToSideMenu(CustomContainer, new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
//What CustomContainer should do (if any)
}
});
f.revalidate();
}