How to use paint() such that when repaint() is called the previously drawn object should not get deleted when drawing the new object. That is the drawing area must get UPDATED only and not REDRAWN.
In my code when one of many button is clicked, some aplhabet get displayed. I want to have functionality such that when other buttons are clicked the previously drawn alhabets must be present.Take is as if a string of alphabets getting created as the buttons are clicked.
Im using Java Swing for coding.
Some piece of my code:
if(source == btnAlpha[i] )
bollyDraw.repaint(); //bollydraw is an object of a JPanel extended class having implemented the paintComponent(Graphics g) method
In the paint() method:
if (word[i] == key) {
g.drawChars(word, i, 1, x, y);
}
In a project I worked on I used a List to store the objects that were to be drawn as a member of a class. Then as the user interacted with my UI I added/removed items from this list. The JPanel that rendered the items painted the items that were in this list. It's helps separate the UI logic from the paint logic as you can determine what goes into the paint list when an event is fired rather than in the paint method ( which should be as clean as possible ). However this will force you to repaint everything on every paint call.
In conjunction with this Kim's RepaintManager is a great way to limit what gets repainted. It is region based so there is some complexity in determining what region of the screen has changed. If you have the time it is better to use something like this otherwise it could be difficult to add this functionality down the road.
Your app must be prepared to re-paint anything it has painted. From your description, I'm afraid that means you have to keep track of everything you've painted.
The Swing behavior is partially dictated by the underlying window manager and graphical system, which at any time may chose to paint over an area where your application is present. You can override update() to control repaints initiated by your own app, and might be able to improve performance by implementing your own RepaintManager.
This tutorial explains Swing painting in more detail: http://java.sun.com/products/jfc/tsc/articles/painting/
Custom Painting Approaches shows a couple of ways to do this depending on your exact requirement.
Related
I have a problem that I'm not able to understand, none the less solve.
I am making a clone of Asteroids (I call it Meteors, to be clever). Currently I have a class entitled MeteorGame which is the chief class that does the GUI drawing. MeteorGame extends JFrame to make the window, and it has another class that it uses to interpret keyboard events. Everything works great but I need to scale this up. Basically, what I have created is one "level" of the game, and now I need a level manager. I call this class Meteors and I want IT to handle creating the JFrame, rather than MeteorGame.
So to this effect, what I am trying to create is a system where Meteors class is basically a shell that creates a window and instantiates "levels" of MeteorGame in sequence. I have converted my MeteorGame class from JFrame to JPanel, so that my JFrame Meteors class adds JPanel components to itself as the user levels up.
I want each MeteorGame to draw itself and interpret keyboard event entirely autonomously, with the JFrame Meteors class simply working to queue up levels.
Many problems.
Is using the paintComponent() method the only way to draw to a JPanel? The way my old class works is it uses a constant while loop (managed for frame rate) to continuously call the update() and draw() methods that do all the work. So 40 times per second the method draws itself onto the JFrame.
With my updates converting draw() to paintComponent() the frame is drawn only once, and then disappears. I need to find a way to keep redrawing the JPanel continuously. (to eliminate flicker I draw the panel by writing to an image and then drawing the image)
Is there a better way to do all of this? I'm moving from a background in Objective-C iOS development where I am much more familiar with the view hierarchy. I'm sure that what I'm doing is not the most ideal situation by any means.
Also, when I create a JButton in the JFrame class and try to draw it using the following code, nothing happens. What am I doing wrong?
JButton button = new JButton("Close");
button.setLocation(300, 300);
add(button);
"Is using the paintComponent() method the only way to draw to a JPanel?"
Technically, no. But it's the correct way.
"The way my old class works is it uses a constant while loop (managed for frame rate) to continuously call the update() and draw() methods that do all the work"
Don't do this. Instead implement a javax.swing.Timer passing delay to timer, which will determine the frame rate. See more at How to Use Swing Timers
"With my updates converting draw() to paintComponent() the frame is drawn only once, and then disappears."
What you want to do is have a model class, say Asteroid which maintains the state of each Asteroid object. You can then maintain a List<Asteroid> that you can iterate through in the Timer calling each of its method to manipulate its state, then repaint() the panel with every tick of the timer. Then you can can iterate through the List in the paintComponent method, and call each Asteroid's draw method.
"I need to find a way to keep redrawing the JPanel continuously. (to eliminate flicker I draw the panel by writing to an image and then drawing the image)"
It most cases, using the Timer (if used correctly) will help in alleviating the flickering (of course given other factor that I may be unaware of).
"Is there a better way to do all of this?"
Take all the above notes into consideration and have a look at this answer, which takes all those points into consideration, and is also a wannabe asteroid like game/background of a game.
"Also, when I create a JButton in the JFrame class and try to draw it using the following code, nothing happens. What am I doing wrong?"
Can't tell with the bit of code you've provided.
I am using JPanels to simulate a print preview and just printing the content panel, however I have ran into a problem whereby if I try to print multiple panels that are essentially the same document, only the the one currently being displayed on screen will print.
Is there a way I can force the JPanel to repaint even if it is not currently on screen?
I have tried:
Disabling double buffering via:
JComponent.setDoubleBuffered()
RepaintManager.setDoubleBufferingEnabled()
Painting Twice
Painting through paint()
Painting through repaint()
Painting through print()
I couldn't get it to paint off screen and I felt like I was wasting my time battling the Swing API so I just cheated and made the panels display on screen as they are being printed; now I have a new "feature" that shows you the page being printed.
I'll leave the question open incase someone knows how to do this as I would prefer not to shove all the pages in the user's face.
Update
Turns out the problem was with components that had extended java.awt.Container, the Swing components must override certain AWT methods that deal with this sort of rendering.
I am making something that resembles a subtitle player that will go over a video.
I would like to make the background transparent so that the box that the text is in will not interfere with the movie/TV show playing behind it. I have tried 2 ways to do this and each way results in the same problem. The text does not disappear when the next sentence appears. If the background is a color (Eg: Color.red), then this works fine. After a certain time, I call text.setText("next sentence"), but this does not work with a transparent background. The relevant code is as follows. text is a JTextField
I should mention the video is not in this program. This program is ONLY subtitles.
First way:
text.setBackground(new Color(0,0,0,0));
Second way: (using a transparent image)
Graphics c = myPicture.getGraphics();
text.paintAll(c);
I update the text like this.
Thread.sleep(Graphix.subtitles.get(counter).getStart());
text.setText(Graphix.subtitles.get(counter).getText());
This also makes it overlap.
text.setForeground(Color.blue);
text.setBackground(new Color(0,0,0,0));
text.setOpaque(false);
The relevant code from Main is as follows.
final JFrame JFwindow = new JFrame("Subtitles");
JFwindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFwindow.getContentPane().add(new Subtitles());
JFwindow.setSize(1300, 150);
JFwindow.setUndecorated(true);
JFwindow.setBackground(new Color(0,0,0,0f));
JFwindow.pack();
JFwindow.setVisible(true);
Transparency is achieved by calling JPanel#setOpaque and passing it false.
You should NEVER be calling getGraphics. getGraphics and return null and is, at best, only as snap shot. Once the RepaintManager starts a new paint cycle, the results of painting to it will be overridden.
Using a tarnsparent color will only confuse the RepaintManager as it won't know that it needs to paint under the component
Sleeping within the Event Dispatching Thread (EDT) will stop Swing from performing any updates (as well as process any events). Instead I'd recommend using a javax.swing.Timer. See Concurrency in Swing for more details.
If you're using the VLC bindings, then it can't be achieved
Don't forget to make all the parent containers that the sub titles are contained in transparent as well
just working on some code to do with java graphics, very simple example from a lecture I had today. Anyway, the internet seems to say that update will not be called by a System trigger such as resizing a frame etc. In this example, update is called by such a trigger (hence update and paint are called when I only expect paint to be called). He seemed to put it down to Operating Systems and different results on each.
Can anyone clarify this for me?
Working on windows 7
Thanks in advance
Ben
Here's a great article that really says it all:
http://java.sun.com/products/jfc/tsc/articles/painting/
1) Painting in AWT
To understand how AWT's painting API works, helps to know what
triggers a paint operation in a windowing environment. In AWT, there
are two kinds of painting operations: system-triggered painting, and
application-triggered painting.
2) System-triggered Painting
In a system-triggered painting operation, the system requests a
component to render its contents, usually for one of the following
reasons:
The component is first made visible on the screen.
The component is resized.
The component has damage that needs to be repaired. (For example, something that previously obscured the component has moved, and a
previously obscured portion of the component has become exposed).
3) App-triggered Painting
In an application-triggered painting operation, the component decides
it needs to update its contents because its internal state has
changed. (For example,. a button detects that a mouse button has been
pressed and determines that it needs to paint a "depressed" button
visual).
4) The Paint Method
Regardless of how a paint request is triggered, the AWT uses a
"callback" mechanism for painting, and this mechanism is the same for
both heavyweight and lightweight components. This means that a program
should place the component's rendering code inside a particular
overridden method, and the toolkit will invoke this method when it's
time to paint.
I don't want to get called events during the render or update step, but before them. I also don't want to only redraw when an event has occurred, but as soon as possible, so I need a loop in my program.
poll events - call functions to associated listeners
update - may be merged with draw
draw
How can I accomplish this?
I don't really understand your problem, but if you want to draw continuously, then you should make a main loop. This thing cannot be made with swing components, but only if you design an event or use a predefined event. In that event, redraw the whole canvas, using validate() when you add a new component and repaint() or paint() when you just want to update the image.
If you don't want to render continuously then just render when "something" happens, such as when an event triggers.