NTP является определенно способом пойти. В основном "выпустил-забыл", пока Вы позволяете ему брандмауэр на Вашем локальном ведущем устройстве (который обычно является машиной брандмауэра или маршрутизатора.)
Это были основные проблемы с исходным кодом, из-за которых он не работал:
После выполнения вышеизложенного, действительно не имело значения, вызывается ли метод paintComponent или paint, оба, казалось, работают до тех пор, пока Я не забыл вызвать суперконструктор в самом начале.
Эта информация была собрана из того, что написали @jitter, @tackline и @camickr, так что большое спасибо!
PS Не знаю, считается ли ответ на свой вопрос плохим тоном , но поскольку информация, которая мне нужна, была собрана из нескольких ответов, я подумал, что лучший способ - это обновить другие ответы и написать такую сумму.
One of the reasons the paintComponent() doesn't get invoked in the original code is because the component has a "zero size" and the RepaintManger is smart enough not to try and paint something with no size.
The reason the reordering of the code works is because when you add the component to the frame and then make the frame visible the layout manager is invoked to layout the component. By default a frame uses a BorderLayout and by default a component is added to the center of the BorderLayout which happens give all the space available to the component so it gets painted.
However, you change the layout manager of the content pane to be a FlowLayout, you would still have a problem because a FlowLayout respects the preferred size of the component which is zero.
So what you really need to do is assign a preferred size to you your component so layout managers can do their job.
Одна из основных проблем заключается в том, что вы не обновляете компоненты Swing в потоке отправки событий (EDT) . Попробуйте обернуть весь код вашего основного метода следующим образом:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// swing code here...
}
});
Также: добавьте ImageLoadTest к кадру, прежде чем устанавливать его видимым. Это основано на быстром чтении кода - я прочитаю его дальше и посмотрю, что еще найду.
РЕДАКТИРОВАТЬ:
Следуйте моему первоначальному совету выше и упростите свой основной метод, чтобы он выглядел следующим образом и ваш paintComponent () будет вызываться:
public static void main(String args[]) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Empty JFrame");
frame.setSize(new Dimension(1000, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PaintComponentTest ilt = new PaintComponentTest();
frame.add(ilt);
frame.setVisible(true);
ilt.setBackground(Color.BLACK);
}
});
}
Также я бы прочитал об использовании таймеров для выполнения анимации, а также об общей диспетчеризации событий Swing и о том, как / когда переопределять различные методы рисования.
http: // java. sun.com/products/jfc/tsc/articles/painting/
http://java.sun. com / docs / books / tutorial / uiswing / misc / timer.html
http://java.sun.com/docs/books/tutorial/uiswing/concurrency/dispatch.html
To make Tom Hawtin - tackline happy. I rewrote once again
There are several things I changed (check the lines with the //new
comment)
Rewrote it completely
ImageLoadTest.java
) and a file to test it (Tester.java
)Improvements on original posters code
ImageLoadTest
constructor (super()
)setPreferredSize()
of component in constructor. If size isn't set swing of course won't paint your component. preferred size is based on max. width of all images and on sum of all image heightssuper.paintComponent(g)
in overriden paintComponent()
changed paintComponent
to automatically base yOffset
on height of images being drawn
GUI initialization done on EDT
sleep()
to illustrate loading and loading of images could take a long time SwingWorker
's are usedworker
waits then sets new title and then loads imagesworker
in done()
finally adds the component to the JFrame
and displays it. Added component to content pane of JFrame
as described in JFrame api. And as described in javadoc made necessary call to validate()
on JFrame
after calling add()
, as the JFrame
is an already visible container whichs children changed.javdoc citation from
validate()
The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the контейнер был отображен.
JPanel
в качестве базового класса для ImageLoadTest
для исправления setBackground ()
, который мне не удалось заставить работать с JComponent
. Итак, ваши основные проблемы заключаются в том, что вы не установили предпочтительный размер компонента и не вызывали validate ()
в JFrame
после добавления чего-либо в уже видимый контейнер.
Это должно работать
jpanelpaint / ImageLoadTest.java
package jpanelpaint;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
import java.util.List;
public class ImageLoadTest extends JPanel {
private List<Image> list;
public ImageLoadTest() {
super();
}
public ImageLoadTest(List<Image> list) {
this();
this.list = list;
int height = 0;
int width = 0;
for (Image img : list) {
height += img.getHeight(this);
width = img.getWidth(this) > width ? img.getWidth(this) : width;
setPreferredSize(new Dimension(width, height));
}
}
@Override
protected void paintComponent(Graphics g) {
int yOffset=0;
super.paintComponent(g);
System.err.println("ImageLoadTest.paintComponent()");
for(Image img : list) {
g.drawImage(img, 0, yOffset, null);
yOffset+=img.getHeight(this);
}
}
}
Tester.java
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.SwingUtilities;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import jpanelpaint.ImageLoadTest;
public class Tester {
private JFrame frame;
private ImageLoadTest ilt;
private final int NUMBEROFFILES = 4;
private List<Image> list;
//will load the images
SwingWorker worker = new SwingWorker<List<Image>, Void>() {
@Override
public List<Image> doInBackground() throws InterruptedException {
//sleep at start so user is able to see empty jframe
Thread.sleep(1000);
//let Event-Dispatch-Thread (EDT) handle this
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setTitle("Loading images");
}
});
//sleep again so user is able to see loading has started
Thread.sleep(1000);
//loads the images and returns list<image>
return loadImages();
}
@Override
public void done() {
//this is run on the EDT anyway
try {
//get result from doInBackground
list = get();
frame.setTitle("Done loading images");
ilt = new ImageLoadTest(list);
frame.getContentPane().add(ilt);
frame.getContentPane().validate();
//start second worker of background stuff
worker2.execute();
} catch (InterruptedException ignore) {}
catch (ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
//just delay a little then set background
SwingWorker worker2 = new SwingWorker<Object, Void>() {
@Override
public List<Image> doInBackground() throws InterruptedException {
Thread.sleep(1000);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setTitle("Setting background");
}
});
Thread.sleep(1000);
return null;
}
@Override
public void done() {
ilt.setBackground(Color.BLACK);
frame.setTitle("Done!");
}
};
public static void main(String args[]) {
new Tester();
}
public Tester() {
//setupGUI
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame = new JFrame("Empty JFrame");
frame.setSize(new Dimension(1000, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
//start the swingworker which loads the images
worker.execute();
}
//create image names
private String[] createImageFileNames(int count){
String[] fileNames = new String[count];
for(int i=0; i < count; i++)
fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp";
return fileNames;
}
//load images
private List<Image> loadImages() {
List<Image> tmpA = new ArrayList<Image>();
try {
for(String name : createImageFileNames(NUMBEROFFILES)){
System.err.println(name);
tmpA.add(ImageIO.read(new File(name)));
}
} catch (IOException e) { }
return tmpA;
}
}
Я рекомендую прочитать первую пару глав «Filthy Rich Clients». Я использовал Swing в течение многих лет, но только после прочтения этой книги я наконец полностью понял, как работает механизм рисования в Java.