Java: Getting values from GUI - java

In my application user gets to choose "distribution type" for a few parameters and then I create Graph and show it to him. There are 3 different types of these distributions with each of them having its own parameters ( like alpha, beta, probabilities, etc). Each parameter can have either of those distributions.
Here is the screenshot to make it clear, what I'm trying to describe:
Distribution options are contained in CardLayout, that is controlled by combobox.
When user presses the button, I need to instantiate proper domain objects for distributions. Right now, I'm just passing ComboBox item (which is enum) and CardLayouted panel to factory that chooses proper subpanel and instantiates correct object. But it seems wrong to pass around gui objects, also makes factory useless for any other situation.
But I can't think of a better way to instantiate correct object. Probably just one idea:
Let CardLayouted panel decide which panel is ontop and instantiate
proper object on request. I wouldnt need any factories for this one. But is it ok for gui object to do this kind of logic? How can I delegate to domain in a proper way?
All suggestions will be appreciated a lot!

Swing has generally good support for MVC and pushing or pulling data from a domain object to input / display controls. What I'd do is:
Instantiate the panels you put into the CardLayout with a "blank" domain object as its GUI model. (Or some sort of locator that can retrieve the model from another layer.) Then hook up change notifications on your input components that will update the domain object when the values in the input change.
Then, when it comes to persisting the domain object, just retrieve it from the form panel.
If you need to show the same model value in two controls, they should share the same model. If you need to do updates to an object being displayed from lower layers of the code, you should perform the update on the model instead of / in addition to the domain object.

Related

Vaadin Best approach: distribute object state changes to other components

I'm dealing with a WebApp (Vaadin19) and stuck now in the question, how to share an object-state change from one component to another. There is one object instance in two or more components. After changing an attribute of the object in one component and going back to another component, I want to see the changed attribute.
Let me explain, what I mean:
There is a grid with some lines of data. The grid shows only a subset of the data to respect the clarity.
A click on the grid opens a detailed view in "read mode". The data is structured (contains sub-objects itself).
A click on the "read mode"-view opens then a dialog with tabs. The activated tab depends on the sub-object, that was clicked before.
After changing an element in the sub-object and closing the dialog, I want that the UI will reload/revalidate it's content. I think it's clear, that I use there the same object-instance.
Is there an event I have to submit to the UI?
Or:
What is the best approach for this?
The actual refresh is easy: theGrid.getDataProvider().refreshAll(), or refreshItem instead if you have access to the item that has been changed and it has a good implementation of equals and hashCode.
How to hook things up so that the dialog notifies the grid is then really depending on your architecture.
If they are already close to each other in the code, then you could e.g. store a reference to the Grid in an instance field and just reference that in the dialog handler.
If you want to decouple, then you need some kind of event bus. You can use the regular Spring event mechanisms as long as you ensure that the event stays within the UI scope. Alternatively, you can use ComponentUtil::addListener and ComponentUtil::fireEvent to use e.g. UI.getCurrent as a simple event bus.

How to update a panel which shows details of an object

I have a panel, let's call it detailsPanel, which holds a Person reference and displays its field values in the following manner:
Name: person.getName ();
Surname: person.getSurname ();
Emain: person.getEmail ();
.... .......
.... .......
And so on. I will use JLabels (correctly aligned using a GridBagLayout) to show each (fieldName, fieldValue). I have a lot of fields to display.
The problem is that the panel which shows the details must be always visible, i.e it will not be shown in a modal JDialog, so that i could create the panel by simply reading my Person object fields at the panel creation.
The panel must always be visible, and its Person reference will change when the user selects a different row in a Person list. This means i will call a method to update its state, something like:
detailsPanel.setPerson (aPerson);
Now, i'm wondering how i should update all the fields. Should i keep a reference to all the JLabels which show the values, and use setText(value) on each of them when i update the panel, or would it be better to override getText() method for every label, returning the correct field value, so that in the update method i would only repaint the panel, and the text would automatically change when the getter method is used on a different Person object?
Any suggestion is appreciated!
Since this is UI stuff which is usually called almost never (relative to how often things are called in other computation) you don't need to worry about efficiency at all. Just do what you think is the most elegant solution. There are three options That quickly come to my mind. They are ordered from quick and static to elegant and reusable:
Quick and dirty: create your constructor and make everything look nice. Then move everything from the constructor to a separate init() method and every time the entities change, you just call removeAll(); and then init() again.
As you suggested, keep a reference to all labels and use the setPerson() method to update all panels. Then call this method in the constructor (this is arguably the most common solution).
As you suggested, build your own extension of JLabel. This new class should either have an update() method which is to be called when things change, or have it set its own listeners to ensure that it gets notified of any relevant change.
If you are planning to create a single panel which is supposed to display all kinds of objects, you could have those object implement an interface called Displayable which gives you generic access to all its values and maybe even listeners to each value. An alternative to the Displayable interface is to use reflection and use annotations to allow the panel to get its values for display.
Please note that the most elegant solution is - contrary to what some people may tell you - not always the best for any situation. How much maintenance do you expect there to be in the future? How big is the application? Will you ever hand off the code to someone else? All these and more need to be considered to decide how "nice" you want your solution to be.

GUI with multiple frames

I'm looking to build out a Java GUI with a table area and an area that will display the data of a selected row of the table. I've never tried a multi-frame set up before so before I venture to do this I wanted to check with others. Is it difficult to have two frames and have them passing data back and forth? The idea would be that I could move the details frame anywhere I like on the screen or to a second monitor and allow the table to go full-screen if the user wants. Any input or examples are appreciated.
don't to create two of more JFrames use JDialog instead,
reuse this JDialog for another action(s)
create one JFrame and one JDialog for displaying details
have to determine if and which of JTables row(s) is selected
better would be to set ListSelectionMode to the SingleSelection
maybe would be better to invoke (show that already exist) JDialog from JPopupMenu Action
You should have no problem in doing what you are after. You can have public methods in each frame which expose properties and/or structures and you then pass the instance of one JFrame to the other. This should allow you to pass data back and forth.
That being said however, I think that this scenario is valid only when you have one, two, or at most three JFrames. Having a lot of frames calling each other could result a maintenance nightmare.
there are several possibilities to do so:
you can add one of the jframes as a listener to anothe, or both to each other. For this, you have to implement a listener mechanism, like in java.awt. You can pass the information contained in the event objects - this would be the most clean alternative
you can pass the instance of the detailframe directly in the constructor of the main frame and call operations from main frame on detail frame. this is the simplest way, but you will need lot of code changes if you have some new features to add

Java swing card layout - show function

I'm using the card layout to create my app,
2 of my cards are shearing the same information (in one you enter data to textarea and in the other the data is printed).
The data is been saved in the Frame.
I have added a refresh function to the second card that get the value and print it, But I don't know how to trigger it.
Is there any event that can be bind to this function?
Or any other way to get to the card functions from the frame (so I can trigger it every time I show the card)?
Thanks'
There are generally two ways of achieving what you are after. Either you update/refresh the output card whenever it is displayed, like you suggested. This can be done by adding a ComponentListener to the Component that you use as your output card. This way you can override the componentShown method so that it calls your custom refresh method. See the accepted answer for this question.
The second alternative is to call refresh whenever any of the data is changed - always keeping it up to date, even when it is not actually visible. Depending on how your application looks this might be done in different ways. If you have a dedicated data model then you could use the Observer / Observable pattern to notify changed from an internal model, or you could hard-code the model to call refresh whenever it is changed. If you just want to get the data directly from the input fields on the first card, then you could just add that code into their respective change listeners etc.

Java Swing: how do I properly instantiate GUI and pass domain objects?

I have a GUI with nested panels(tabbed with nested panels and etc). I need to pass domain object to deeply nested panel. I can think of two ways:
Instantiate all gui objects in one place, like frame class. That
would make passing domain objects dead simple, but Frame class will
be huge and hardly maintanable.
Each panel has its own class, where we instantiate and layout its
components. Now its easy to maintain and classes are clean, but how
do I pass down the chain my domain objects? I dont want to chain-pass
them through constructors of panels that shouldn't even know their
existance. And top level panels would have a ton of these objects to
start with.
Niether way seems like a soulution. How do you usually aproach this?
When I put together a Java Swing GUI, I have a data model for each major GUI element. Note that this isn't an MVC pattern. This is more like a local MV pattern. If you want, you can consider GUI element listeners as the "controller".
Each panel has its own class, where we instantiate and layout its
components. Now its easy to maintain and classes are clean, but how
do I pass down the chain my domain objects?
You have the right idea, although you shouldn't have to do much passing.
My JFrame (or JApplet) will have an associated model class of global type fields. An instance of this model class will usually be passed along to the children elements. This is to allow children elements to react properly when a menu option is selected (as an example)
My JPanel(s) will have an associated model class that maintains the state of text or button children elements.
More complicated children elements, like a JList or a JTree, already have an associated data model. I will probably wrap these associated data models into the JPanel model class for convenience.
The children elements will trigger some sort of selection or action listener. Some of these listeners might need access to model classes besides the model class associated with the parent. In this case, you're going to have to pass the instances of your model classes to the listeners.
This is sort of a Chain of Responsibility pattern. What I would do is have something that creates a map with all of your display objects in it and pass it from constructor to constructor. That way every instance can take what it needs from the map without caring what else is there.

Categories