I'm new to Java and oriented-object and I'm trying to create a chat program. Here's what I'm trying to do:
Somewhere in my Main.java
Window window = new Window;
Somewhere in my Window.java
History history = new History()
Somewhere in my History.java:
public History()
{
super(new GridBagLayout());
historyArea = new JTextArea(15, 40);
historyArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(historyArea);
/* some other code... */
}
public void actionPerformed(ActionEvent event)
{
String text = entryArea.getText();
historyArea.append(text + newline);
entryArea.selectAll();
historyArea.setCaretPosition(historyArea.getDocument().getLength());
}
public JTextArea getHistoryArea()
{
return historyArea;
}
public void addToHistoryArea(String pStringToAdd)
{
historyArea.append(pStringToAdd + newline);
historyArea.setCaretPosition(historyArea.getDocument().getLength());
}
Now that I'm in Server.java, I want to use the method addToHistoryArea. How can I do that without making my historyArea static? Because if I understand well how static works, I couldn't have different historyArea even if I create a new History...
Thanks for your help and tell me if I got it all wrong!
In your Server constructor, send the instance of your History object (e.g new Server (history), and then you can invoke, history.addToHistoryArea, other option would be have a setter method which sets an instance of history to an instance variable, and then just call the addToHistoryArea method
public class Server{
private History history;
public Server(History history){
this.history = history;
}
public void someMethod(){
this.history.addToHistoryArea();
}
}
Another way
public class Server{
private History history;
public void setHistory(History history){
this.history = history;
}
public void someMethod(){
this.history.addToHistoryArea();
}
}
In someplace in Server you can have History
public class Server{
private History history;
public void setHistory(History history){
this.history= history;
}
public void someMethod(){
history.addToHistoryArea();
}
}
Or if you don't want to have an instance in Server
public void someMethod(History history){
history.addToHistoryArea();
}
Or if you want to be more decoupled you can take approach with the observer pattern or perhaps a mediator if they are colleagues.
You may want to create a History object in the Server class and then call the addToHistoryArea() method on that history instance.
public class Server{
private History history;
public void setHistory(History history){
this.history = history;
}
public void methodCall(){
history.addToHistoryArea();
}
}
Related
I am often struggling with the same problem of custom Objects that creates a e.g. gui Component. And I never know what is the best way to get from the gui Component back to the object.
So multiple hacks and tricks are welcome.
Let me explain it to you:
This is my custom Object I need to find afterwards
public class MyObject {
int yearOfBirth;
String name;
public MyObject(int yearOfBirth, String name) {
this.yearOfBirth = yearOfBirth;
this.name = name;
}
public int getYearOfBirth() {
return yearOfBirth;
}
public Component getPanel() {
Component panel1 = makeTextPanel("This is the personal tab of "+name);
return panell;
}
}
This is where I need to find it through the Tab I am focusing
public class MyTabControl implements ChangeListener {
JTabbedPane myTabPane = new JTabbedPane();
public MyTabControl(){
//This will add a Listener for clicking on one Tab
myTabPane.addChangeListener(this);
}
public void oneMoreTab(MyObject myObject) {
myTabPane.addTab(myObject.name, myObject.getPanel())
}
public void stateChanged(ChangeEvent arg0) {
System.out.println("Focus of Tab changed");
int actualFocusedTabIndex = myTabPane.getSelectedIndex();
Component acutalFocusedComponent = myTabPane.getComponentAt(actualFocusedTabIndex);
//This works fine, I can get the Tab. Or at least the Component.
//But how do I get the yearOfBirth or better the Object itself?
int yearOfBirthOfTheSelectedTab = ???
}
}
This is just the main function
public static void main(String[] args) {
//Commands to start and create the GUI
MyTabControl myTabControl = new MyTabControl();
MyObject mother = new MyObject(1960, "Helen");
myTabControl.oneMoreTab(mother);
MyObject father = new MyObject(1955, "James");
myTabControl.oneMoreTab(father);
}
EDIT:
1 not working solution: Extend Component class
I have tried to extend the class Component. But this will create a failure (see comment in code):
public class ComponentWithExtras extends Component {
MyObject myObject;
public void addMyObject(MyObject myObject) {
this.myObject = myObject;
}
}
// The following line will create failure: Can't cast Component to ComponentWithExtras
ComponentWithExtras componentWithExtras = (ComponentWithExtras) myObject.getPanel();
componentWithExtras.addMyObject(myObject);
myTabPane.addTab(myObject.name, componentWithExtras);
Please note: I am new in this subject.
Suppose I have a class Event.
public class Event {
//constructors, etc.
public void pathFollowed(int location) {
//this method could be called at any time
}
}
And a class called EventManager.
public class EventManager {
private int managerLocation;
private ArrayList<Event> events;
public EventManager() {
events = new ArrayList<Event>();
}
public void addEvent(Event e) {
//THIS IS THE AREA OF INTEREST
events.add(e);
}
}
In the "area of interest" comment, is there any way of setting the value of managerLocation whenever the Event e calls upon pathFollowed(int location). My goal is that when any of the Events in the events arraylist calls pathFollowed(int location) that managerLocation would be set to "location" ("location" referring to the input in the pathfollowed method).
I was originally thinking of over-riding the pathFollowed method, but then I realized this can't be done because by the time the event gets to the addEvent method, it is already instantiated and can't be changed in this manner.
Thanks in advance.
Maybe some kind of listener pattern?
public class Event {
private List<PathListener> pls; //Or just one if you know you'll only need one
//constructors, etc.
public void pathFollowed(int location) {
//this method could be called at any time
for(PathListener pl : pls)
pl.notifyLocation(location);
}
public addPathListener(PathListener pl) {
pls.add(pl);
}
}
EventManager:
public class EventManager implements PathListener {
private int managerLocation;
private ArrayList<Event> events;
public EventManager() {
events = new ArrayList<Event>();
}
public void addEvent(Event e) {
e.addPathListener(this);
events.add(e);
}
#Override
public notifyLocation(int location) { //Of the PathListener interface
managerLocation = location;
}
}
This is just a kind-of-generic example, because I don't know what your purpose is, but maybe it will get you thinking.
I've looked around but nothing seems to help me out. Basically I'm writing a multithreaded chat program with a gui. The user inputs his name in a textfield in a Login class and hits the login button which directs him to a ClientGUI class. In the client GUI class theres a JLabel at the top that says
"Welcome to the ChatSystem (Username)"
. So what the user input in the textfield in the login class should appear in the JLabel after "Welcome to the ChatSystem" but I can't figure out why it doesn't work. Here's my code:
Login Class:
loginB = new JButton("Login");
main.add(loginB);
loginB.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
ClientGUI clientgui = new ClientGUI();
clientgui.setVisible(true);
}
}
ClientGUI class:
public ClientGUI(){
Login login = new Login();
String username = login.usernameTF.getText();
welcome = new JLabel("Welcome to ChatSystem "+username, SwingConstants.CENTER);
}
I understand that username should really by a JLabel and not a String but I have tried many ways to do this and I can't seem to get my head around this.
That is not going to work like that because
login.usernameTF.getText(); is actually a new created object in the ClientGUI constructor...
what I would suggest to do is to overload the constructor and to pass the name as parameter...
Example:
loginB.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
ClientGUI clientgui = new ClientGUI(getTheNameAndpassItHere);
clientgui.setVisible(true);
}
}
and then ClientGUI class:
public ClientGUI(String username){
//Login login = new Login();
// String username = login.usernameTF.getText();
welcome = new JLabel("Welcome to ChatSystem "+username, SwingConstants.CENTER);
}
Basically, you should use a Observer Pattern, which allows ClientGUI to generate events to interested parties when something changes.
This decouples your code and prevents the ClientGUI from doing things it shouldn't (like removing the label or it's parent component for example)
You could use some of the inbuilt listeners if they meet your needs, but for something like this, I'd prefer to use my own
public class LoginEvent extends EventObject {
private Throwable cause;
private String userName;
public LoginEvent(Object source) {
super(source);
}
public Throwable getCause() {
return cause;
}
public String getUserName() {
return userName;
}
}
public interface LoginListener extends EventListener {
public void loginFailed(LoginEvent evt);
public void loginSuccessful(LoginEvent evt);
}
Then you could add an instance of the listener to the ClientGUI...
loginB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ClientGUI clientgui = new ClientGUI(getTheNameAndpassItHere);
clientgui.addLoginListener(new LoginListener() {
#Override
public void loginFailed(LoginEvent evt) {
Throwable cause = evt.getCause();
// Show error message
}
#Override
public void loginSuccessful(LoginEvent evt) {
String name = evt.getUserName();
// Update UI
}
});
clientgui.setVisible(true);
}
}
or something simular
the swings component are by default private you need to make them public by just little steps
1.go to the properties of the component and then to the code tab
2.you will find variable modifier as private make them public and as well as static if you want.
you will now be able to use the components with the same code
I have used listeners with Android and never had any problems, however today when it tried to create a simple listener in Java I am getting NullPointerException, what is the cause of this and how can I fix it?
this includes 3 classes, ListenerMainStart.java, SendMessageClass.java, and ReceiveMessageClass.java
ListenerMainStart.java
public class ListenerMainStart {
public static void main(String[] args) {
new SendMessageClass();
}
}
SendMessageClass.java
public class SendMessageClass {
public OnStringRequestedListener onStringListener;
public Timer timer;
public SendMessageClass() {
timer = new Timer();
timer.schedule(new TimerAction(), 3000);
}
public void SetOnStringRequestedListener(OnStringRequestedListener listener) {
System.out.println("value of onStringListener " + onStringListener.toString());
onStringListener = listener;
}
public interface OnStringRequestedListener {
public void passString(String sendString);
}
public class TimerAction extends TimerTask {
#Override
public void run() {
if (onStringListener!=null){
// pass string to other class, ONSTRINGLISTENER IS ALWASY NULL
onStringListener.passString("string sent from SendMessageclass");
} else {
System.out.println("onStringListener is null");
}
}
}
}
ReceiveMessageClass.java
public class ReceiveMessageClass implements SendMessageClass.OnStringRequestedListener {
SendMessageClass senderClass;
public ReceiveMessageClass() {
// instantiate class
senderClass = new SendMessageClass();
// set the listener to the class
senderClass.SetOnStringRequestedListener(this);
}
#Override
public void passString(String sendString) {
// do action when string is sent from other class
System.out.println("message recevied from other class is " + sendString);
}
}
It looks like you need to call "SetOnStringRequestedListener" before you turn on your timers. As it is, that method never gets called and onStringListener never gets set. You do call that line of code in the receiver, but of course its far too late there. Your main should instantantiate both the receiver and the sender, SetOnStringRequestedListener, and then set off the timers.
SendMessageClass send = new SendMessageClass();
ReceiveMessageClass recv = new ReceiveMessageClass()
send.SetOnStringRequestedListener(recv)
EDIT: Then take out any code in the receiver that references the sender. The idea behind using the listener is that the two classes don't know directly about each other.
the title might be not very descriptive but i couldn't think of a better one.
The problem is as follows:
I have one screen (ScreenOne) with a link to another screen (ScreenTwo).
On the ScreenTwo is a link back to ScreenOne.
I implemented this via custom RichTextFields and a custom ChangeListener.
Now the problem is that i keep getting a StackOverflowError!
Is there any way to navigate back and forth in that way?
regards matt
public class MyApp extends UiApplication
{
public static void main(String[] args)
{
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp()
{
ScreenOne so = ScreenProvider.getInstance().getScreenOne();
so.initialize();
ScreenProvider.getInstance().getScreenTwo().initialize();
pushScreen(so);
}
}
public class ScreenOne extends MainScreen {
MyTextField link;
public ScreenOne() {
link = new MyTextField("FirstScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenTwo()));
}
}
public class ScreenTwo extends MainScreen {
MyTextField link;
public ScreenTwo() {
link = new MyTextField("SecondScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenOne()));
}
}
public class MyFieldChangeListener implements FieldChangeListener {
private Screen nextScreen;
public MyFieldChangeListener(Screen nextScreen) {
this.nextScreen = nextScreen;
}
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().pushScreen(nextScreen);
}
}
public class MyTextField extends RichTextField {
public MyTextField() {
super();
}
public MyTextField(String text) {
super(text);
}
protected boolean touchEvent(TouchEvent message) {
if (TouchEvent.CLICK == message.getEvent()) {
FieldChangeListener listener = getChangeListener();
if (null != listener)
listener.fieldChanged(this, 1);
}
return super.touchEvent(message);
}
}
public class ScreenProvider {
private static ScreenProvider instance = null;
private ScreenProvider(){}
public static ScreenProvider getInstance() {
if (instance == null) {
instance = new ScreenProvider();
}
return instance;
}
private ScreenOne screenOne = new ScreenOne();
private ScreenTwo screenTwo = new ScreenTwo();
public ScreenOne getScreenOne() {
return screenOne;
}
public ScreenTwo getScreenTwo() {
return screenTwo;
}
}
The constructor of ScreenOne creates a ScreenTwo instance, and the constructor of ScreenTwo creates a ScreenOne instance. You have an infinite loop here.
Regarding revision 5 of this question:
new ScreenProvider() -> new ScreenOne() -> ScreenProvider.getInstance() -> new ScreenProvider() -> ...
still infinite. Again, the problem is that you're trying to setup a cycle via object constructors. You need to create the objects first, then assign the next and previous.
Regarding revision 4 of this question:
getScreenOne() -> new ScreenOne() -> getScreenTwo() -> new ScreenTwo() -> getScreenOne() -> newScreenOne() -> ...
you still have an infinite loop, because the constructors are trying to store an instance of each other. You need to construct the objects first, then add the cyclic references.
In your ScreenProvider you don't need to make screen1/screen2 static -- they're members of the singleton instance.
Outside of that the other problem I see in this current version is that you're going to be pushing a screen onto the stack -- that's already on the stack. Try popping the prior screen first.
That overflow error is likely the result of an infinite loop caused by constantly jumping from ScreenOne and ScreenTwo. Could you describe what you actually would want to accomplish and/or show a snippet of code?