I have my form Welcome on this form i have two radio buttons-Verification and enrollment and a OK button .when user select one of radio buttons and press OK then a form will show but i am not able to do that. Please help.
this is my Statemachine class code:
package userclasses;
import generated.StateMachineBase;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.RadioButton;
import com.sun.lwuit.Form;
import com.sun.lwuit.util.Resources;
public class StateMachine extends StateMachineBase implements ActionListener {
Resources resources;
RadioButton Verification = new RadioButton("Verification");
RadioButton Enrollment = new RadioButton("Enrollment");
StateMachineBase cl = new StateMachineBase() { };
com.sun.lwuit.ButtonGroup bg=new ButtonGroup();
Form fo, f;
public StateMachine(String resFile) {
super(resFile);
// do not modify, write code in initVars and initialize class members there,
// the constructor might be invoked too late due to race conditions that might occur
}
/**
* this method should be used to initialize variables instead of
* the constructor/class scope to avoid race conditions
*/
StateMachine()
{
try {
resources = Resources.open("/NEW AADHAR.res");
}
catch(java.io.IOException err) {
err.printStackTrace();
}
cl.setHomeForm("Welcome");
fo = (Form)cl.startApp(resources,null,true);
f = cl.findWelcome(fo);
//fo.addCommandListener(this);
Verification = cl.findRadioButton1(f);
Enrollment = cl.findRadioButton(f);
f.addComponent(Verification);
f.addComponent(Enrollment);
//fo.addComponent(bg,null);
bg.add(Enrollment);
bg.add(Verification);
Verification.addActionListener(this);
Enrollment.addActionListener(this);
}
protected void initVars() { }
protected void onWelcome_OKAction(Component c, ActionEvent event) { }
public void actionPerformed(ActionEvent ae) {
throw new UnsupportedOperationException("Not supported yet.");
}
protected boolean onWelcomeEXIT() {
// If the resource file changes the names of components this call will break notifying you that you should fix the code
boolean val = super.onWelcomeEXIT();
return val;
}
protected void onWelcome_ButtonAction(Component c, ActionEvent event) {
// If the resource file changes the names of components this call will break notifying you that you should fix the code
super.onWelcome_RadioButton1Action(c, event);
super.onWelcome_RadioButtonAction(c, event);
if(Verification.hasFocus()) {
showForm("Login",null);
}
else if(Enrollment.hasFocus()) {
showForm("Authentication",null);
}
else {
Dialog.show("INFORMATION","Please select option","OK","CANCEL");
}
}
|
When you generate a netbeans project from the GUI builder the src folder will now contain the res file you need to work with. Whenever you modify the GUI code that StateMachineBase will be regenerated so you can just rename the components in the GUI builder (you can do this by clicking on the tree node and pressing F2 or by selecting the name attribute in the properties table).
The properties table allows you to assign an event for every component that supports it (e.g. radio button action events) which will generate the appropriate callback method in the StateMachine class (write your code only in the StateMachine class).
Radio buttons can be associated with one group by giving them the same group name.
The easiest way to do it is to use Resource Editor. Simply run it from LWUIT/util directory.
To create project using this tool follow each step from this video: http://www.youtube.com/watch?v=HOfb8qiySd8. Be sure to watch it to the end.
It will create 4 Netbeans projects (ProjectName, ProjectName_Desktop, ProjectName_MIDP, ProjectName_RIM). Fix depedencies (most important for ProjectName and _MIDP one) and you can start coding.
File StateMachineBase.java will be located in 'generated' package, which means that it will be regenerated every time you change something in Resource Editor.
Implement everything in StateMachine class ('userclasses' package), but don't create new methods there, use Resource Editor to create them for you: Resource Editor -> GUI Builder (tab on left side) -> Select component -> Events (tab on the right).
Now, if you want to do something for example, you want to change TextField value, you will write something like this:
protected boolean onUstawieniaKontoZapisz() {
// If the resource file changes the names of components this call will break notifying you that you should fix the code //this comment was generated
boolean val = super.onUstawieniaKontoZapisz(); //generated
Form current = Display.getInstance().getCurrent();
TextField login = findUstawieniaKontoLoginTextField(current); //TextField name in Editor is: 'UstawieniaKontoLoginTextField' - a bit long I know, but it's unique
TextField password = findUstawieniaKontoHasloTextField(current); //same here, 'UstawieniaKontoHasloTextField' is second's TextField name
Configuration.setEmail(login.getText()); //Configuration class is used to store preferences
Configuration.setPassword(password.getText());
return val; //generated
}
You can find all 'find*' methods inside StateMachineBase class. There is one for each Component you have added using Resource Editor (GUI Builder tab).
For grouping radio buttons into groups use Resource Editor too, select each radio button and on Properties tab find 'Group' property. Set it to the same word on every radio button you want to have in the same group.
Related
I'm currently making a reading app in Java, and this is my main menu.
What I want is that when I press the bottom button after selecting a book another window with the book opens. What I did now is a function that will open the other window while closing the one I'm currently in to free a little bit of memory.
I first close the current window after retrieving the necessary information from it (the index of the book) like this:
btnOuvrirLeLivre.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
int index = list.getSelectionIndex();
LiseuseController controller = new LiseuseController(null, null);
parent.dispose();
controller.viewBookController(index);
}
});
(I'm using the MVC method for my project), parent is just the composite used to open the frame.
public void viewBookController(int index) {
Display displayBook = new Display();
Shell shellBook = new Shell(displayBook);
shellBook.setLayout(new GridLayout(1, false));
index += 250;
LiseuseView lecture = new LiseuseView(shellBook, SWT.NONE, index);
shellBook.pack();
shellBook.open();
while(!shellBook.isDisposed()) {
if(!displayBook.readAndDispatch())
displayBook.sleep();
}
displayBook.dispose();
}
The index is just the book's number in my database, everything should be fine but I get this error when I do this after pressing the button to open the book:
Exception in thread "main" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:4875)
at org.eclipse.swt.SWT.error(SWT.java:4790)
at org.eclipse.swt.SWT.error(SWT.java:4761)
at org.eclipse.swt.widgets.Display.checkDisplay(Display.java:824)
at org.eclipse.swt.widgets.Display.create(Display.java:887)
at org.eclipse.swt.graphics.Device.<init>(Device.java:126)
at org.eclipse.swt.widgets.Display.<init>(Display.java:563)
at org.eclipse.swt.widgets.Display.<init>(Display.java:554)
at Controller.LiseuseController.viewBookController(LiseuseController.java:133)
at View.LiseuseHome$4.widgetSelected(LiseuseHome.java:81)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:252)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4209)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1037)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4026)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3626)
at Controller.LiseuseController.viewController(LiseuseController.java:126)
at Main.Main.main(Main.java:59)
(LiseuseController.java:133) contains "Display displayBook = new Display();"
And (LiseuseController.java:126) contains
if(!display.readAndDispatch())
display.sleep();
This is from the other function used to open the first window.
I don't really understand what is causing this error and I can't just put one in "visible" and the other one "invisible" like if I'm using Jframe because the 2 windows are on 2 different .java files.
Do you have any idea on how to fix this?
From the API documentation of org.eclipse.swt.widgets.Display
Applications which are built with SWT will almost always require only
a single display. In particular, some platforms which SWT supports
will not allow more than one active display. In other words, some
platforms do not support creating a new display if one already exists
that has not been sent the dispose() message.
You should therefore adapt your application to use only one instance of Display. Since the class LiceuseController already manages opening the initial window and the supplementary window(s), it seems fitting for it to manage an instance of Display for both uses.
This instance should be created at the application's start, maintained by the LiceuseController class and finally disposed when the application shuts down.
Another problem is that none of the methods in LiceuseController actually returns. As you can see from the stack trace, Display.readAndDispatch from LiseuseController.viewController is still active when you are creating the new window. I guess you also want to reopen the original window when the supplementary window is closed. Opening and closing windows in this manner will, however, endlessly increase your call stack until you end up with a StackOverflowException.
Instead, the LiceuseController should be able to create windows without outside interference. Therefore, instead of actively calling a method in the controller class to open another window, the listener should only tell the controller what window it should open next when the current window was closed.
An example could look like
public enum WindowType {
MAIN, BOOK, NONE
}
public class LiceuseController {
Display display;
WindowType nextToOpen = WindowType.MAIN;
public LiceuseController() {
display = new Display();
}
public void setNextToOpen(WindowType value) {
nextToOpen = value;
}
public void run() {
for (boolean run = true; run;) {
switch(nextToOpen) {
case MAIN:
viewController();
break;
case BOOK:
viewBookController();
break;
case NONE:
run = false;
break;
default:
throw new RuntimeException("unexpected enum constant");
}
}
/*
* Depending on how you want to manage the instance of this class,
* you could also extract this into a separate method.
*/
display.dispose();
}
private void viewController() {
// open main window using 'display'
}
private void viewBookController() {
// open book window using 'display'
}
}
so that a listener only needs to call LiceuseController.setNextToOpen and then close the current window. This will cause either viewController or viewBookController to return after which the loop will reenter and open the requested window. To shut down the application, call setNextToOpen with WindowType.NONE.
I am navigating between forms in the NEW GUI builder. The old one had a back button on every form by default.
How do I enable the back button on new gui builder in every form, every time i navigate in a new form? Tried through constants in theme.res. It is still not enabled by default.
Furthermore, is the method "new form1.show" the best way to navigate between forms ? (see code)
Assuming name files:
Main.java, myapplication.java, Form1 ,Form2 ,Form3
Code for navigation, assuming names button1 and Form3:
public void onbutton1ActionEvent(com.codename1.ui.events.ActionEvent ev) {
new Form3().show();
}
Back command from old gui builder, not working here:
public Form showForm(String resourceName, Command sourceCommand) {
try {
Form f = (Form)formNameToClassHashMap.get(resourceName).newInstance();
Form current = Display.getInstance().getCurrent();
if(current != null && isBackCommandEnabled() && allowBackTo(resourceName)) {
f.putClientProperty("previousForm", current);
setBackCommand(f, new Command(getBackCommandText(current.getTitle())) {
public void actionPerformed(ActionEvent evt) {
back(null);
}
});
}
if(sourceCommand != null && current != null && current.getBackCommand() == sourceCommand) {
f.showBack();
} else {
f.show();
}
return f;
} catch(Exception err) {
err.printStackTrace();
throw new RuntimeException("Form not found: " + resourceName);
}
}
I've tried:
form.setBackCommand(cmd);
public Command setBackCommand(String title, ActionListener<ActionEvent> listener)
public void setBackCommand(Command cmd)
public Command setBackCommand(String title, BackCommandPolicy policy, ActionListener<ActionEvent> listener)
public void setBackCommand(Command cmd, BackCommandPolicy policy)
boolean onBack() {
return true;
}
https://www.codenameone.com/blog/toolbar-back-easier-material-icons.html
on main.java and myapplication.java did not accept the commands.
Form3.getToolbar().setBackCommand("", e -> Form3.showBack());
althouth is should not work only for form3, but every form.
Did not work either. Putting "back command" on every sidemenu would not be the ideal solution, because we might be navigating to each form from different forms.
EXTRA:
Is there a way to enable global toolbar and global commands for all forms, so i do not copy paste the toolbar code for each new form? If not answered here, i might make a new thread.
Thanks.
The old GUI builder handled navigation as it was designed at a time when Nokia was the worlds leader in the mobile phone industry and a 4in device was considered large. Back then we assumed the UI was simpler for each form and the navigation was the hard part.
This changed. But the bigger problem for most developers was the concept of stateless navigation which triggered a lot of issues both in design and functionality.
The new GUI builder doesn't include any navigation code or any global code. Each form stands on its own.
Having said that you can implement your own state machine by just keeping form instances and showing the form you want to navigate to e.g.:
public static class Controller {
private static Form1 f1;
private static Form2 f2;
public static void showF1() {
if(f1 == null) f1 = new Form1();
f1.show();
}
// etc...
}
I used static context for simplicity but you can implement your own strategy. Notice that you can also insert global logic here e.g. add the toolbar as a function like:
private static void initForm(Form f) {
// add global commands to the toolbar
}
Alternatively you can derive all the forms from a common base class as the new GUI builder doesn't restrict your inheritance.
I'm currently working with an SWT TableViewer. And I have a given it a StyledCellLabelProvider implementation. I have given it a set of input and it displays it fine. There is use case where a use can select rows from the table to perform certain actions on and then an icon needs to be added to a specific cell on each row that the modification was done on.
The problem I'm running into here is that the image is not showing up unless I click physically inside the tableviewer after performing the modifcation. Please note that the tableviewer's selection remains the same after the modification has been performed as well. I know the update in the StyledCellLabelProvider is being called after I call refresh on the tableviewer.
My question is why is it not showing up without clicking?
MyStyledCellLabelProvider
public void update(ViewerCell cell) {
if (cell.getElement() instanceof Foo && ((Foo)cell.getElement()).hasBeenModified()) {
cell.setImage(myImage);
}
cell.setText("ABCD");
}
TableViewerComposite
#Override
public void notifyModificationMade(Object[] modifiedObjects){
//Update input on tableviewer
...
//Refresh after updating
tableViewer.refresh(); //Triggers the StyledCellLabelProvider to be called
}
Thanks again!
EDIT:
So one piece of information I forgot is that the cell that is being updated will sometimes have a org.eclipse.ui.forms.widgets.Hyperlink already existing inside of it instead of text and will continue to have it after the image has been added. I think this is what is causing the issue. When I removed the hyperlink code and went back to text, it worked as intended. Here is the code I'm using to add the HyperLink to the cell.
public void update(ViewerCell cell) {
if (cell.getElement() instanceof Foo && ((Foo)cell.getElement()).hasBeenModified()) {
cell.setImage(myImage);
final Hyperlink link = new Hyperlink((Composite) cell.getViewerRow().getControl(),
SWT.UNDERLINE_LINK);
link.setUnderlined(true);
link.setBackground(link.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
link.setForeground(link.getDisplay().getSystemColor(SWT.COLOR_BLUE));
link.setText("My url");
link.setHref(url);
link.addHyperlinkListener(new HyperlinkAdapter() {
...
});
TableItem item = (TableItem) cell.getItem();
TableEditor editor = new TableEditor(item.getParent());
editor.grabHorizontal = true;
editor.grabVertical = true;
editor.setEditor(link, item, cell.getColumnIndex());
editor.layout();
}
}
You need to call super.update(cell); after your code inside update
From the source code of StyledCellLabelProvider.java, the update method says
/*
* (non-Javadoc)
*
* #see org.eclipse.jface.viewers.OwnerDrawLabelProvider#update(org.eclipse.jface.viewers.ViewerCell)
*/
public void update(ViewerCell cell) {
// clients must override and configure the cell and call super
super.update(cell); // calls 'repaint' to trigger the paint listener
}
The super class OwnerDrawLabelProvider.java forces a redraw of cell.
For school, I'm attempting to recreate Microsoft's Notepad program using Java's Swing. I'm working on the saving and opening of .txt files, and I'm trying to figure out a way for the program to detect when a change has been made to the document. If a change has been detected and the user chooses to open or create a new file, I want the program to prompt the user if they would like to save their changes before continuing.
My thought for this was to create a flag, called documentChanged, that would initially be false, and which would be set to true whenever a change was made to the JTextArea. To detect this change, I thought of using a TextListener as follows:
public class JNotepad implements ActionListener
{
boolean documentChanged;
JTextArea notepad;
JNotepad()
{
documentChanged = false;
notepad = new JTextArea();
notepad.addTextListener(new TextListener() {
public void textValueChanged(TextEvent te) {
documentChanged = true;
}
});
}
}
However, I learned that Java classes are unable to implement multiple interfaces at once, and I'm already using ActionListeners to implement the items of my notepad's menu bar.
My question is, is there any way to use both TextListener and ActionListener (or any other listener) simultaneously in the same class? If not, what would be my best plan of action for detecting a change in the document?
It was answer in another post. See Text Changed event in JTextArea? How to?
And also see How to Write a Document Listener (DocumentListener) in Oracle, you will see an applet example.
How does your this even compile
notepad = new JTextArea();
notepad.addTextListener(new TextListener() {
// ....
}
since TextListeners are not defined to work with JTextAreas but rather with TextAreas, a completely different beast.
You should add a DocumentListener to your JTextArea's Document.
notepad.getDocument().addDocumentListener(new DocumentListener() {
void insertUpdate(DocumentEvent e) {
documentChanged = true;
}
void removeUpdate(DocumentEvent e) {
documentChanged = true;
}
void changedUpdate(DocumentEvent e) {
documentChanged = true;
}
});
Regarding
My question is, is there any way to use both TextListeners and ActionListeners (or any other listener) simultaneously in the same class?
Use of a DocumentListener has nothing to do with ActionListeners used elsewhere in your program since their domains are orthogonal to each other, i.e., the one has absolutely nothing to do with the other.
What is the best practice for subscribing to events from another JFrame? For example, I have a "settings" form, and when the user presses okay on the settings form, I want the main form to know about this so it can retrieve the settings.
Thanks.
Here is my ideal interface:
public void showSettingsButton_Click() {
frmSettings sForm = new sForm(this._currentSettings);
//sForm.btnOkay.Click = okayButtonClicked; // What to do here?
sForm.setVisible(true);
}
public void okayButtonClicked(frmSettings sForm) {
this._currentSettings = sForm.getSettings();
}
Someone publishes an Event, that something has changed, here the settings. A subscriber that registered for this specifig event, gets notified about it and can do his work, here get the settings. This is called publisher/subscriber.
For this you can use Eventbus or implementing something smaller on your own.
One approach is to have only a single JFrame. All the other 'free floating top level containers' could be modal dialogs. Access the the main GUI will be blocked until the current dialog is dismissed, and the code in the main frame can check the settings of the dialog after it is dismissed.
For anyone interested, here is what I ended up going with. I'm not sure if it's the best way, but it is working for my purposes.
// Method called when the "Show Settings" button is pressed from the main JFrame
private void showSettingsButton_Click() {
// Create new settings form and populate with my settings
frmSettings sForm = new frmSettings(this.mySettings);
// Get the "Save" button and register for its click event...
JButton btnSave = sForm.getSaveButton();
btnSave.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
SaveSettings(sForm);
}
});
// Show the settings form
sForm.setVisible(true);
}
// Method called whenever the save button is clicked on the settings form
private void SaveSettings(frmSettings sForm) {
// Get the new settings and assign them to the local member
Settings newSettings = sForm.getSettings();
this.mySettings = newSettings;
}
And if, like me, you are coming from a .NET perspective, here is the C# version:
private void showSettingsButton_Click(object sender, EventArgs e)
{
frmSettings sForm = new frmSettings(this.mySettings);
sForm.btnSave += new EventHandler(SaveSettings);
sForm.Show();
}
private void SaveSettings(object sender, EventArgs e)
{
frmSettings sForm = (frmSettings)sender; // This isn't the exact cast you need..
Settings newSettings = sForm.Settings;
this.mySettings = newSettings;
}