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
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);
I am implementing a car pooling app. The gui is made with netbeans.
I have my main class Voiture.java
public class Voiture {
public static void main(String[] args) {
View view = new View();
Controller controller = new Controller(view);
controller.run();
}
}
The controller class :
public class Controller {
private buttonHandler butHandler;
private QueriesRunner queriesRunner;
private User user;
private View view;
public Controller(View view) {
this.butHandler = new buttonHandler();
this.queriesRunner = new QueriesRunner();
this.user = new User();
this.view = view;
}
public void run() {
view.getLoginPage().show();
}
}
QueryRunner just runs sql queries by connecting to my model, a database.
The view main class :
public class View {
private LoginPage loginPage;
private RegisterPage registerPage;
private UserWelcomePage userWelcomePage;
public View() {
this.loginPage = new LoginPage();
this.registerPage = new RegisterPage();
this.userWelcomePage = new UserWelcomePage();
}
}
In the LoginPage there is a login button. The function that is run (via a button listener) when the button is clicked is :
private void loginButtonActionPerformed(java.awt.event.ActionEvent evt) {
boolean b = buttonHandler.notifyLogin(enteredEmail.getText(),
enteredPassword.getText());
if (b) {
jLabel1.setText("Login SUCCESS");
} else {
jLabel1.setText("Login Fail, Please Register");
}
}
buttonHandler just run queries by making the correct sql query and then passing it to the queryRunner class.
What seems difficult to do properly, is to destroy the LoginPage instance and show the welcomePage with the correct info (name of the user, city he was born in ...) when the login is successful. Right now it just puts the LOGIN SUCCESS on the screen.
What I tried to do is just put everything in the core of loginButtonActionPerformed by hiding the loginPage, showing the welcome page and passing the info through the ButtonHandler class. But that seems like the beginning of a really hideous code because I don't pass through the controller.
I start doubting if MVC is the best pattern to use for a login page...
I know this question has been covered in many posts here.
However, something is still not clear to me, so i wanted to ask you my problem in detail.
I have to develop a java application using Swing and using the MVC model.
The application is mainly divided into two parts:
login part
questionnaire part (after login, a questionnaire is displayed)
So following MVC model i divided my code into 3 packages containing the following classes:
Model
LoginModel
QuestionModel
View
LoginView
QuestionView
Controller
LoginController
QuestionController
After developing these classes, i didn't know how to set the window that the program was current working on (login, questionnaire or other future implementations).
So i thought about implementing 3 other classes that use the Observer pattern:
MainModel - Observable
MainView
MainController - Observer
But now i'm not sure how to change the current window.
For example when login is successful, the window must change from LOGIN to QUESTION, so "MainModel.window = Window.QUESTION" and send it to the View.
Should it be added in LoginModel.login() by extending LoginModel with MainModel?
Or how can I do this?
My code:
public class main {
public static void main(String[] args) {
MainView view = new MainView();
MainModel model = new MainModel();
MainController controller = new MainController(view, model);
}
}
public class MainView {
private JFrame window;
public MainView() {
window = new JFrame();
window.setLayout(new CardLayout(0, 0));
LoginView login = new LoginView(); // init window at opening
QuestionView question = new QuestionView();
window.add(login);
window.add(question);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public void update(Window window) {
// ??
}
}
public class MainModel {
private List<Observer> observers = new ArrayList<>();
private Window window;
public MainModel() {
window = Window.LOGIN; // init window at opening
}
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void setWindow(Window newWindow) {
newWindow = window;
for (Observer o : observers)
o.update(newWindow);
}
}
public class MainController implements Observer {
private MainView view;
private MainModel model;
public MainController(MainView view, MainModel model) {
this.view = view;
this.model = model;
this.model.addObserver(this);
}
#Override
public void update(Window window) {
this.view.update(window);
}
}
public class LoginView extends JPanel {
private JButton btnLogin;
// ... other attributes
public LoginView() {
btnLogin = new JButton("Login");
new LoginController(this);
}
public JButton getBtnLogin() {
return btnLogin;
}
public void ShowResult(boolean bResult) {
// print result with JOptionPane.showMessageDialog
}
}
public class LoginController {
private LoginView view;
public LoginController(LoginView view) {
this.view = view;
setActionListener();
}
public void setActionListener() {
ActionListener loginButton;
loginButton = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
LoginModel model = new LoginModel();
boolean bResult = model.login(view.getUserNameField(), view.getPasswordField());
view.ShowResult(bResult);
}
};
view.getBtnLogin().addActionListener(loginButton);
}
}
public class LoginModel {
// ... attributes etc
public boolean login(String username, String password) {
boolean bResult;
// ... Some operation etc (useless for this example)
bResult = true; // Simulation login successful
if (bResult)
// ? Change window model to Window.QUESTION.
// But how?
// LoginModel extends MainModel? To call "super.setWindow(Window.QUESTION)?
return bResult;
}
}
// My Observer class
public interface Observer {
public void update(Window window);
}
// My Window class
public enum Window {
LOGIN,
QUESTION,
}
// Questionnaire classes code is very similar to the Login code
public class QuestionView extends JPanel {
private JButton btn;
// ...
new QuestionController(this);
// ...
}
public class QuestionController {
private QuestionView view;
// ...
setActionListener();
// ...
}
So in conclusion is it correct to use this approach? Or how else could i view/update the current window better?
In Swing, the MVC pattern looks like this:
The view reads from the model
The view may not update the model
The controller updates the model and the view
The MVC name implies that you create the model first, then the view, then the controllers.
There's usually not one controller to "rule them all". Each listener is responsible for its own part of the model and the view.
You usually have one application model. An application model is made up of one or more plain Java getter/setter classes. In your case, it looks like a Person class and a Questionaire class. You would probably also have a Question class, to hold one question, several possible answers, and the chosen answer. You may have additional plain Java getter/setter classes I'm not thinking about now.
You would have one JFrame, one JPanel to hold a question and possible answers, and a JDialog for the login and password. You may need multiple JPanels for different types of answers (not different questions), so you might need a main JPanel with a CardLayout.
Your controllers will be the ActionListener for the login JButton, and the "I'm finished answering this question" JButton. You may have other listeners that I'm not thinking about now.
I'm working on developing an Vaadin application. When developing a Java desktop application I use AbstractAction to create the buttons of my GUI. How to do that using Vaadin
Here is how I do in Java Desktop application:
// In my view
JButton button = new JButton(new Action(BUTTON_NAME, presenter, "methodToInvoke", Object... arguments));
class Action extends AbstractAction {
public Action(ButtonName name, Presenter presenter, String method, Object... arguments) {
this.name = name;
this.presenter = presenter;
this.method = method;
this.arguments = arguments;
readButtonProperties();
}
public void actionPerformed(ActionEvent e) {
//Call method from presenter with arguments using reflection
}
}
Edit:
I already read this. It's not the way I'm asking for.
From your example it isn't really clear what your requirements are.
Sounds like you insist on using reflection, but I'm not sure why. You could just do this, which is basically the same thing the Button documentation already says.
Presenter presenter = getPresenter();
String with = "with";
int my = 42;
List<Data> = new List<>();
Button vaadinButton = new Button("I'm a button.", clickEvent -> presenter.doStuff(with, my, arguments));
If you need more than a simple method call, you could just as well create a more elaborate ClickListener implementation that has more than the buttonClick() method.
Button vaadinButton = new Button("Button Caption", new Action(...))
class Action extends AbstractAction implements Button.ClickListener {
public Action(ButtonName name, Presenter presenter, String method, Object... arguments) {
this.name = name;
this.presenter = presenter;
this.method = method;
this.arguments = arguments;
readButtonProperties();
}
public void actionPerformed(ActionEvent e) {
//Call method from presenter with arguments using reflection
}
#Override
public void buttonClick(ClickEvent event) {
actionPerformed(null);
}
}
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();
}
}