How to interact with swing components in different classes - java

I'm just trying to figure some things out in my head about getting information to and from swing components from other classes.
I have a main class that uses a few classes to build a swing gui. How do I go about writing information to these components from another class. As far as I understand I need to use an arraylist to store references to these components but I'm not exactly sure how to do this, can someone please help me out?

I would suggest that you try to separate the model from the view. Don't store data relevant for the application logic in the actual GUI components.
Storing references to the components in an array list, and then access the data via the array list and various getText methods just seems like a bad idea to me.
Store the values in an object representing some model, and let the GUI reflect the state of the model.

This is one way of accessing another class's methods:
public class MyFrame extends JFrame implements ActionListener
{
private final MyBusinessClass bc = new MyBusnessClass();
#Override public void actionPerformed(ActionEvent e) {
this.bc.someBusinessMethod();
}
}

Related

Is it good design pattern to pass model objects to view objects in java swing MVC?

I have class Model:
class Model {
Object[][] objects=new Object[3][];
}
I have a controller which is action listener:
class MyListener implements ActionListener {
public void actionPerformed(ActionEvent a){
//here I have to get objects array from Model and pass it to view to display
}
}
But I worry if I pass objects array to JPanel it will cause problems later.
Is there another way for JPanel to use objects?
Haven't touched Swing for a very long time, but still: JPanel doesn't really need any kind of model objects, it's just a widget that can aggregate other widgets. Usually, it makes sense to pass the model to widgets that can actually show something, for instance, textArea, textField, tables and so on.
In an MVC model implementation of swing, Components act as both as a view (obviously) and controllers by means of listeners reacting to some events.
In any case, the following rules apply:
Controllers change the model
Views are "subscribed" to the model changes. Usually, its implemented in internal models of components in swing itself, but you can extend them and define your behavior. Once model gets changed by controller, it fires special events to views, like "hey, I'm changed".
Model is usually loosely coupled to views.
Views react to these events and apply the changes (usually repainting with new data).
From your question its kind of hard to tell what will happen when someone changes the model (not enough information).

Using two GUI from one source

I'm working on an existing project and am wanted to simplify and make usable it. I have two GUI that I want they to feed from just one resource else their some GUI codes. I mean there are gui1.java and gui2.java consist of their GUI codes. And, one for their common parts. Let's call it as common.java. With gui selection part I can satisfy which gui selected (gui1 or gui2). I think to extend common.java by JFrame then extend gui1.java and gui2.java with common.java. Moreover, If there is external part of one of that GUIs, I can add external part using if condition (as I said I can determine which gui selected.) For example:
protected void MovementStateControl() {
try {
URL url = new URL(NameofMyproject.GetWepIp() + "<MESSAGE><Command_No>4</Command_No></MESSAGE>");
URLConnection connection = url.openConnection();
Document doc = parseXML(connection.getInputStream());
NodeList Settings = doc.getElementsByTagName("SYSTEM_SETTINGS");
Node MovementSystem = Settings.item(0);
Element MovementElem = (Element) MovementSystem;
jLabel7.setText(MovementElem.getElementsByTagName("device_name").item(0).getTextContent());
SystemGuiSelect.DeviceName = MovementElem.getElementsByTagName("device_name").item(0).getTextContent();
NameofMyproject.signal_max_level = Integer.parseInt(MovementElem.getElementsByTagName("signal_max_val").item(0).getTextContent());
/* If gui1 is selected, the part should be done as well. Otherwise, just above part okay. */
if (gui1) {
NameofMyproject.signal_min_level = Integer.parseInt(MovementElem.getElementsByTagName("signal_min_val").item(0).getTextContent());
if (!"EXISTS".equals(MovementElem.getElementsByTagName("polarization_system").item(0).getTextContent())) {
jLabel24.setVisible(false);
LblPolAngle.setVisible(false);
lblPolTarget.setVisible(false);
jLabel13.setVisible(false);
jTextField3.setVisible(false);
jButton16.setVisible(false);
jButton8.setText("Tx-Xy");
jButton3.setVisible(false);
jButton4.setVisible(false);
jProgressBar3.setVisible(false);
jLabel36.setVisible(false);
jLabel37.setVisible(false);
jLabel5.setVisible(false);
jButton18.setVisible(false);
} else {
jLabel24.setVisible(true);
LblPolAngle.setVisible(true);
lblPolTarget.setVisible(true);
jLabel13.setVisible(true);
jTextField3.setVisible(true);
jButton16.setVisible(true);
jButton8.setText("Tx-Xy-Zu");
jButton3.setVisible(true);
jButton4.setVisible(true);
jProgressBar3.setVisible(true);
jLabel36.setVisible(true);
jLabel37.setVisible(true);
jLabel5.setVisible(true);
jButton18.setVisible(true);
}
}
} catch (Exception e) { }
}
The problem is here I want the common GUI parts to put into common.java to remove code duplication because of having two GUI same codes too much. Of course because common.java is super class it cannot be aware of elements of its sub class. (JLabels, JButtons, etc. can't be recognized) Even if their thread parts are same, I can't feed them from same source. The GUIs have been created using NetBeans. By the way, my solution for the problem is adding parameter all methods but what about for the method how many arguments are there? (Maybe I use vargs) however, I wonder whether there are more efficient solution.
As far as I understand you have 2 basic problems you need to deal with. First is the separation of UI view from control logic, the Second is to increase the reuse within your Swing code.
My solution would be introducing an In Process Event Bus for communication between View and Control and Extract Components with common layout pattern from your current UI classes to increase the reuse within you Swing code.
Separating View from Control using an Event Bus
You need this because your view shall differ, but your control logic shall stay the same. You need to find a way to tell your UI that the device_name has changed. I would suggest to use a Event Bus implementation therefore. There are some realizations that already solve the EventDispatchThread handling for you.
Separated by an Event Bus your gui2.java will only react to the events concerning the visual elements it contains and gui1.java which has all currently known fields will react to all events. Your controller just publishes the events without knowing if it is consumed by someone or just dropped.
Ectract Components to increase reuse within Swing code
I would suggest to identify common parts of the UI, like Groups of labels, textfields and so on, that functionally belong to each other (e.g. Surname and Forename of a person). Extract them to a separate class extending JPanel and reuse them wherever you need it.
Do not register these fragments directly to the EventBus or at least inject the event names they should react to. Otherwise you may not use two instances of the same component within one JFrame because they would automaticallyshow the same values.
I hope this provides some ideas where to start your refactoring and which direction to go.
As you mentioned it, the super class should not know about its subclasses.
Instead of using inheritance, use composition.
You common.java should be composed of its specialized containers. This will decoupled common.java from gui1.java and gui2.java, in the future if you require to add a new gui3.java you won't break any APIs and its easy to just create a new SpecializedGUI.java
By basing on your example of method, i propose you to use a simple solution to solve your problem.
First, as Gilbert has suggested, the common widgets (textfield, label, etc...) must be in the abstract common class and if possible layed in the common class (it is more simple). Of course, the specific widgets to a concrete gui will be in the concrete class.
To ease the use of common widgets which are manipulated by the concrete classes, declare your fields as protected in your abstract common class.
Second, in your snippet, you do
if (gui1) { then...
Instead of conditional statements which are not needed (it's not the role of the parent class to know the children guy) and cumbersome (not maintenable in the time) , I propose you to create listeners. These will be simple interfaces that your concrete classes must implement.
It does simply dispatching to the concrete classes the responsibility to act or to no act when a event is dispatched by the parent class.
In order to force your concrete classes to implement the interface, make your abstract class Common to implement this interface.
In this way, the concrete class will not have the choice to implement it.
Here a very simple example with two guis and illustrating the presented concepts :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public abstract class CommonFrame extends JFrame implements MyFrameListener {
protected JLabel myLabelForControlMove;
private JButton btnControlMove;
private JPanel panel;
public CommonFrame() {
panel = new JPanel();
add(panel);
myLabelForControlMove = new JLabel("waiting for information...");
panel.add(myLabelForControlMove);
btnControlMove = new JButton("click to control move");
panel.add(btnControlMove);
setVisible(true);
pack();
// call concrete class with no aware which one is used
onMovementStateCreation();
btnControlMove.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// call concrete class with no aware which one is used
onMovementStateControl();
}
});
}
}
public interface MyFrameListener {
void onMovementStateCreation();
void onMovementStateControl();
}
public class Gui1 extends CommonFrame {
#Override
public void onMovementStateCreation() {
myLabelForControlMove.setText("control starts");
}
#Override
public void onMovementStateControl() {
myLabelForControlMove.setText("control with state Gui1");
}
}
public class Gui2 extends CommonFrame {
#Override
public void onMovementStateCreation() {
myLabelForControlMove.setText("control with state Gui2");
}
#Override
public void onMovementStateControl() {
// does nothing
}
}

Instead of getting two similar JFrames, I get one whith double component

I created a JFrame with buttons, labels and texts and I want to show it two times when I execute the main program, so I did like that:
import java.net.SocketException;
public class Main {
public static void main(String[] args) throws SocketException {
new MyFrame("client1");
new MyFrame("client2");
}
}
The result: I get two frames: one with the component of the other one inside, and one empty.
How to resolve this issue?
You are using static instance fields with your MyFrame for your components
A component can only reside within a single container, the moment you create your second frame, the static components are removed from the first container before been added to the second.
The solution, don't do this, ever...
I assume you are using static because you want to access these fields from another class, in that case, you should appropriate getters in the MyFrame class and pass a reference of it to those classes that need it.
Alternatively, you could establish a series of observers who monitor for changes and take appropriate action, this helps to decouple the code.
Personally, if you need to modify the MyFrame instances in some way, I'd provide setter methods that update your components instead, as I don't like exposing UI elements without good reason, to much opportunity for others to mess with them in appropriately

Swing - Organization of JFrames (or JDialogs???) in my program

I have a main controller class that shows a JFrame containing a JTable and, for each row in this table, I have to show a specific "form" on doubleclick.
This secondary window will need information about the specific row selected on the main JTable, as well as some objects saved as fields in the controller class.
An conceptual example of what I need to do is the following:
I have a set of Shops (listed in the JTable in the main JFrame) and, on double click on a row, another window has to appear, allowing for a management of the Shop (sending orders, checking deliveries, etc...).
My question, me being such a newbie with Swing, is: what is the best organization for a common pattern like this one?
Should I model another JFrame and pass as arguments all the data that I could happen to need (I really don't like this), or should I pass only a reference to the Controller class (this would be against the MVC pattern, I think).
Or maybe I should use a JDialog instead of another JFrame? The thing is that, really, the functionality that I need from this second window are a little too big for a dialog, I think...
I am confused, any tip/suggestion/advice will be much appreciated!
Thank you
Regards
Or maybe I should use a JDialog instead of another JFrame?
Bingo.
I actually don't like the idea of having a listener inside my Model class (aka Shop) – implementing the ActionListener. I think I would extend the JDialog class (let’s call it MyJDialog) then when a row is double clicked … create a new instance of MyJDialog class and pass in the Shop object in the constructor. Within the MyJDialog class you can modify the Shop object by calling mutators (setters). Moreover, the Shop class should have a way of notifying observers when a property is changed – take a look at PropertyChangeSupport.

How to go about with real GUI development with Java Swing and MVC

I am creating a Blackjack Card game emulator. I am a SCJP,familiar with Core Java concepts. I have a very basic understanding of Java swings and awt.
Already finished writing the basic game logic,a CLI logic. My design includes several classes like,
Dealer,Player,Table,Card,Casino and some others..
Enums for Cards and suite.
I have read about MVC as a theoretical concept, familiar with the name 'design patters'(no understanding whatsoever as to how they are implemented) Everywhere I am suggested to learn while writing some real code.So I started off with this...
I am stuck now, how should I go about writing code for my project?? Writing the GUI code and organising it within the already existent code.
It took me ages to learn MVC (I got taught incorrect things about it in university, and additionally a lot of online sources at the time were wrong about it). Anyway, the core of you need to do is not have any view information in your model (i.e., what the player looks like on the screen, the framebuffer, the polygons of your models). Instead, you create the view and model in separate namespaces, and then use events to link the two together. When sometimes happens in your model, the view gets notified, and changes are made to the view. Additionally, when the mouse is pressed or a key is pressed, the input event gets transformed into another model-oriented event which can take the form of a method call into the model. Any changes in the model are then fed back onto the view.
Remember this: the model should be functional without the view being attached, and should not show anything on the screen while executing (except perhaps debug info in the console).
Here is a simple example of how this could be split.
Presumably, a player's cards are represented as a 'hand' or a similar object (i.e. a collection of cards). This is your model. So lets call your model:
package casino.blackjack.model;
class DealtCards
{..}
You display your cards using maybe a JPanel or some other Swing construct. So you could put all the objects that actually do the rendering of each card in a seperate package:
package casino.blackjack.view;
class DealtCardsView
{..}
The DealtCards object exists independently of how it is displayed, but its state may change if a user does something on the GUI. For example, asking to be 'hit'. Presumably, there could be a button to do this. The view is derived from your model.
package casino.blackjack.view;
class DealtCardsView
{
JButton hitMeButton = new JButton("HIT");
DealtCards cards;
public DealtCardsView(DealCards myCards)
{
cards = myCards;
renderCards();
}
private void renderCards(){.. do something..}
}
Now, if a player decides to hit, his DealtCards object changes. So, we want to implement a way in which your model is updated. You can do this using a controller class. The controller class implements the ActionListener interface. When an action is performed (i.e. user clicks "hit" button), the controller updates the model. So the view cannot directly update the model. It just sends a notification that an 'action' has occurred. Any interested parties, in this case, our controller, can then take appropriate action.
package casino.blackjack.controller;
class DealtCardsController implements ActionListener
{
DealtCards cards;
DealtCardsView cardView;
public DealtCardsController(DealtCards myHand, DealtCardsView myView)
{
cards = myHand;
cardView = myView;
cardView.hitMeButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
cards.changed();
}
}
So you split your application in three layers. Your model just contains the current state (or current data), and any validation that goes around it. Your view classes render the model in an appropriate manner. Any user interaction, on the view, is handled by the controller, whose responsibility is then to update the model.
This way, if you want to change your view, (say use an applet instead of a window) your model doesn't care.
Sorry about the long winded reply, but hope that helps a little!
EDIT: A nice MVC explanation here: java / gwt UI coding - clean code

Categories

Resources