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.
Related
I am trying to implement a simple web browser control in one of my apps. This is to help integrate a web app into a toolset i am creating.
The problem is, this web app absolutly loves popup windows....
When a popup is opened, it opens in an IE window which is not a child of the MDI Container form that my main window is part of.
How can i get any and all popups created by clicking links in my WebBrowser to be a child of my MDI container (similar to setting the MDIParent property of a form)?
Thanks in advance.
The web browser control supports the NewWindow event to get notified about a popup window. The Winforms wrapper however does not let you do much with it, you can only cancel the popup. The native COM wrapper permits passing back a new instance of the web browser, that instance will then be used to display the popup.
Taking advantage of this requires some work. For starters, use Project + Add Reference, Browse tab and select c:\windows\system32\shdocvw.dll. That adds a reference to the native COM interface.
Create a form that acts as the popup form. Drop a WebBrowser on it and make its code look similar to this:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
public WebBrowser Browser {
get { return webBrowser1; }
}
}
The Browser property gives access to the browser that will be used to display the web page in the popup window.
Now back to the main form. Drop a WebBrowser on it and make its code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://google.com");
}
SHDocVw.WebBrowser nativeBrowser;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
base.OnFormClosing(e);
}
void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel) {
var popup = new Form2();
popup.Show(this);
ppDisp = popup.Browser.ActiveXInstance;
}
}
The OnLoad method obtains a reference to the native COM interface, then subscribes an event handler to the NewWindow2 event. I made sure to unsubscribe that event in the FormClosing event handler, not 100% sure if that's necessary. Better safe then sorry.
The NewWindow2 event handler is the crux, note that the first argument allows passing back an untyped reference. That should be the native browser in the popup window. So I create an instance of Form2 and Show() it. Note the argument to Show(), that ensures that the popup is an owned window. Substitute this as necessary for your app, I assume you'd want to create an MDI child window in your case.
Do beware that this event doesn't fire for the window displayed when Javascript uses alert(). The browser doesn't treat that window as an HTML popup and doesn't use a browser window to display it so you cannot intercept or replace it.
I found that the best way to do this was to implement/sink the NewWindow3 event
Add the reference to c:\windows\system32\shdocvw.dll as mentioned in the other answers here.
Add event handler
SHDocVw.WebBrowser wbCOMmain = (SHDocVw.WebBrowser)webbrowser.ActiveXInstance;
wbCOMmain.NewWindow3 += wbCOMmain_NewWindow3;
Event method
void wbCOMmain_NewWindow3(ref object ppDisp,
ref bool Cancel,
uint dwFlags,
string bstrUrlContext,
string bstrUrl)
{
// bstrUrl is the url being navigated to
Cancel = true; // stop the navigation
// Do whatever else you want to do with that URL
// open in the same browser or new browser, etc.
}
Set "Embed Interop Types" for the "Interop.SHDocVw" assembly to false
Set the "local copy" to true.
Source for that help MSDN Post
Refining Hans answer, you can derive the WebBrowser for accessing the COM without adding the reference. It is by using the unpublished Winforms WebBrowser.AttachInterface and DetachInterface methods.
More elaborated here.
Here is the code:
Usage (change your WebBrowser instance to WebBrowserNewWindow2)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.webBrowser1.NewWindow2 += webBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
webBrowser1.NewWindow2 -= webBrowser_NewWindow2;
base.OnFormClosing(e);
}
void webBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
{
var popup = new Form1();
popup.Show(this);
e.PpDisp = popup.Browser.ActiveXInstance;
}
public WebBrowserNewWindow2 Browser
{
get { return webBrowser1; }
}
}
Code:
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SHDocVw
{
public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
public class WebBrowserNewWindow2EventArgs : EventArgs
{
public WebBrowserNewWindow2EventArgs(object ppDisp, bool cancel)
{
PpDisp = ppDisp;
Cancel = cancel;
}
public object PpDisp { get; set; }
public bool Cancel { get; set; }
}
public class WebBrowserNewWindow2 : WebBrowser
{
private AxHost.ConnectionPointCookie _cookie;
private WebBrowser2EventHelper _helper;
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void CreateSink()
{
base.CreateSink();
_helper = new WebBrowser2EventHelper(this);
_cookie = new AxHost.ConnectionPointCookie(
this.ActiveXInstance, _helper, typeof(DWebBrowserEvents2));
}
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachSink()
{
if (_cookie != null)
{
_cookie.Disconnect();
_cookie = null;
}
base.DetachSink();
}
public event WebBrowserNewWindow2EventHandler NewWindow2;
private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
{
private readonly WebBrowserNewWindow2 _parent;
public WebBrowser2EventHelper(WebBrowserNewWindow2 parent)
{
_parent = parent;
}
public void NewWindow2(ref object pDisp, ref bool cancel)
{
WebBrowserNewWindow2EventArgs arg = new WebBrowserNewWindow2EventArgs(pDisp, cancel);
_parent.NewWindow2(this, arg);
if (pDisp != arg.PpDisp)
pDisp = arg.PpDisp;
if (cancel != arg.Cancel)
cancel = arg.Cancel;
}
}
[ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
TypeLibType(TypeLibTypeFlags.FHidden)]
public interface DWebBrowserEvents2
{
[DispId(0xfb)]
void NewWindow2(
[In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp,
[In, Out] ref bool cancel);
}
}
}
I know the question is very old but I solved it this way: add new reference, in COM choose Microsoft Internet Controls and in the code, before the click that opens a new window add the following:
SHDocVw.WebBrowser_V1 axBrowser = (SHDocVw.WebBrowser_V1)webBrowser1.ActiveXInstance;
axBrowser.NewWindow += axBrowser_NewWindow;
and then add the following method:
void axBrowser_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
{
Processed = true;
webBrowser1.Navigate(URL);
}
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.
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);
}
}
In form I embedded WebBrowser component with lots of html contents (Mainly Table, buttons ) for rich ui. Is it possible to handle event on clicking html button ?
Sure, look at the kitchen sink demo for a sample.
Generally just navigate to a URL on the event and implement your own BrowserNavigationCallback to handle navigation to that specific URL.
This is the code from the Kitchen Sink demo notice the setBrowserNavigationCallback block:
final WebBrowser wb = new WebBrowser();
if(wb.getInternal() instanceof BrowserComponent) {
Button btn = new Button("Add");
final TextArea content = new TextArea();
Container north = new Container(new BorderLayout());
north.addComponent(BorderLayout.CENTER, content);
north.addComponent(BorderLayout.EAST, btn);
cnt.addComponent(BorderLayout.NORTH, north);
content.setHint("Add to web document");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
((BrowserComponent)wb.getInternal()).execute("fnc('" + content.getText() + "');");
}
});
((BrowserComponent)wb.getInternal()).setBrowserNavigationCallback(new BrowserNavigationCallback() {
public boolean shouldNavigate(String url) {
if(url.startsWith("http://sayhello")) {
// warning!!! This is not on the EDT and this method MUST return immediately!
Display.getInstance().callSerially(new Runnable() {
public void run() {
((BrowserComponent)wb.getInternal()).execute("fnc('this was written by Java code!')");
}
});
return false;
}
return true;
}
});
}
I am following this exactly:
http://msdn.microsoft.com/en-us/library/ms185301.aspx
but can't get it to work. The form appears when I try and add my new item, but when I input text and click the button, nothing happens.
For posterity's sake here is my code:
The non-empty methods in the Wizard class which extends IWizard
public void RunStarted(object automationObject,
Dictionary<string, string> replacementsDictionary,
WizardRunKind runKind, object[] customParams)
{
try
{
// Display a form to the user. The form collects
// input for the custom message.
inputForm = new UserInputForm();
inputForm.ShowDialog();
customMessage = inputForm.get_CustomMessage();
// Add custom parameters.
replacementsDictionary.Add("$custommessage$",
customMessage);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// This method is only called for item templates,
// not for project templates.
public bool ShouldAddProjectItem(string filePath)
{
return true;
}
The user input form code:
public partial class UserInputForm : Form
{
private string customMessage;
public UserInputForm()
{
InitializeComponent();
}
public string get_CustomMessage()
{
return customMessage;
}
private void button1_Click(object sender, EventArgs e)
{
customMessage = textBox1.Text;
this.Dispose();
}
}
And the button is indeed named button 1:
this.button1.Location = new System.Drawing.Point(200, 180);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(100, 40);
this.button1.TabIndex = 0;
this.button1.Text = "Click Me";
this.button1.UseVisualStyleBackColor = true;
So I don't have much experience with Windows Forms (do web apps), but I am following the directions on MSDN and it's pretty clear cut. Any suggestions? Can anyone else get this to work?
Okay I figured it out. I had to add the event handler in the form's constructor manually:
public UserInputForm()
{
InitializeComponent();
button1.Click += button1_Click;
}
Why this isn't in the documentation on MSDN boggles my mind.
If you use the WinForms designer mode to drag your button from the Toolbox, and then double-clicked the button in the designer view, it would have added the event handler and stubbed that Click method for you. Just FYI.