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.
Related
I am making some application for myself, just to practice on my designs and GUI.
My application is divided into two sides, first side is the model / logic however you call this, second side is the visual side, where you handle the gui, buttons and view.
So now my application has a feature that pops up and asks the user if he wants to use some feature, and then if he clicks yes, it will open a new JFrame window with many configurations.
these configurations will "probably" be in the Config class.
My question is, what is the best way to transfer data from the GUI to the model? Since you have to create a button listener in order to detect button clicks or text, what is the best proper way to update the configuration after the button was clicked?
For example, you have an application, and in order to start it you need to click on the button, I have two ideas in my head:
Transfer the Config object to the area where you handle the button & listen to it
Make Config static, and set up a Set() method, so you can set configurations without any objects, like Application.setConfiguration(config, type)
But I heard that statics are NOT always good, so I wondered, using static in this case is OK and good or are there better ways to do this? Or passing the config object to the GUI area is OK aswell?
This is how my structure looks like:
(source: gyazo.com)
I want to get my event listener called when the component is repainted (JComponent). I read about different Event Listeners but none seems to be the correct one for Invalidate or Repaints. Any way to do this?
Why I want this: I'm trying to get notified when there is some change in a control, in order to fire the method that tracks the changes (as in the file has changed, "do you want to save changes?").
Another use for this is for manually invoking the custom layout manager of a non-added-to-the-container-but-drawn component (this one is kind of complex, it's for a GUI editor program).
Why I want this: I'm trying to get notified when there is some change in a control, in order to fire the method that tracks the changes (as in the file has changed, "do you want to save changes?").
Normally, you track changes to an edited file in the GUI model class. Every time your model adds or removes a character, you set a dirty flag in the model that you check later.
Another use for this is for manually invoking the custom layout manager of a non-added-to-the-container-but-drawn component (this one is kind of complex, it's for a GUI editor program).
Your understanding of Swing appears to be backwards. The components don't drive the layout. The layout arranges the components.
Here's one example of a Swing character based text editor.
Here's a Stack Overflow question about a GUI builder editor.
Right now, when I have a form with many JComponents, mainly JTextFields, JTextAreas, JComboboxes, JCheckBoxes and JButtons and want to control their behaviour, for instance the change of focus after a certain key was released, I do the following:
I put all my components in a JComponent[] and cycle through it, adding the appropriate listener. When an event is registered by said listener, I check with "instanceof" what kind of JComponent fired the event and assign the proper reaction.
I use this method for instance to cycle with VK_ENTER through the form, or to "firePropertyChange(..)" after a DocumentListener fires, or to add UndoRedoListeners and so on.
My question : is there a better way to do this and if yes, can you explain to me the benefits ?
but my question refers to the general practice of putting all
JComponents in an array and cycling through them for every listener
and every fired event. It works fine enough, but it feels a bit
"uneconomic",so I wanted to know if it is recommended practice, or if
there is a better way of doing it.
I usually write a custom listener (often as an anonymous class) per type/ instance if I have type/ instance specific behavior so that I can avoid instanceof and other other checks.
You'll want to customise the focus tranfersal system.
Take a look at How to Use the Focus Subsystem, in particular Customizing Focus Traversal
I have a JComboBox whose values are retrieved across the net.
I'm looking for a way to indicate that fact to the user, when the user wants to see the list, expands the drop down, and only then the data is being retrieved.
The basic requirements include:
JComboBox's drop-down shouldn't lock the EDT, but the combo's action should not work until there are values.
User should know when all data has been retrieved.
The size (UI real-estate) of the indication should be as small as possible.
Note that the data isn't retrieved until the user wants to see the combo's values (i.e. expands the drop-down list).
The solution i've used:
I've used a SwingWorker to keep the UI responsive. The combo box was overlayed using JIDE's Overlayable with JIDE's InfiniteProgressPanel that listens to the worker.
To avoid locking the EDT, your data retrieval should be done in a background thread. I would use a SwingWorker to find and load the values since this makes available a background thread with other goodies that make it very Swing-friendly. I would make the JComboBox enabled property false until all values have been loaded, and then enable it via setEnabled(true). You will know the SwingWorker is done either through its done() method (by overriding it), or by adding a PropertyChangeListener to the SwingWorker and being notified when its state is SwingWorker.StateValue.DONE.
One way for the user to know that the process is complete is that they will see when the combo box has been re-enabled. If you want a more obvious indicator, you could display a JProgressBar or a ProgressMonitor. This could be displayed in a dialog if you wish to leave the GUI appearance mostly unchanged.
I implemented it by adding "Loading..." item and a special border around the JComboBox. On click separate thread is started adding new items via SwingUtilities.invokeAndWait. When loading is completed the "Loading..." last item is removed.
to not force my users to wait until the data is loaded, combine the answers by eel and stan :-)
start off with the model containing zero or one real value plus the dummy entry "loading"
register a PopupMenuListener and start a SwingWorker loading the data (into a separate datastructure, might be a new model) in its very first menuWillBecomeVisible
while loading, select the dummy entry (and/or whatever else is appropriate to inform the user what's happening), the action has to be aware of "nothing-to-do-yet" as well
listen to the worker, when receiving the DONE replace/fill the data into the combo's model
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.