Design for a JApplet animation using Swing and Threads - java

I'm trying to implement a small Applet that does some animation. I would like to do the animation in a JPanel and below the Animation JPanel, have play/pause, and skip buttons to control the animation. To do this correctly, I think I need to have the animation in a Thread. (correct?)
My Questions are: Whats is a good way to organize my Classes for this application? How to I get my animation thread to run inside a JPanel?
I've been looking in the tutorials at oracle.com and this is what I have so far...
Class AnimationApplet extends JApplet {
...
public void init(){
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (InterruptedException ex) {
Logger.getLogger(TabApplet.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(TabApplet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private void createGUI() {
AnimationPanel ac = new AnimationPanel();
this.setConentPane(ac);
}
} // Class AnimationApplet
class AnimationPanel extends JPanel implements ActionListener {
...
}
Edit: I don't know if this will help, but here's exactly what I'm trying to do. I'm creating a guitar tab player so it would need to continue sliding the notes across the screen and then at certain points (16th notes), check if there are notes to animate. This seems kind of difficult because you can't divide ms by the beats per minute evenly. So for now, I'm thinking of dividing it into 4 or 5 speeds (slowest, slow, medium, etc);
Thanks,
Nate

No, you don't need to use Threads directly since you could simply use a Swing Timer to drive the animation (though understanding that this uses threading behind the scenes). I would have my animation component extend JPanel as you're doing and draw in its paintComponent method. I would avoid having any gui or "view" class extend a listener class as you're doing above as that's making a single class do too much. I'd either use anonymous inner listeners, or private inner class listeners or if complex separate stand-alone listener classes.
Another caveat -- make sure that your paintComponent method does painting and painting only, that it contains no program logic and avoid creating classes or reading in images from within this method. It needs to be lean and fast.

I like javax.swing.Timer for animation; here's a simple applet example.

Related

Lag before JFrame event handlers are added?

I'm working on a simple Java swing project. This is the code of the main class (name changed):
public class MainProg
{
private static MainProg program;
//mainWin is a JFrame
private MainWindow mainWin;
//Event handler class which extends MouseAdapter
private TrayManager trayMgr;
public static void main(String[] args)
{
program = new MainProg();
}
public MainProg()
{
mainWin = new MainWindow();
trayMgr = new TrayManager();
mainWin.startBtn.addMouseListener(trayMgr);
mainWin.setVisible(true);
}
}
As is clear, when the program starts, in main() it creates a new instance of the MainProg class, which then calls the constructor. In the constructor, it creates a new instance of the JFrame mainWin. It then attaches an event handler to a button on mainWin.
In the event handler class trayMgr, the only method is mouseClicked() which does nothing
except a System.out.println('Clicked');
The issue is, when I run this program in Netbeans, the JFrame is shown right away, but I seem to have to click the button 2-3 times before the message is printed in the console.
Is this just something specific to Netbeans, or do I have to change something to make the event handler be set before the window is made visible?
Your threading issue is not likely one that is causing your current problem, but there's the theoretic potential for problems, and I've seen some real problems associated with some of the more touchy look and feels. Quite simply you should queue your code that starts your GUI onto the Swing event thread. You do this by doing:
public void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(
public void run() {
program = new MainProg();
}
));
}
Someone else recommended using invokeAndWait(...) instead of invokeLater(...) but this can be risky especially if you inadvertently make this call from within the Swing event thread itself. For your situation you're better off using invokeLater(...).
But again, I think the main problem with the code you have shown was inappropriate use of MouseListener where an ActionListener should have been used. Learning to code any GUI library can be quite tricky, and for that reason, you can't assume anything. Check out the tutorials and learn from the experts. Also if you are considering coding Swing for the long haul, consider ditching the NetBean's code-generation utilities and learn first to code Swing by hand. You won't regret doing this.
Since you asked, the code I posted here is a Java SSCCE on a different topic. invokeLater is a way of running computations on the EDT. (There is also invokeAndWait, which would work fine here, but under some other conditions can cause a deadlock.)
In fact this example is perhaps a bit over-conservative. Some references say you can run Swing from the main thread the call to show() or setVisible(). However I have a program that misbehaves under Java 7 when I try that.

GUI threading in java

I'm trying to code a simple game in Java. The basic structure is a single JFrame with different JPanels that I add/remove at different times. At startup, there is a JPanel that's a basic menu (start game, high scores, etc). Once the "Start" button is pressed it switches to a level selector panel with three buttons to select the difficult level of the game. Once any of the three buttons is pressed, it switches to another panel that will displays a three second countdown, then the actual game. All three buttons call the same method, just with a different difficulty value passed in.
I have all the separate pieces working fine, but I'm having troubles with the transition from the level selection panel to the countdown. If I don't use threads the screen freezes on button press and does not switch to the new panel. I've tried messing around with threads, but I don't know that much about them and have only had limited success (I've got it so it will successfully switch some of the time, but not consistently).
In terms of code, in the level selection panel I have something like this listening for button clicks:
private class ButtonClickedListener implements ActionListener {
public void actionPerformed(ActionEvent evt) {
gui.newLevel(1);
}
}
where in place of just gui.newLevel(1) I've messed around with starting new threads and calling the method from them.
The newLevel() method look like:
getContentPane().removeAll();
levelPanel = new LevelPanel(levelNum, this);
add(levelPanel);
validate();
levelPanel.start();
I use very similar code when switching from the start menu JPanel to the level selector panel (again, with an ActionListener on the buttons), which works just fine.
LevelPanel's start() method initializes values for the new JPanel and displays the countdown on screen (currently with the following code, although I messed with putting something like this in the newLevel() method instead) before displaying the actual game:
try {
Thread.sleep(1000);
//update countdown number
validate();
repaint();
Thread.sleep(1000);
//update countdown number
validate();
repaint();
Thread.sleep(1000);
//update countdown number
validate();
repaint();
} catch (Exception e) {
System.out.println(e);
}
//start game
I would really appreciate any help getting this code to work, and I'm pretty sure some sort of threading is the way to go but I'm not quite sure where/how. Any suggestions and/or code samples would be great!
Thanks in advance!
EDIT: I ended up rewriting the countdown using a timer instead of Thread.sleep(), which fixed part of the problem and the rest of it I eventually figured out and was entirely unrelated to GUI stuff, which is why I didn't think to check it in the first place.
never really never use Thread.sleep(1000); during EDT, this code caused freeze on GUI is un_resposible, untill a new event invoke EDT or mouse hover over can alive this container too
1) there are two ways how to dealy any event(s) in the Swing GUI, by implements
Swing Timer
delaying by using Thread.sleep(1000); in the SwingWorker
The layout and painting must be done in EDT. Use SwingUtilities.invokeAndWait to call the validate() and repaint()
You can start some code with a time delay using TimerTask:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
invokeLater(); // This starts after [delay] ms
// and - if given - will run every [period] ms.
}
}, delay, period);
You could solve your problem with this, though it won't be a pretty solution.
// edit: (see comments) you should synchronize accesses to the gui properly, else it will give you errors.

Why does my boilerplate Java desktop app JFrame use EventQueue.invokeLater in the main method?

I am using the latest Eclipse, and GWT Designer, to make a swing application in Java.
The main function in my application window (which is a javax.swing.JFrame) in the auto generated by the tools looks like this:
/* launch the application */
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This seems like a lot of noise around what could have been just this:
public static void main(String[] args) {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
I have read that the EventQueue.InvokeLater technique is required in some situations, and another question asks where to use it here.
My question is simpler; Why do this automatically in the code generator here? Why should main return quickly and let the application window get created later by the event queue? Wouldn't blocking be exactly the point? Why is the JFrame auto-generated designer doing this EventQueue stuff? I have tried to see some difference in the start up and showing of forms whether this code is done the simpler way or the harder way, and I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me, and that perhaps in real-world large complex Jframe based classes, there is some benefit to this delaying/queuing strategy?
Depending on your application and how it's being used, it's possible that there could be something that is drawing on the screen (and thus using the EventQueue) before or during the call to your main method. Calls that modify any UI components should be made on the Event Dispatch Thread, and this includes setting the application visible.
So just to be safe, it's a good practice to start your application on the EDT.
Why do this automatically in the code generator here?
It won't hurt, it's easy to generate, and it's considered good practice.
Why should main return quickly and let the application window get created later by the event queue?
It's possible that the main method is being called from some other application that is using the EDT and may have already drawn something on screen. If you draw your application directly in main, it's possible that your application may be altering some component that is in the process of being handled by something on the EDT, and potentially already drawn on the screen.
So just to be safe in case this situation ever happens, you should leave it up to the EDT to draw your application so it can do it when it won't interfere with anything else.
Wouldn't blocking be exactly the point?
Unless something else is calling main other than the JVM process that your user started by double-clicking the desktop icon, it's not going to make a difference when main returns as long as there is something on the screen.
I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me
You're right - most of the time it's probably not gonna make a difference, but I presume they included it because it was easy to generate & implement, it can't hurt, and it would exemplify good practice.
1) why is building Swing GUI inside try-catch-finally, I can't see any reason(s) for that, split create non thread safe GUI and non thread safe code to the separates threads,
2) Swing isn't thread safe, then correct is in all cases that pack() + setVisible(true) would be
last GUI rellated code lines
wrapped into invokeLater
forgot for examples from some code ExamplesDepots, this forum, another forums, sure these code works, but with risk that whatever/everything could happen
correct Swing GUI launch
for example
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
}
});
}
3) is there some Serializable, Custom L&F then (better would be) wrap into invokeAndWait

Java -- For an animation, how should a logic class notify a loosely coupled view to repaint

For an application that repaints frequently, how should the 'model' notify the 'views' that they need to repeatedly repaint one of their components. This:
class AppLogic extends Observable {
void runAnimation() {
while (isAnimationRunning) {
modifyDataStructures();
setChanged();
notifyObservers();
Thread.sleep(25);
}
}
}
class View extends JComponent implements Observer {
void update(Observable o) {
o.getData();
innerPanel.repaint();
}
}
seems like a terrible way to go about animating a panel, especially if the animation is being repainted most of the time that the program is running. Any suggestions? Thanks.
*Ignore the obvious errors in threading and such
Assuming that you are building a kind of "Dashboard" application that updates the information periodically, do what this answer says. If you want something more advanced (like animations for a game) you need more work. Check this article for some interesting tidbits about game programming and animation in Java.
Rather than "running" the business logic, you could use a Swing Timer in the View component and just ask the business model to paint itself, e.g passing the current time as a parameter.

How do I implement a good game menu in Java?

I have been working on a Java game for a while that I started back in my college days. After taking considerable breaks due to my professional career, I'm getting back to it and realizing how awful the code is. I basically had a "monolithic main" with both GUI and game logic in the same class file. What I'm attempting to do, is abstract and "componentize" the GUI into smaller chunks. My executed class extends JFrame which I add and remove panels to/from when buttons are clicked. Ex.
public class GameFrame extends JFrame{
private JPanel[] _panels = {new MainPanel(), new OptionsPanel(), new DifficultyPanel()};
private int _currentPanelIndex = 0;
public GameFrame(){
...
add(_panels[_currentPanelIndex]);
...
}
}
Within each panel class, I have private ActionListeners for the buttons. In MainPanel, I'm getting the singleton GameFrame instance and setting the current panel kind of like:
class SinglePlayerButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
GameFrame instance = GameFrame.getInstance();
JPanel[] panels = instance.getPanels();
int currentPanelIndex = instance.getCurrentPanelIndex();
instance.remove(panels[currentPanelIndex]);
int newPanelIndex;
for(newPanelIndex = 0; newPanelIndex < panels.length; newPanelIndex++){
if(panels[newPanelIndex] instanceof DifficultyPanel){
break;
}
}
instance.add(panels[newPanelIndex]);
}
}
I do not like this deep of coupling in my classes, but I can live with it. However, the real problem is that when I click the last button that takes me into the game, I can't have:
public void actionPerformed(ActionEvent e){
GameFrame.getInstance().startGame();
}
because this will cause my game to run in the Java Event thread, thereby disallowing any other events from being handled. Previously, I had a busy while loop:
...
while(waiting){
//Do nothing
}
remove(_panels[_currentPanelIndex]);
startGame();
...
...
public void actionPerformed(ActionEvent e){
waiting = false;
}
What is the best way to let my GameFrame class know that I've clicked the play button? Can I send an event or message to it from one of its sub-panels telling it to start, and if so, how do I keep the game from running in the Event thread? Should I handle it in the actionPerformed() method and simply spawn a new thread? I would prefer to keep it in the main thread. Thanks.
Go for Slick 2D (a lightweight OpenGL 2D game development framework with lots of cool stuff) or Nifty-GUI.
Slick has also some examples and tutorials and is easy to learn, for example the StateBasedGame can easily be used to implement multiple in-game menus (such as main menu, settings menu, in-game options, in-game pause/resume etc.)
You should have the game logic executing on it's own thread of execution, possibly when the user clicks a button. I don't understand your prior approach with the while(wait) - that would still create problems if your game logic did some time consuming calculation that prevented the even thread from doing updates because the even thread does not stop executing when you call startGame().
EDIT:
It's not clear from the code you pasted that the GUI updates and the game logic are happening on seperate threads of execution - you might want to demonstrate that in your code.

Categories