I'm trying to use events to do something on actor but i don't understand how to do it properly.
I have a button on my screen and a text (just for example). they are both actors in a stage
my purpose is: if i click on the button, i would like to change text
I add listener on my button, i get the click but i don't know how to send event (or anything else) to my text to set it.
Main class with stage definition and his
public class AGame implements ApplicationListener {
private WorldRendererTouchPad renderer;
private Stage stage;
private static Vector3 cameraVelocity=new Vector3(0,0,0);
private ButtonJump button;
public static final int SCREEN_WIDTH=800;
public static final int SCREEN_HEIGHT=480;
public void create() {
stage = new Stage();
stage.setViewport(SCREEN_WIDTH, SCREEN_HEIGHT, true);
stage.getCamera().translate(-stage.getGutterWidth(), -stage.getGutterHeight(), 0);
renderer = new MyRenderer(SCREEN_WIDTH, SCREEN_HEIGHT);
stage.addActor(renderer);
renderer.create();
button=new ButtonJump();
stage.addActor(button);
button.create();
Gdx.input.setInputProcessor(stage);
}
....
resize and other methods
}
MyRenderer class (contains text actor):
public class MyRenderer {
private TextTest text;
public MyRenderer(float screenWidth, float screenHeight) {
setBounds(0, 0, screenWidth, screenHeight);
}
public void create() {
this.initActors();
}
private void initActors() {
text=new TextTest("Hello world!");
addActor(text);
}
// is it usefull?
public void setText(String newText) {
text.setText(newText);
}
}
and the ButtonJump class (extends MyButton just here for define Skin and ButtonStyle)
public class ButtonJump extends MyButton {
public boolean isJump=false;
private static InputListener buttonListener=new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("event" , "="+event.toString());
// do something to update text
return true;
}
};
public ButtonJump() {
super();
}
public void create() {
this.setPosition(getStage().getWidth()-60, 30);
this.addCaptureListener(buttonListener);
}
public void capture() {
if (this.isJump)
Gdx.app.log("jump button", "Jump is set");
else
Gdx.app.log("jump button", "No jump");
}
}
If you use the clicklistener you need to let the other actor hold an reference to it to call a method on click. It is not that good to let all Actor know of each other. Use an anonymous way.
There is a "common" system for it in games.
If you really want to use Events, do implement an Event-System. Therefore you have an interface Listen and an Interface Event_Handler. At the start of your game you init one Implementation of the Eventhandler. The interface should at least look like this:
public interface Interface_EventHandler extends Disposable
{
public void handleEvent(final Event... e);
public void registerListener(final Interface_Listen listener,
final Event_Type... type);
public void unregisterListener(final Interface_Listen... listener);
public void unregisterAllListener();
public void unregisterAllListener(final Event_Type... type);
public void processEvents();
public void processEvents(final int maxTimeInMS);
}
Okay so now how does it work. The handler has an hashmap with all eventtypes as Key and an list of listeners as Value. So if someone want to notice an event he registers with the registerListerner at the handler for the right Event_Type (Enum). It need to have the interface Listen to get events. Everyone can now push an Event into the handler with the handleEvent(...) method. Or even more than one.. (varargs) ..
Okay that still does not explain how it work. We now have a registered listener (actor for example) and we have events that get into the handler.
Every Rendercycle you call the processEvents() at the hanlder once. That mean that every event that get pushed in at a frame get handled at the next frame. (Asynchronus) While that he iterates over all events and push them to the listeners. Moreover the listener should have a queue too where they put all events and when they are at their .act() they handle the events. (more asynchronus).
Okay here is an Handler i use:
package com.portaaenigma.eventsystem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import com.badlogic.gdx.utils.TimeUtils;
import com.portaaenigma.managers.Logger;
public class EventHandler implements Interface_EventHandler
{
private HashMap> listeners;
private LinkedList events;
public EventHandler()
{
listeners = new HashMap<Event_Type, ArrayList<Interface_Listen>>();
// add the arraylist for every Eventtype
for (Event_Type e : Event_Type.values())
{
listeners.put(e, new ArrayList<Interface_Listen>());
}
events = new LinkedList<Event>();
}
#Override
public void handleEvent(final Event... e)
{
for (Event event : e)
{
events.push(event);
}
}
#Override
public void unregisterListener(final Interface_Listen... listener)
{
for (Event_Type e : Event_Type.values())
{
for (Interface_Listen interface_Listen : listener)
{
listeners.get(e).remove(interface_Listen);
}
}
}
#Override
public void processEvents()
{
while (events.size() != 0)
{
// get the first element and delete it
Event e = events.pop();
for (Interface_Listen l : listeners.get(e.getType()))
{
l.handleEvent(e);
}
}
}
#Override
public void processEvents(final int maxTimeInMS)
{
int startSize = 0;
if (events.size() != 0)
{
startSize = events.size();
Logger.log("Processing Events: " + events.size());
}
long startTime = TimeUtils.millis();
while (events.size() != 0)
{
// get the first element and delete it
Event e = events.pop();
for (Interface_Listen l : listeners.get(e.getType()))
{
l.handleEvent(e);
}
// stop handling if time is up
if (startTime - TimeUtils.millis() > maxTimeInMS)
{
Logger.log("Handled " + (events.size() - startSize) + " Events");
break;
}
}
}
#Override
public void registerListener(final Interface_Listen listener,
Event_Type... type)
{
for (Event_Type event_Type : type)
{
listeners.get(event_Type).add(listener);
}
}
#Override
public void unregisterAllListener()
{
Logger.log("UnregisterAll");
for (Event_Type e : Event_Type.values())
{
listeners.get(e).clear();
}
}
#Override
public void unregisterAllListener(final Event_Type... type)
{
for (Event_Type event_Type : type)
{
listeners.get(event_Type).clear();
}
}
#Override
public void dispose()
{
unregisterAllListener();
events.clear();
listeners.clear();
}
}
The interface for all listeners is simple it's just this:
public interface Interface_Listen
{
public void handleEvent(final Event e);
}
Last but not least the event. How can you now send different data? Quiet simple. Have an hashmap out of Strings and Strings and for sure the EventType.
public class Event
{
private Event_Type type;
private HashMap<String, String> m_messages;
public Event(final Event_Type e, final Event_Message... m)
{
m_messages = new HashMap<String, String>();
for (Event_Message message : m)
{
m_messages.put(message.m_key, message.m_value);
}
type = e;
}
public Event_Type getType()
{
return type;
}
public void addMessages(final Event_Message... m)
{
for (Event_Message event_Message : m)
{
m_messages.put(event_Message.m_key, event_Message.m_value);
}
}
public String getMessage(final String name)
{
if (m_messages.get(name) == null)
{
Logger.error("Message not found: " + name);
}
// if null return an empty string
return m_messages.get(name) != null ? m_messages.get(name) : "";
}
public void clearMessages()
{
m_messages.clear();
}
}
Okay i hope this does explain how to implement an EventSystem at a Game. This meight not be the regular way at other Software but in games you queue up the events and handle them once in a Gameloop cycle. Also the listeners do the same.
So in your case. Implement such an handler and register the actors as listener. Sure they need to implement the listener interface and do something with the event. Let the one actor push an event into the handler which directs to the other actor and your are done. And they event dont need to know of each other and it does work for as much actors as you whish. You can even create 1 event for different classes different actors and so on. Usefull for example at mapchange. You push one event with the notice.. "changemap".. and every actor knows he need to stop moving and every subsystem knows that it does need to stop because of an mapchange and so on ...
It seems to be a bit overkill but it has alot of advantages and worth to use even at early stages. I made the misstake and started using it laterly and now i regret it.
Sorry for the bracing. It's not the regular java standart but more clear i think... Sorry for alot of varargs just like it at that point. Meight be confusing.
Literatur:
Game Coding Complete, Fourth Edition Chapter 11
Related
I'm trying to find an easy way of linking a TreeView of type Download to an ObservableList of the same type.
MainController.java
public class MainController {
private ObservableList<Download> downloads = FXCollections.observableArrayList();
#FXML private TreeView<Download> $TreeDownloads;
#FXML
public void initialize() {
$TreeDownloads.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
$TreeDownloads.setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
$TreeDownloads.setShowRoot(false);
downloads.addListener(new ListChangeListener<Download>() {
#Override
public void onChanged(Change<? extends Download> c) {
if (c.wasAdded()) {
addDownloads(c.getAddedSubList());
}
if (c.wasRemoved()) {
//
}
}
});
downloads.add(new Download("3847"));
downloads.add(new Download("3567"));
downloads.add(new Download("2357"));
}
private void addDownloads(List<? extends Download> downloads) {
downloads.forEach(download -> {
TreeItem<Download> treeItem = new TreeItem<>(download);
$TreeDownloads.getRoot().getChildren().add(treeItem);
new Thread(download::start).start();
});
}
private void removeDownloads(List<? extends Download> downloads) {
// remove treeitems from the treeview that hold these downloads
}
}
Download.java
public class Download {
private DoubleProperty progress = new SimpleDoubleProperty(0D);
private StringProperty id = new SimpleStringProperty("");
public Download(String id) {
this.id.set(id);
}
public void start() {
while (progress.getValue() < 1) {
try {
Thread.sleep(1000);
progress.add(0.1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public String toString() {
return id.getValue();
}
}
How do i implement a remove by Object(Download) mechanism, and is there an easier way to bind observablelist's items to a treeview?
Still not entirely certain what the exact problem is, all pretty straightforward:
First off, your list change listener implementation is incorrect, it must advance the subChanges before accessing its state (you did run your posted code, or not ;)
downloads.addListener(new ListChangeListener<Download>() {
#Override
public void onChanged(Change<? extends Download> c) {
// this while was missing
while (c.next()) {
if (c.wasAdded()) {
addDownloads(c.getAddedSubList());
}
if (c.wasRemoved()) {
// accessing the list of removed elements is .. plain standard api
removeDownloads(c.getRemoved());
}
}
}
});
Now implement the removal of the corresponding treeItems:
private void removeDownloads(List<? extends Download> downloads) {
// remove treeitems from the treeview that hold these downloads
List<TreeItem<Download>> treeItemsToRemove = treeDownloads.getRoot().getChildren().stream()
.filter(treeItem -> downloads.contains(treeItem.getValue()))
.collect(Collectors.toList());
treeDownloads.getRoot().getChildren().removeAll(treeItemsToRemove);
}
Asides:
java naming conventions use lowercase letters for members: treeDownloads (not $TreeDownloads)
the "verifiable" in MCVE implies being runnable as-is: the poster should be the first to verify that ;) yours wasn't due to incorrect implementation of the listener
the "minimal" in MCVE means leaving out everything that's not needed: f.i. calling the threading code - which in your first snippet was particularly distracting because violating fx' threading rule is a rather common error
I have a custom dialog that is added to the scene and then removed again. Doing profiling with VisualVM, I noticed that even after a GC run the instance of this dialog is still retained.
I know that this means that there must be a reference to that object somewhere so I had a look at the references:
As seen in the image there are a lot of references from this$ which means inner classes, in this case they are bindings or ChangeListeners. The change listener can be replaced with WeakChangeListener. I'm not quite sure how I should handle the Bindings however.
Furthermore there are some references that do not make much sense at first glance:
bean of type SimpleStringProperty or SimpleObjectProperty
oldParent and value of type Node$1
So here are the concrete questions:
How to get around these strong references, so the object can actually be garbage collected? Would the use of lambda expressions instead of anonymous inner classes have any effect in this respect? How to figure out where the object is references by bean, oldParent and value.
EDIT1:
The bean references of type SimpleStringProperty are used in the super class and therefore should not cause an issue here, I guess. One SimpleObjectProperty bean reference comes from a utility method that provides an EventHandler. How would I resolve that, is there something similar for EventHandler as for ChangeListeners?
EDIT2:
I tried to come up with a simple application to reproduce the same thing. I could manage it and saw that I have basically the same fields listed in the heap dump, but then noticed that I have retained a reference to the component that is removed from the scene in my application. Once I let go of that reference it was cleaned up. The only noticeable difference is in my small example there is no reference in an Object array.
EDIT3:
I did some digging and found two places in the code that when commented out or not used, will not cause the object become eligible for garbage collection. The first one is this ChangeListener:
sailorState.numberOfSailorsProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue,
Number oldValue, Number newValue) {
int inTavern = newValue.intValue()-sailorsAdditionalOnShip.get();
if (inTavern < 0) {
sailorsAdditionalOnShip.set(Math.max(sailorsAdditionalOnShip.get() + inTavern, 0));
inTavern = 0;
}
sailorsInTavern.set(inTavern);
}
});
The second one is a bit more complex. The component is a Dialog that has a close button. On pressing that one the dialog closes. This is the code of the button, I do not think that with this part is the problem, but for completeness sake:
public class OpenPatricianButton extends Control {
protected final StringProperty text;
protected final ReadOnlyObjectProperty<Font> currentFont;
protected final ObjectProperty<EventHandler<MouseEvent>> onAction;
public OpenPatricianButton(String text,
final Font font) {
super();
this.text = new SimpleStringProperty(this, "text", text);
this.currentFont = new ReadOnlyObjectPropertyBase<Font>() {
#Override
public Object getBean() {
return this;
}
#Override
public String getName() {
return "currentFont";
}
#Override
public Font get() {
return font;
}
};
this.onAction = new SimpleObjectProperty<EventHandler<MouseEvent>>(this, "onAction");
this.getStyleClass().add(this.getClass().getSimpleName());
}
#Override
public String getUserAgentStylesheet() {
URL cssURL = getClass().getResource("/ch/sahits/game/javafx/control/"+getClass().getSimpleName()+".css");
return cssURL.toExternalForm();
}
public StringProperty textProperty() {
return text;
}
public String getText() {
return text.get();
}
public void setText(String text) {
this.text.set(text);
}
public Font getFont() {
return currentFont.get();
}
public ObjectProperty<EventHandler<MouseEvent>> onActionProperty() {
return onAction;
}
public EventHandler<MouseEvent> getOnAction() {
return onAction.get();
}
public void setOnAction(EventHandler<MouseEvent> onAction) {
this.onAction.set(onAction);
}
}
public class OpenPatricianSmallWaxButton extends OpenPatricianButton {
public OpenPatricianSmallWaxButton(String text,
final Font font) {
super(text, font);
}
#Override
protected Skin<?> createDefaultSkin() {
return new OpenPatricianSmallWaxButtonSkin(this);
}
public OpenPatricianSmallWaxButton(String text) {
this(text, Font.getDefault());
}
}
public class OpenPatricianSmallWaxButtonSkin extends SkinBase<OpenPatricianSmallWaxButton> {
public OpenPatricianSmallWaxButtonSkin(final OpenPatricianSmallWaxButton button) {
super(button);
InputStream is = getClass().getResourceAsStream("sealingWaxFlattend.png");
Image img = new Image(is);
final ImageView imageView = new ImageView(img);
final Label label = new Label();
label.textProperty().bind(button.textProperty());
label.getStyleClass().add("OpenPatricianSmallWaxButtonLabeled");
label.setFont(button.getFont());
label.onMouseClickedProperty().bind(button.onActionProperty());
label.textProperty().bind(button.textProperty());
imageView.onMouseReleasedProperty().bind(button.onActionProperty());
StackPane stack = new StackPane();
stack.getChildren().addAll(imageView, label);
Group group = new Group(stack);
group.setManaged(false);
button.setPrefHeight(img.getHeight());
button.setPrefWidth(img.getWidth());
getChildren().add(group);
}
}
And here is the code fragment where the button is instantiated:
closeButton = new OpenPatricianSmallWaxButton("X", font);
closeButton.setLayoutX(WIDTH - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_PADDING);
closeButton.setLayoutY(CLOSE_BTN_Y_POS);
closeButton.setOnAction(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
executeOnCloseButtonClicked();
}
});
closeButton.getStyleClass().add("buttonLabel");
getContent().add(closeButton);
The call to remove the button is done through Guava AsyncEventBus. Therefore the code is a bit length. It starts in the Application thread and then gets posted to the event bus thread which then eventually has to call Platform.runLater:
protected void executeOnCloseButtonClicked() {
ViewChangeEvent event = new ViewChangeEvent(MainGameView.class, EViewChangeEvent.CLOSE_DIALOG);
clientEventBus.post(event);
}
public void handleViewChange(ViewChangeEvent event) {
if (event.getAddresse().equals(MainGameView.class)) {
if (event.getEventNotice() instanceof DialogTemplate) {
setNewDialog((DialogTemplate) event.getEventNotice());
} else {
sceneEventHandlerFactory.getSceneEventHandler().handleEvent(event.getEventNotice());
}
}
}
public void handleEvent(Object eventNotice) {
Preconditions.checkNotNull(dialogContoller, "Dialog controller must be initialized first");
if (eventNotice == EViewChangeEvent.CLOSE_DIALOG) {
dialogContoller.closeDialog();
}
....
public void closeDialog() {
if (Platform.isFxApplicationThread()) {
closeDialogUnwrapped();
} else {
Platform.runLater(() -> closeDialogUnwrapped());
}
}
private void closeDialogUnwrapped() {
if (dialog != null) {
new Exception("Close dialog").printStackTrace();
getChildren().remove(dialog);
dialog = null;
dialogScope.closeScope();
}
}
The really peculiar thing is that the dialog can be cleaned up by the GC (provided the first issue with the ChangeListener is commented out) when I call closeDialog from a timer. In other words this behaviour does only happen if I close the dialog with a mouse click.
I was just wondering if there are any callback methods or if we can create some call backs for action listener in java (lets say: beforeAction(), afterAction() etc...), just like we have some of the call backs in Javascript, like:
beforeFilter(), afterFilter() etc...
I've Googled the topic, but didn't found out what exactly I'm looking for.
I've also thought of something like:
public void actionPerformed(ActionEvent e) {
beforeAction();
actuallAction();
afterAction();
}
Shall we consider those methods as callbacks???
Any Help would be appreciated.
Thanks.
Edit: Yeah I'm asking about java swing.
First of all, the need for ordered listener execution might be an indicator for a design problem/mistake, as usualy listeners should not have any causal dependencies. So review your design first.
If you still insist on staged listeners, all you need is some kind of 'staged' action listener adapter that delegates ActionEvents to three different groups of listeners (the 'stages'):
public class StagedActionEventSource implements ActionListener {
public static StagedActionEventSource forButton(Button button) {
StagedActionEventSource l = find(button.getActionListeners());
if (l == null) {
l = new StagedActionEventSource();
button.addActionListener(l);
}
return l;
}
public static StagedActionEventSource forList(List list) {
StagedActionEventSource l = find(list.getActionListeners());
if (l == null) {
l = new StagedActionEventSource();
list.addActionListener(l);
}
return l;
}
// ... add more widget-based implementations here ...
private static StagedActionEventSource find(ActionListener[] listeners) {
for (ActionListener l : listeners) {
if (l instanceof StagedActionEventSource)
return (StagedActionEventSource) l;
}
return null;
}
private ActionListener beforeActionRoot;
private ActionListener onActionRoot;
private ActionListener afterActionRoot;
public void addBeforeActionListener(ActionListener l) {
beforeActionRoot = AWTEventMulticaster.add(beforeActionRoot, l);
}
public void removeBeforeActionListener(ActionListener l) {
beforeActionRoot = AWTEventMulticaster.remove(beforeActionRoot, l);
}
public void addActionListener(ActionListener l) {
onActionRoot = AWTEventMulticaster.add(onActionRoot, l);
}
public void removeActionListener(ActionListener l) {
onActionRoot = AWTEventMulticaster.remove(onActionRoot, l);
}
public void addAfterActionListener(ActionListener l) {
afterActionRoot = AWTEventMulticaster.add(afterActionRoot, l);
}
public void removeAfterActionListener(ActionListener l) {
afterActionRoot = AWTEventMulticaster.remove(afterActionRoot, l);
}
#Override
public void actionPerformed(ActionEvent e) {
fireEvent(beforeActionRoot, e);
fireEvent(onActionRoot, e);
fireEvent(afterActionRoot, e);
}
private void fireEvent(ActionListener root, ActionEvent e) {
if (root != null) {
root.actionPerformed(e);
}
}
}
Note that this concept only works if all your listeners are registered via this adapter. Of course it is still possible to directly register a listener at the component, but this listener will then not take part in the staged event dispatching - instead it will be called before or after the listeners registered at the StagedEventSource.
Usage:
Button button = new Button(...);
StagedActionEventSource.forButton(button)
.addBeforeActionListener(new MyActionListener());
StagedActionEventSource.forButton(button)
.addActionListener(new MyActionListener());
I dont know if Java has this kind of feature (rather not), but you can always chech on Aspect Oriented Programing and it's implementations in Java like Spring-AOP .
I have a JSlider component on my frame which is being constantly updated by an external component (a media player which sets a new value from time to time). I want the slider to handle the stateChanged event only when I manipulate the slider and not my external component.
Is there any way to achieve this?
I'd implement my own BoundedRangeModel, this way you can add additional flags that indicates whether it should accept updates or not
UPDATE with EXAMPLE
The basic idea would be to implement your own model, that way you can control when the value is actually changed
public class MyBoundedRangeModel extends DefaultBoundedRangeModel {
private boolean updatesAllowed;
public void setUpdatesAllowed(boolean updatesAllowed) {
this.updatesAllowed = updatesAllowed;
}
public boolean isUpdatesAllowed() {
return updatesAllowed;
}
#Override
public void setMinimum(int n) {
setUpdatesAllowed(true);
super.setMinimum(n);
setUpdatesAllowed(false);
}
#Override
public void setMaximum(int n) {
setUpdatesAllowed(true);
super.setMaximum(n);
setUpdatesAllowed(false);
}
#Override
public void setExtent(int n) {
setUpdatesAllowed(true);
super.setExtent(n);
setUpdatesAllowed(false);
}
#Override
public void setValue(int n) {
super.setValue(n);
}
#Override
public void setValueIsAdjusting(boolean b) {
setUpdatesAllowed(true);
super.setValueIsAdjusting(b);
setUpdatesAllowed(false);
}
#Override
public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting) {
if (isUpdatesAllowed()) {
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
}
}
}
This would allow you to control the change of the "value" property. The problem you have here is that ALL the set methods go through the setRangeProperties method, so you need to decide what should be allowed to effect it. In my example, the only method that does not control it is the setValue method.
In your code you would need to call it something like...
MyBoundedRangeModel boundedRangeModel = new MyBoundedRangeModel();
slider.setModel(boundedRangeModel);
...
boundedRangeModel.setUpdatesAllowed(true);
slider.setValue(value);
boundedRangeModel.setUpdatesAllowed(false);
Your only other choice is to extend the JSlider itself and override the setValue method directly in a similar way
I am facing problem to set a perticulat value of a custom JComboBox. If I call setSelectedItem() from the initialize() method of the following class it is not selecting the particular value.
The extended JComboBox class is:
public class ThemeComboBox extends JComboBox {
private static final long serialVersionUID = 50L;
public ThemeComboBox(DefaultComboBoxModel model) {
super(model);
initialize();
LibraryLogger.initMessage(getClass().getSimpleName());
}
public void initialize() {
ThemeComboBoxModel model = (ThemeComboBoxModel) getModel();
for(ThemeModel themeModel : model.getThemeModels()) {
if(themeModel.getThemeClass().equals(ConfigurationManager.getInstance().getUiManager().getUiProperties().getTheme())) {
setSelectedItem(themeModel);
System.out.println("=========");
break;
}
}
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
ThemeComboBox themeComboBox = (ThemeComboBox) actionEvent.getSource();
System.out.println(themeComboBox.getSelectedItem());
}
});
}
}
While if I override the getSelectedItem() of custom DefaultComboBoxModel then it is selecting that value but on choosing other value the selection remain same or it remain unchange.
The model class is:
public class ThemeComboBoxModel extends DefaultComboBoxModel {
private static final long serialVersionUID = 51L;
private Vector<ThemeModel> themeModels;
public ThemeComboBoxModel(Vector<ThemeModel> models) {
super(models);
}
public Vector<ThemeModel> getThemeModels() {
return themeModels;
}
public void setThemeModels(Vector<ThemeModel> themeModels) {
this.themeModels = themeModels;
}
/*#Override
public Object getSelectedItem() {
for(ThemeModel themeModel : themeModels) {
if(themeModel.getThemeClass().equals(ConfigurationManager.getInstance().getUiManager().getUiProperties().getTheme())) {
return themeModel;
}
}
return null;
}*/
}
I am unable to understand what I am doing wrong. Any information will be very helpful to me.
Thanks in advance.
1) I hope that main method is initialized from invokeLater
2) Swing is single threaded, where output to the GUI is done quite in one moment
3) there isn't any guarantee that all events have got any order, basically isn't possible ordering events for Swing GUI, same/especially on GUI startup
4) show GUI (setVisible(true);), then last codeline will be JComboBox#setSelectedItem(int or Object), wrapped inside invokeLater
5) add Listeners only if needed, remove useless Listeners