repaint is not calling paintComponent - java

Repaint is not calling PaintComponent.
I tried to call it from another method of the Try class too but it did not work out.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class Try extends JPanel {
int i =0;
#Override
public void paintComponent(Graphics g){
//super.paintComponent(g);
System.out.println("hey");
}
public static void main(String[] args) {
JFrame f=new JFrame();
Try t = new Try();
f.setSize(500,600);//400 width and 500 height
Container contentPane = f.getContentPane();
contentPane.add(new PaintComponent());
f.setVisible(true);//making the frame visible
while(true){
t.repaint();
}
}
}

There are multiple issues some of which are mentioned by #trashgod in comments.
You are calling repaint on the instance which you did NOT add to the content pane - you have a different one there (actually, you have something completely different there - new PaintComponent()).
Do not remove super.paintComponent ( g ); unless you clean up the area on your own (pretty much fill the whole component background if it is opaque), otherwise you will get visual glitches on such components upon repaint.
You are spamming repaint operations which is extremely bad, make at least some delay between the repaints giving Swing time to perform the repaints. The best case is if you repaint component only when it actually will display something different visually. If you need to update the view all the time - at least limit it to 30-60 frames (repaints) per second. Also, some internal Swing optimizations might "eat" some of the repaint calls, so expect that you might not see as many paintComponent calls as a number of repaints you call on the component.
You are working with Swing components outside of Event Dispatch Thread (shortly EDT) which might cause issues. Make sure you always use it to create Swing components and call any methods on them. SwingUtilities helps with that.
Any heavy operations that take a long time (or unknown time) to be completed should be executed outside of EDT, otherwise, your UI will simply hang while you are waiting for that operation to complete because all UI updates are performed on EDT and not anywhere else.
Considering all I said above, this is how your example should look like:
public class Try extends JPanel
{
#Override
public void paintComponent ( final Graphics g )
{
super.paintComponent ( g );
final Graphics2D g2d = ( Graphics2D ) g;
g2d.drawString ( Long.toString ( System.currentTimeMillis () ), 25, 35 );
System.out.println ( "repainted" );
}
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
#Override
public void run ()
{
final JFrame f = new JFrame ();
final Try t = new Try ();
f.getContentPane ().add ( t );
f.setSize ( 500, 600 );
f.setVisible ( true );
new Thread ( new Runnable ()
{
#Override
public void run ()
{
try
{
while ( true )
{
t.repaint ();
Thread.sleep ( 25 );
}
}
catch ( final InterruptedException e )
{
//
}
}
} ).start ();
}
} );
}
}
Hope that clarifies it a bit for you.
There is also SwingWorker class that helps to perform long-running tasks in Swing, but I didn't use it here to keep the example as simple as possible.
Also a side note - you do not need to call repaint () within EDT because it sends the repaint request to EDT on its own, so that method is safe to use on any thread (like I do in the example).

Related

JLabel's Set Location inside for not moving smoothly

i'm using a label for a little sprite for some testing that i'm doing, but i want to move the sprite 10 pixels per keypress. Now, i can do that, but now i'm trying to make it move the 10 pixels smoothly, so i tried the next code:
for(int i = 0; i < 100; i++){
x++;
container.setLocation(x, y);
System.out.println(x);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Now the problem is that, the sprite only moves when the for cycle ends, but the console shows the X value changing for each iteration. Any thoughts/help?
Thanks!
I suggest you to take a look at how to animate a JComponent using Swing Timer class, instead of for loop. You can find various tutorials about how to use Swing Timer. Here, to briefly explain, you are blocking EDT(Event Dispatch Thread) which operates the graphical side of the Java. Whenever you want to make a constant and smooth flow in your animations, make sure that you never block the EDT.
EDIT: Here is the demonstration of the usage of Swing Timer Class:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class AnimationTrial extends JFrame {
private final int DELAY = 10;
private Timer timer;
private int x, y;
private JLabel label;
public static void main(String[] args) {
EventQueue.invokeLater( new Runnable () {
#Override
public void run() {
new AnimationTrial();
}
});
}
public AnimationTrial()
{
setSize(500, 500);
x = 50;
y = 50;
label = new JLabel("They see me movin' they hatin'!");
timer = new Timer( DELAY, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0) {
x++;
label.setLocation(x, y);
}
});
timer.start();
getContentPane().add(label);
pack();
setVisible (true);
}
}
If you dont create new Thread, the user interface runs on the same thread as its method.
Therefore your for-cycle is fired after some action and thread cant do anything else until it ends.
Solution : Create your own class, pass the JLabel or the whole form as parameter in constructor, implement threading and run it as new thread.
I'd suggest you give a look to the Timing Framework, if you want to do something close to an animation in Swing. It could help you, depending on your general need.
If you want other sprites to move in sync with your sprite you can create a TimerTask and use scheduleAtFixedRate(). Your TimerTask would then be responsible for moving all sprites and redrawing everything that was part of the moving like the JPanel in the background and the sprites.
To make your code snippet work you would have to add redrawing of the Background and the sprite after setting the location but I would advise against that approach as it can easily lead to badly designed code where you create one God Class that does everything.
The TimerTask approach should also be more precise if the calculations need a bit time as it tries to have the same time between 2 calls where the approach with the sleeping thread can easily lead to different delays if the calculations are finished earlier or later.

How can I make a jslider actually affect things as it slides?

I have set up an area where a jslider should alter the delay of some dots in a jpanel here
JSlider source = (JSlider)e.getSource();
if (source == speedSlider) {
if (source.getValueIsAdjusting()) {
GraphicsDisplay.delay += 100000;
}
}
The delay is put into affect by the following
public static boolean stop = true ;
public static long delay = 3000000 ;
public void paint ( Graphics g2 ) {
//code making dots up here...
int a;
if ( !stop ) {
for ( a=0; a<delay; a++ ) ;
moveDot ( ) ;
}
repaint();
}
I can't get the slider to do anything. And I know it has something to do with
if (source.getValueIsAdjusting()) {
GraphicsDisplay.delay += 100000;
}
The problem isn't with the slider, it's with your painting...
Basically, you are blocking the Event Dispatching Thread, preventing it from actually painting...
public void paint ( Graphics g2 ) {
// Let's ignore the fact that you haven't called super.paint here...
//code making dots up here...
int a;
if ( !stop ) {
// Block the EDT, stop all painting and event processing until this for
// exist...
for ( a=0; a<delay; a++ ) ;
moveDot ( ) ;
}
// This is a very bad idea inside any paint method...
repaint();
}
Basically, what's happening, is the RepaintManager is consolidating most of your repaint requests down to as few events as possible, in order to maintain performance. So while you "block" the EDT, you paint requests are been queued, but not processed, the repaint manager is making decisions that may also consolidate those requests down to a few events in order to maintain performance.
A better solution would be to use a Swing Timer. See How to Use Swing Timers
private javax.swing.Timer timer;
//...
timer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
moveDot();
repaint();
}
});
timer.start();
//...
if (source.getValueIsAdjusting()) {
timer.stop();
timer.setDelay(source.getValue());
timer.start();
}
Your use of static variables is also a little scary...
ps- I forgot to mention, you should avoid overriding paint and instead use paintComponent, making sure you call super.paintComponent first...See Perfoming Custom Painting

Java Swing - mouseMoved event is fired slowly

Currently I am experiencing issues with the mouseMoved event in Java - Swing. Briefly, I have got a JPanel and I have attached MouseMotionListener to it, in order to hide or show JscrollPane on the fly:
myPanel.addMouseMotionListener(new MousePresenter());
I have got my own class that implements MouseMotionListener interface:
public class MousePresenter implements MouseMotionListener {
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (x>20 && x<200) {
hideScrollBar();
}
else {
showScrollBar();
}
}
}
The issue is that the mouseMoved event is not being fired often enough. Is there any related solution to this issue whilst using MouseMotionListener?
Thank you for your time.
The following seems to work just fine for me. Note that the handling of the event is rather fast:
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame( "TestFrame" );
JPanel content = new JPanel( new BorderLayout() );
final JLabel mousePosition = new JLabel( "Unknown" );
content.add( mousePosition, BorderLayout.NORTH );
content.addMouseMotionListener( new MouseMotionAdapter() {
#Override
public void mouseMoved( MouseEvent e ) {
mousePosition.setText( "X: " + e.getX() + " Y: " + e.getY() );
}
} );
frame.setContentPane( content );
frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
} );
}
That might not be the case for your hideScrollBar method
A mouse moved event is inherently slowly since it's fired on every pixel change.
The only thing you can do to optimize the whole issue is to optimize what you do inside the callback handler. In your case you do have
if (something)
doA();
else
doB();
This means that in any case you are either trying to show or to hide the scrollbar even when it's already shown or hidden. What you can do is:
if (scrollBarIsVisible && x>20 && x<200) {
hideScrollBar();
scrollBarIsVisible = false;
}
else if (!scrollBarIsVisible) {
showScrollBar();
scrollBarIsVisible = true;
}
So that you only modify the visibility of the element (which can be a heavy operation since it may require to relayout things) when switching from inside the bounds to outside and viceversa. This should lower the computational operations by a lot.
If you all your code is being executed in the Event Dispatch thread it could be causing problems. Have a look at this trail and try to put any code that does a lot of work in a SwingWorker thread.
Your code is not very well optimized. As it is, it will always call either the show or hide Scrollbar methods. You should probably modify it such as it hides it only if visible and it displays it only if hidden.
Problem solved. There was certain performance issue in my app that caused such delays.
Thank you for your effort and piece of information and advice you provided.

why calling repaint in this code?

if you add a jpanel instance to the content pane, the paintComponent method is called, right?
content_pane.add (fDrawingPanel);
so why would you call "repaint" at the first line in the run() method? (it says "to paint the loading message, but it should already be painted, because paintComponent was called before, and once fShow is true, we don't set it back to false, so this code is, i think, supposed to be called once ) :
public class MediaTrackApplet extends JApplet
implements Runnable
{
// Need a reference to the panel for the
// thread loop.
DrawingPanel fDrawingPanel;
// Parameters to track the image
MediaTracker fTracker;
Image fImg;
int fImageNum = 0;
boolean fShow = false;
String fMessage ="Loading...";
/** Use a MediaTracker to load an image.**/
public void init () {
Container content_pane = getContentPane ();
// Create an instance of DrawingPanel
fDrawingPanel = new DrawingPanel (this);
// Add the DrawingPanel to the contentPane.
content_pane.add (fDrawingPanel);
// Get image and monitor its loading.
fImg = getImage (getCodeBase (), "m20.gif.jpg" );
fTracker = new MediaTracker (this);
// Pass the image reference and an ID number.
fTracker.addImage (fImg, fImageNum);
} // init
/** If the image not yet loaded, run the thread
* so the run() will monitor the image loading.
**/
public void start () {
if (!fTracker.checkID (fImageNum) ) {
Thread thread = new Thread (this);
thread.start ();
} else
// Unloading/reloading web page can will leave
// checkID true but fShow will be false.
fShow = true;
} // start
/** Use a thread to wait for the image to load
* before painting it.
**/
public void run () {
// Paint the loading message
repaint ();
// The wait for the image to finish loading
try {
fTracker.waitForID (fImageNum );
} catch (InterruptedException e) {}
// Check if there was a loading error
if (fTracker.isErrorID (fImageNum ))
fMessage= "Error";
else
fShow = true;
// Repaint with the image now if it loaded OK
repaint ();
} // run
}// class MediaTrackApplet
/** This JPanel subclass draws an image on the panel if
* the image is loaded. Otherwise, it draws a text message.
**/
class DrawingPanel extends JPanel {
MediaTrackApplet parent = null;
DrawingPanel (MediaTrackApplet parent) {
this.parent = parent;
}// ctor
public void paintComponent (Graphics g) {
super.paintComponent (g);
// Add your drawing instructions here
if (parent.fShow)
g.drawImage (parent.fImg,10,10,this);
else
g.drawString (parent.fMessage, 10,10);
} // paintComponent
} // class DrawingPanel
Thanks
Are you referring to the EDT?
Yes. This venerable, but superannuated, example hails from an era that predates our modern understanding that Swing GUI objects should be constructed and manipulated only on the event dispatch thread. The initial invocation of repaint() has the effect of posting a new Runnable on the EventQueue, while allowing the background thread to finish loading images in anticipation of the subsequent repaint(). See also Memory Consistency Properties and this related example.

paintComponent not being called at the right time

I'm trying to write an app that goes something like this:
- Display a dialog
- When user clicks OK, close dialog, go to main app
Here are the relevant code snippets:
public class Owari extends JPanel implements ActionListener, MouseListener, Runnable {
// FIELDS
JFrame frame;
JTextField IP;
String IPAddress;
static final int SERVER_MODE = 0;
static final int CLIENT_MODE = 1;
int mode;
OwariBoard board;
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Owari() );
}
Owari() {
setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
board = new OwariBoard();
}
void main() {
this.addMouseListener( this );
frame.dispose();
frame = new JFrame( "Owari" );
frame.setContentPane( this );
frame.pack();
frame.setVisible(true);
if ( mode == SERVER_MODE ) {
server();
}
if ( mode == CLIENT_MODE ) {
client();
}
}
public void run() {
frame = new JFrame( "Owari" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JPanel init = new JPanel( new GridBagLayout() );
frame.setContentPane( init );
add some components to the init panel including a button with
this as its actionListener and OK as its command.
frame.pack();
frame.setVisible( true );
}
public void actionPerformed( ActionEvent e ) {
if ( e.getActionCommand().equals( "Client" ) ) {
mode = CLIENT_MODE;
IP.setVisible( true );
}
else if ( e.getActionCommand().equals( "Server" ) ) {
mode = SERVER_MODE;
IP.setVisible( false );
}
else {
IPAddress = IP.getText();
main();
}
}
public void paintComponent( Graphics g ) {
super.paintComponent( g );
System.out.println( "painting" );
do some paintin
}
void server() {
frame.setTitle( "Owari Server" );
try {
server = new ServerSocket( 666 );
socket = server.accept();
initIO();
} catch ( IOException e ) {}
yourTurn = true;
System.out.println( "Got to end of server()" ); // At this point, the window
DOES get painted
What happens is the following:
The initial dialog displays:
I click the OK button.
The main window gets resized to the preferred size of the main app but it doesn't get painted, it's just transparent (shown here with this page as the background, heh):
http://imgur.com/6Ssij.jpg
I can tell the paintComponent method hasn't been called because "painting" isn't printed to the console.
However, "got to this point in the program" DOES get printed, so the program isn't hanging, it's just not calling paintComponent.
Then when I launch a client and connect, the app finally gets painted, and "painting" and "got a client" get printed to the console.
Also later on in the app, calls to repaint() are delayed (ie paintComponent is actually called later in the program than when the call to repaint() is made).
I also tried replacing the initial dialog using sthing along the lines of
public void main
frame.getRootPane.removeAll()
frame.setContentPane(this)
frame.getRootPane().revalidate()
frame.pack()
Exact same result.
tl;dr paintcomponent isn't being called when i want it to, what do?
Bumping for some more info: the call to repaint() is done before the call to sever.accept() So why does it not repaint() before hanging at the server.accept() call?
openasocketandwaitforaclient
Your code is executing in the Event Dispatch Thread so the blocking socket is preventing the GUI from repainting itself.
YOu need to use a separate Thread for the socket. Read the section from the Swing tutorial on Concurrency for an explanation and a solution.
your code seems to work so, maybe you should try to invoke the repaint() methode of you frame after resizing this frame.
Anhuin

Categories

Resources