#java #swing #graphics #inner-classes
#java #swing #графика #внутренние классы
Вопрос:
Это часть моего кода, которая выполняет какую-то анимацию; однако, кажется, что-то не так: всякий раз, когда я пытаюсь использовать переданный ‘g’ изнутри анонимного класса для рисования чего-либо, это ничего не дает, но когда я использовал его вне анонимного класса (внутри метода rollBalls), он делает то, что должен делать. Есть идеи, почему? И как мне это исправить? Спасибо.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
rollBalls(g);
}
private void rollBalls(final Graphics g) { //Roll all 3 balls on the bar
new Timer(1, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
g.setColor(Color.red);
g.fillRect(0, 0, 500, 500);
}
}).start();
}
Комментарии:
1. Почему вы пытаетесь изменить состояние
final
объектаg
?2.
final
требуется для того,g
чтобы быть доступным изнутри анонимного класса.
Ответ №1:
Ваша проблема заключается в нескольких аспектах, но в первую очередь вы понимаете, что графический объект, переданный в метод paint или paintComponent, обычно не сохраняется и может быть удален после завершения метода. Далее у вас есть программная логика, вызываемая из метода paintComponent, который никогда не должен выполняться. У вас нет полного контроля над тем, когда или даже вызываются ли методы paint или paintComponent, и, следовательно, они не должны диктовать логику вашего приложения.
По этой причине вы не делаете Swing graphics таким образом. Вместо этого установите таймер вне любого метода paintComponent, попросите его обновить поля класса, затем вызовите repaint(), и пусть ваш paintComponent использует эти поля класса для рисования по мере необходимости, и на этот раз с стабильным графическим объектом, который передается в него через его параметры.
Я понимаю, что ваш код — это «всего лишь образец», но вы делаете что-то неправильно, пытаясь нарисовать непосредственно из actionPerformed. Вы просто не должны этого делать.
Ответ №2:
Я согласен с комментарием судна на воздушной подушке, Полного Угрей. вы должны сделать что-то вроде этого
class MyClass extends JComponent{
MyClass(){
new Timer(1, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MyClass.this.repaint();
}
}).start();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, 500, 500);
}
Комментарии:
1. Я знаю, что могу это сделать; однако мне нужно нарисовать изнутри выполненного действия. Этот код является всего лишь образцом.
2. Приведенный выше код, по сути, делает это.
repaint()
внутренниеactionPerformed()
вызовыpaintComponent()
в соответствии с вашим определениемTimer
.
Ответ №3:
Возможно, вы работаете не в том потоке для обновления графического интерфейса? Попробуйте поместить команды рисования из анонимного класса в Runnable и передать это SwingUtilities.invokeLater.
Я не думаю, что это имеет какое-либо отношение к внутренней классности.
Комментарии:
1. Это не имеет ничего общего с потоковой обработкой, поскольку, во-первых, весь код в actionPerformed вызывается в EDT.