I'm working through the book Beginning BlackBerry 7 Development and really putting my little or non existent oop/java skills to the test- eclipse is throwing up an error from the code in the book stating that loginhandler hasn't been declared- and yes its correct- it hasn't been declared but it also hasn't been declared in the book.
What has been done is an inner class called logincommandhandler (at the bottom of my code) which can be seen in an excerpt here- http://my.safaribooksonline.com/book/-/9781430230151/chapter-4-user-interface-basics/67 - this is what its meant to be calling (i assume) but my limited oop skills i do not know what loginHandler should be- should it be defined somewhere with a type?
(there is no erata for the book)
package com.beginningblackberry.uifun;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.PasswordEditField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.CheckboxField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.util.StringProvider;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
public class UiFunMainScreen extends MainScreen implements FieldChangeListener {
BitmapField img;
EditField usernameField;
PasswordEditField passwordField;
ObjectChoiceField domainField;
CheckboxField rememberCheckBox;
ButtonField clearButton, loginButton;
public UiFunMainScreen(){
Bitmap logoBitmap = Bitmap.getBitmapResource("img/upd8rLOGO.png");
img = new BitmapField(logoBitmap, Field.FIELD_HCENTER);
add(img);
add(new SeparatorField());
add(new LabelField("Please Enter Your Credentials:"));
usernameField = new EditField("Username:","");
passwordField = new PasswordEditField("Password:","");
domainField = new ObjectChoiceField("Domain",new String[] {"Home","Work"});
rememberCheckBox = new CheckboxField("Remember password",false);
add(usernameField);add(passwordField);
add(domainField);
add(rememberCheckBox);
add(new SeparatorField());
clearButton = new ButtonField("Clear",ButtonField.CONSUME_CLICK);
loginButton = new ButtonField("Login",ButtonField.CONSUME_CLICK);
HorizontalFieldManager buttonManager = new HorizontalFieldManager(Field.FIELD_RIGHT);
buttonManager.add(clearButton);
buttonManager.add(loginButton);
add(buttonManager);
clearButton.setChangeListener(this);
//loginButton.setChangeListener(this);
loginButton.setCommand(new Command(LoginHandler));
}
//routing
public void fieldChanged(Field field, int context){
if(field == clearButton){
clearTextFields();
}else if(field == loginButton){
login();
}
}
private void login(){
if(usernameField.getTextLength()== 0 || passwordField.getTextLength() == 0){
Dialog.alert("You must enter a username and password");
}
else
{
String username = usernameField.getText();
String selectedDomain = (String) domainField.getChoice(domainField.getSelectedIndex());
LoginSuccessScreen loginSuccessScreen = new LoginSuccessScreen(username, selectedDomain);
UiApplication.getUiApplication().pushScreen(loginSuccessScreen);
}
}
public void clearTextFields ()
{
usernameField.setText("");
passwordField.setText("");
}
protected void makeMenu(Menu menu, int instance){
super.makeMenu(menu, instance);
/*
menu.add(new MenuItem(new StringProvider("Login"),20,10){
public void run(){
login();
}
});
*/
//login menu item
MenuItem loginMenu = new MenuItem(new StringProvider("Login"),20,10);
loginMenu.setCommand(new Command(LoginHandler));
menu.add(loginMenu);
//clear text menu item
menu.add(new MenuItem(new StringProvider("Clear"),20,10){
public void run(){
clearTextFields();
}
});
}
class LoginCommandHandler extends CommandHandler
{
public void execute(ReadOnlyCommandMetadata metadata, Object context){
login();
}
}
}
and the error-
LoginHandler cannot be resolved to a variable UiFunMainScreen.java /UiFun/src/com/beginningblackberry/uifun line 69 Java Problem
any blackberry/java wizards shed some light on where i am going wrong?
Update
No one really answered the question bang on- to call the new inner class i called this instead
MenuItem loginMenu = new MenuItem(new StringProvider("Login"),20,10);
loginMenu.setCommand(new Command(new LoginCommandHandler()));
menu.add(loginMenu);
update 2 second answer
Declaring loginHandler as a class variable also works -
LoginCommandHandler loginHandler = new LoginCommandHandler();
My guess would be that it should be an instance of LoginCommandHandler (the class declared at the end). It's a guess, but an educated one: Command's constructor expects a CommandHandler instance, and LoginCommandHandler extends CommandHandler, so...
The easy change is to change all the places that look like this:
loginButton.setCommand(new Command(LoginHandler));
to:
loginButton.setCommand(new Command(new LoginCommandHandler()));
E.g., we're calling the LoginCommandHandler constructor and passing the resulting object into new Command().
Or if for some reason (I haven't really read the code) you need a reference to the handler, declare and instantiate it:
LoginCommandHandler loginHandler = new LoginCommandHandler();
...and then use it
loginButton.setCommand(new Command(loginHandler));
(Note that there are multiple places where they've made this mistake in the that quoted code.)
Your code is missing this line
LoginCommandHandler loginHandler = new LoginCommandHandler();
Moreover you can get code for the book here.
The problem is in this line
loginButton.setCommand(new Command(LoginHandler));
You proabably need a instance of LoginHandler (new LoginHandler()) to pass to new Command method.
As the error indicates, the error is in line 69, which I assume is this:
loginButton.setCommand(new Command(LoginHandler));
Assuming LoginHandler is the name of a class or interface, this line is invalid.
It should be something like new Command(LoginHandler.class), new Command(new LoginHandler()) or maybe new Command("LoginHandler"), since the parameter requires you to pass an object (the type object for a class would be <classname>.class).
If it should be a variable, then it simply doesn't exist (btw. Java convention is that variable names start with a lower case letter) and you have to create it.
... it hasn't been declared but it also hasn't been declared in the book. ... (there is no erata for the book)
This doesn't mean the code in the book is 100% correct and compilable.
Related
I am just trying to extend a SimpleStringProperty in OpenJFX 11.0.1 to add some extra functionality. But ist seems not so easy, I experienced strange behavior of my extended Property and I don't know why. I think it should work.
My in this sample code simplified SimpleStringProperty extension contains another readonly string property which should be updated every time the the user types into a bound TextField. In this case remove all not allowed characters and convert the prefix. (I know this is not perfect but short enough to show)
After starting the sample code you will get a window with a rows of Controls. Typing in a String like "001 (242) 555666" the label should show the normalized phone number like "+1242555666".
The initial conversion works correcty.
I never get any exceptions.
The conversion is called when I type in new digits.
But if you play around with typing and deleting after a few seconds the set() method of my property isn't longer triggered by the bidirectional binding to the TextField.
To simplify the example I didn't use a TextFormatter. If I use one the problem doesn't change.
Can anyone help me figure out the problem?
Windows and OS X show the same behavior with OpenJFX 11 and OpenJFX 11.0.1
I tried the same code with JDK 1.8 and there it works fine.
package testproperty;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
public class TestProperty extends Application {
// attempt to create an own property
public class myPhoneNumberProperty extends SimpleStringProperty {
private final ReadOnlyStringWrapper normalizedNumber = new ReadOnlyStringWrapper("");
public ReadOnlyStringProperty normalizedNumberProperty() { return normalizedNumber.getReadOnlyProperty(); }
public String getNormalizedNumber() { return normalizedNumber.get(); }
public myPhoneNumberProperty() {
super();
}
public myPhoneNumberProperty(String s) {
super(s);
calculate();
}
#Override
public void set(String s) {
super.set(s);
calculate();
}
private void calculate() {
// some calculations (only for test purposes)
String original = this.get();
String result = original.replaceAll("[^0123456789]","");
if (result.startsWith("00")) result = result.replaceFirst("00", "+");
if (original.startsWith("+")) result = "+".concat(result);
normalizedNumber.set(result);
}
}
#Override
public void start(Stage primaryStage) {
// create my property
myPhoneNumberProperty phoneNumberA = new myPhoneNumberProperty("+34 952 111 222");
// set up grid pane
GridPane grid = new GridPane();
grid.setPadding(new Insets(5,5,5,5));
grid.setVgap(20);
grid.setHgap(20);
// set up the row
Label labelA = new Label("Enter phone number");
TextField textFieldA = new TextField();
textFieldA.textProperty().bindBidirectional(phoneNumberA);
Label labelB = new Label("Normalized number");
Label labelN = new Label();
labelN.textProperty().bind(phoneNumberA.normalizedNumberProperty());
grid.addRow(0, labelA, textFieldA, labelB, labelN);
// complete scene
Scene scene = new Scene(grid, 1000, 100);
primaryStage.setTitle("PhoneNumberProperty TestProg");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Your phoneNumberA property object is being garbage collected. To fix this you must keep a strong reference to the object. One option is to make it an instance field.
JavaFX implements bindings using weak listeners/references. Bidirectional bindings have no strong references to the other property. This is different from unidirectional bindings where a reference to the observable value must be kept in order to unbind from it later.
This question already has answers here:
How will Java lambda functions be compiled?
(2 answers)
Closed 5 years ago.
In the below working code,
package com.ca.naive;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.List;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TodoGUI {
public static void main(String[] args) {
List list = new List();
TextField itemField = new TextField();
Button addButton = new Button("Add");
Button removeButton = new Button("Remove");
addButton.addActionListener(e -> list.add(itemField.getText()));
removeButton.addActionListener( e -> list.remove(list.getSelectedIndex()));
Panel buttons = new Panel(new GridLayout(1,0,3,3));
buttons.add(addButton);
buttons.add(removeButton);
Panel bottomPanel = new Panel(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(buttons);
Panel centerPanel = new Panel(new BorderLayout());
centerPanel.add(BorderLayout.NORTH, itemField);
centerPanel.add(BorderLayout.SOUTH, buttons);
Frame frame = new Frame();
frame.setLayout( new BorderLayout() );
frame.add(BorderLayout.WEST, list);
frame.add(BorderLayout.CENTER, centerPanel);
frame.pack();
frame.addWindowListener( new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setVisible(true);
}
}
Does javac replace addButton.addActionListener(e -> list.add(itemField.getText())); syntax with
addButton.addActionListener(new java.awt.Event.ActionListener() {
public void actionPerformed(java.awt.Event.ActionEvent e) {
list.add(itemField.getText());
}
});
?
Does javac replace addButton.addActionListener(e -> list.add(itemField.getText())); syntax with
addButton.addActionListener(new java.awt.Event.ActionListener() {
public void actionPerformed(java.awt.Event.ActionEvent e) {
list.add(itemField.getText());
}
});
?
No, this is not what the compiler does. In your example, an ActionListener implementation will be generated and instantiated, but that does not happen at compile time; it happens at runtime. The compiler does two things. First, it moves the body of your lambda into a hidden method that looks something like this:
void lambda$1(java.util.List list, java.awt.TextField itemField) {
list.add(itemField.getText());
}
Second, at the point where your lambda is declared, it emits a call to a bootstrap method. The bootstrap method is a special factory method that knows how to generate an implementation of a functional interface. It needs to be given some basic information, most notably: the type of the functional interface (already known to be ActionListener); the types of any captured variables (in your case, list and itemField); and which method contains the logic for the implementation (the generated lambda$1 method).
When the bootstrap call gets hit at runtime, it will generate an ActionListener implementation. The next time you end up on this code path, you won't have to call the bootsrap method. Instead, the bootstrap call is replaced such that you end up with something equivalent to:
addButton.addActionListener(TodoGUI$Lambda$1.getInstance(list, itemField));
Where TodoGUI$Lambda$1 is a class that looks something like this:
static class TodoGUI$Lambda$1 implements java.awt.Event.ActionListener {
private final java.util.List list;
private final java.awt.TextField itemField;
TodoGUI$Lambda$1(java.util.List list, java.awt.TextField itemField) {
this.list = list;
this.itemField = itemField;
}
#Override
public void actionPerformed(java.awt.Event.ActionEvent e) {
TodoGUI.lambda$1(list, itemField);
}
static java.awt.Event.ActionListener getInstance(
java.util.List list,
java.awt.TextField itemField) {
return new TodoGUI$Lambda$1(list, itemField);
}
}
Now, with all that in mind, the compiler does not need you to import the ActionListener type. That type does not need to be in the lexical scope at all. The compiler will look and see that you are calling a method called addActionListener on an java.awt.Button instance. It will see that you are passing a single argument, which is a lambda expression. In this case, there are no overloads, so it knows that addActionListener expects you to pass an ActionListener. It sees that ActionListener is a single-method interface, meaning it can be bound to a lambda. It attempts to infer your argument types and return type such that they are compatible with what is expected for an ActionListener: a single ActionEvent argument, and a void return type. Your lambda is compatible, so the call is bound, and the steps above are performed.
Another "non-lambda" example of the effect you described is a call like
System.out.println("hello");
You don't need to import java.io.PrintStream in order to use the println method that comes with out being an instance of this class.
BTW: You can program a class without the use of any import statements. In that case you always have to use the full classname including all packages if you want to use it:
java.io.PrintStream outStream = System.out;
outStream.println("Hello");
An import just saves you the repeated specification of the package each time you use a class.
EDIT at end of post
Test Code and Output
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.text.NumberFormatter;
public class Test{
private JFormattedTextField input, input2;
private NumberFormatter formatter;
private PropertyChangeListener listener;
public Test(){
formatter = new NumberFormatter(NumberFormat.getNumberInstance());
input = new JFormattedTextField(formatter);
input2 = new JFormattedTextField(formatter);
listener = new PropertyChangeListener(){
#Override
public void propertyChange(PropertyChangeEvent evt) {
convert(evt);
}
};
input.setColumns(4);
input2.setColumns(4);
input.addPropertyChangeListener("value", listener);
input2.addPropertyChangeListener("value", listener);
input.setValue(0.0);
JPanel panel = new JPanel();
panel.add(input);
panel.add(input2);
JOptionPane.showMessageDialog(null, panel);
}
private void convert(PropertyChangeEvent evt){
if (evt.getSource()== input){
if (evt.getSource()!= null){
double temp;
temp = converter((Double)evt.getNewValue());
input2.setValue(temp);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run(){
new Test();
}
});
}
private double converter(double value){
value = value*2;
return value;
}
}
The stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Double
at test.Test.convert(Test.java:46)
My thoughts
Because I have a method that passes in a double (it's convert()) , and seemingly evt.getNewValue() returns the direct value, which at the time of input is technically a long, it's throwing that error.
But every attempt at parsing my evt.getNewValue() to a double hasn't worked. Perhaps a little knowledge of what I'm trying to do with this program would help.
What The Program is for
So I've got a JPanel (in a tabbedPane) that has two JFormattedTextField inputs. It's a conversion application. My conversion class method passes in a double and returns a double. I'd like the fields to be linked together, or in other words, as soon as one field's input is changed the other changes with it (as in it's the output of the conversion).
I was considering scrapping the PropertyChangListener and going for a DocumentListener instead, but opted to try the former first as the latter has 3 overrideable methods I have to take care of, one of which might cause some unexpected results (highlighting and deleting the field would trigger two events for example).
TL;DR:
Is there a better way of getting a dynamically updating, dual input field application? Input one number into one field and the other field's number automatically updates.
Still a novice at Java.
Edit1
I've found a temporary solution: Have a DecimalFormat as the format in the JFormattedTextField. But if it could work without having a decimal as well I'd love it.
Edit2
Question answered, didn't realize evt.getNewValue() was returning a Number instance.
All you know for sure is that the object returned by evt.getNewValue() is a Number object. What if you use that information to your advantage and try something along these lines:
temp = ((Number)evt.getNewValue()).doubleValue();
I have this gui pop up panel and it got things to filled up like packets number, distance etc. Once users fill in the information, he will click ok, the gui will close and my other gui class which has calculation method should receives all data that are filled in earlier gui. How do I store that data? I know I can store in temp file but I don't want to do that. I hope you can enlighten me.
import java.awt.*;
import java.applet.Applet;
class Example extends Applet implements ActionListener
{
TextField txt = new TextField(10);
Button goButton = new Button("Go");
String data = new String ();
public void init ()
{
add(txt);
add(goButton);
goButton.addActionListener(this);
}
public void actionPerformed (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals("Go"))
{
// preserve data
data = txt.getText();
repaint();
}
}
}
You should create an intermediate class that represents the data.
After the GUI has been filled in and the submit button clicked, parse the data and fill in the fields in your class.
For example:
public class MyData {
public String Name;
public String Address;
}
Then, fire a method in your calculation method that takes this class as a parameter:
public void Calculate(MyData data) {
...
}
For more advanced handling, look into "interfaces" in Java - that's the standard way this is done.
I'm using netbeans to program something with a user interface...
I hava a main class that named "NewJFrame.java"(A) and one more class
that named "NewClass.java"(B). Class A is extended to class B like this:
public class NewClass extends NewJFrame{
...
}
Contents of ClassA are public static like this:
public static javax.swing.JTextField TextBox1;
I also has a button in classA .So when I click the button, it will call a function
from the classB and that function needs to edit TextBox1's text...
Here is whats going on when I click the button:
private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String Str1;
NewClass nc = new NewClass();
Str1=nc.call();
}
Here is the funcion in ClassB:
public String call()
{
String Str;
Str = TextBox1.getText();
TextBox1.setText(Str + "1"); //This part isn't work.
JOptionPane.showConfirmDialog(null,Str,"22222222",JOptionPane.PLAIN_MESSAGE);
return Str;
}
So I can read the text of TextBox1 and show it in a messagebox but cannot edit his text.
If I put this code in main class it works perfectly but in another class it doesn't work.
Can someone help me to reslove this problem?
(I'm using netbeans 6.9.1)
I Just Trying to use some another class to add my code because I dont want all the codes stay in same file this is not usefull... Come on someone needs to know how to do that you can't be writing all the codes in a *.java file right?
The problem you are facing has nothing to do with NetBeans IDE,
you will face the same problem with any IDE for this code.
One way of achieving this is by aggregating the NewJFrame class in the NewClass
instead of extending it:
Let me exlplain with some code:
public class NewClass {
private NewJFrame frame = null;
public NewClass(NewJFrame frame) {
this.frame = frame;
}
public String call()
{
String text;
text = frame.TextBox1.getText();
frame.TextBox1.setText(text + "1"); //This will work now.
JOptionPane.showConfirmDialog(null,text,"22222222",JOptionPane.PLAIN_MESSAGE);
return text;
}
}
Here we will receive a reference to the calling JFrame class and will use fields
defined in that class.
private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String Str1;
NewClass nc = new NewClass(this); // see the parameter we are passing here
Str1=nc.call();
}
When we create an object of class NewClass we will pass the reference of the
currently calling NewJFrame object
This will work check it.
Now coming to why your code is not working. When NewClass is extending NewJFrame
and when you create a new object of NewClass class it contains a separate
copy of the NewJFrame which is different from the calling NewJFrame reference hence
the field is getting set in another JFrame and not what you wanted.
with regards
Tushar Joshi, Nagpur
AFAIK Netbeans prevents you from editing by hand GUI's and behaves diferrently depending on strange issues like the one you have... but it was months ago, I dont know if current version sucks that much yet.
I really don't understand why you are forcing yourself to use a new class for this? Even if you NEED to, I don't understand why NewClass extends NewJFrame since you are only creating an instance to call a method that has nothing to do with GUI.
I think creating NewClass isn't necessary. Writing all the code in one class isn't bad by itself. This really depends on MANY factors: how much is "all the code"? Does it make sense to separate responsibilities? Etc, etc...
So make the JTextField and JButton NOT static and NOT public, and simply do everything in there:
private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String str = TextBox1.getText();
TextBox1.setText(str + "1"); //This part isn't work.
JOptionPane.showConfirmDialog(null,Str,"22222222",JOptionPane.PLAIN_MESSAGE);
}
P.S.: variable names are start in lowercase: String str, not String Str.
I Found a solution. I'm throwing the contents whereever I'll use. Here is an Example:
Main class:
private void formWindowOpened(WindowEvent evt) {
Tab1Codes tc1 = new Tab1Codes();
if(!tc1.LockAll(TabMenu1))
System.exit(1);
tc1.dispose();
}
Another class where I added some of my codes:
public boolean LockAll(javax.swing.JTabbedPane TabMenu){
try
{
TabMenu.setEnabledAt(1, false);
TabMenu.setEnabledAt(2, false);
TabMenu.setEnabledAt(3, false);
TabMenu.setEnabledAt(4, false);
}catch(Exception e)
{
JOptionPane.showConfirmDialog(null, "I can't Lock the tabs!",
"Locking tabs...",
JOptionPane.PLAIN_MESSAGE,
JOptionPane.ERROR_MESSAGE);
return false;
}
return true;
}
So, I can edit the contents in another class but it's little useless to send every content I want to read and edit.
If someone knows any short way please write here.