Я поместил объект JPanel внутрь JScrollPane, и прокрутка работает, как и ожидалось. Переопределяя paintComponent(), я попытался выполнить пользовательское рисование в объекте JPanel. Однако, когда объект JPanel помещается в JScrollPane, JPanel больше не рисует должным образом (вместо этого показывает только цвет фона).
Поскольку мое приложение требует постоянного обновления JPanel, создается отдельный поток для перерисовки JPanel с определенным интервалом.
Следующие фрагменты кода показывают мой текущий проект:
a) paintComponent() из моей JPanel (этот метод был сокращен только до рисования, фактическая краска будет постоянно обновляться BufferedImage, поставляемым из другого потока, вместо этого большого розового статического поля):
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//Render Frame
// 'RXDisplayCanvas' is the JPanel.
Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics();
G2D.setColor(Color.PINK);
//800 and 600 are arbitrary values for this example, real values are calculated at runtime. The value calculation code is verified to work (as its used elsewhere in a similar scenario)
G2D.fillRect(0, 0, 800, 600);
G2D.dispose();
}
б) Поток 'updater', который периодически перерисовывает кадр:
@Override
public void run() {
long MaxFrameTime;
long Time;
while(isVisible()){
// 'FPSLimit' is a integer value (default to 30)
MaxFrameTime = Math.round(1000000000.0 / FPSLimit);
Time = System.nanoTime();
try{
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run() {
// 'RXDisplayCanvas' is the JPanel.
RXDisplayCanvas.repaint(); //When using this, the JPanel does not display correctly.
//RXDisplayCanvas.paintImmediately(0, 0, RXDisplayCanvas.getWidth(), RXDisplayCanvas.getHeight()); When using this, the JPanel renders correctly but flickers.
}
});
}catch(InterruptedException | InvocationTargetException e){}
Time = System.nanoTime() - Time;
if(Time < MaxFrameTime){
try{
Thread.sleep(Math.round((MaxFrameTime - Time)/1000000.0));
}catch(InterruptedException ex){}
}
}
}
Я принял во внимание, что repaint() не вызывает немедленной перерисовки экрана, а проблема заключается в неправильном рендеринге экрана. Когда программа остается одна, она просто отображает цвет фона JPanel до тех пор, пока JScrollPane не будет прокручен, в котором он правильно отображает один кадр, прежде чем следующий вызов repaint() рисует неправильное отображение.
При переключении repaint() на paintImmediately() (в отрывке b) кадр отображался правильно, но присутствовало сильное мерцание, когда он постоянно чередовался между отрисовкой цвета фона и отрисовкой розового прямоугольника. Я пытался добавлять и удалять менеджеры компоновки, отключать менеджер перерисовки, а также включать и отключать флаг «двойной буферизации» для обоих компонентов, в которых все приводило к одному из двух вариантов поведения, упомянутых выше (рендеринг только фона или мерцание).
Может ли кто-нибудь помочь мне в этом вопросе?
NB: Я хорошо осведомлен о соглашении об именах переменных в Java, так как это частный проект, я решил начинать имена переменных с заглавных букв, потому что я думаю, что это выглядит лучше, пожалуйста, не оставляйте комментарии по этому поводу.