Перемещение синусоиды в графическом интерфейсе Swing/AWT
Я использовал двусвязные списки для создания этой движущейся синусоиды (код может быть крайне примитивным и неорганизованным, но это только первый черновик, и я едва знаю, как использовать Swing..):
import java.awt.*;
import javax.swing.JFrame;
public class DisplayGraphics extends Canvas{
public void paint(Graphics g) {
setForeground(Color.RED);
this.setSize(720,440);
class list {
int pos;
list next;
list prev;
list(){
int pos;
list next ;
list prev;
}
list(int pos){
this.pos = pos;
}
list(int pos, list next){
this.pos = pos;
this.next = next;
}
public void setpos(int pos){
this.pos= pos;
}
public void setnext(list next){
this.next= next;
next.prev=this;
}
public void display(list head){
list tracker = head;
int y;
//displays the sincurve momentarily
for (int i = 1;i<721; i++){
y = (int)(Math.sin(Math.toRadians(tracker.pos))*200)+200;
g.fillOval(i,y,3,3);
tracker = tracker.next;
}
}
}
list temp = new list();
temp.setpos(1);
list head = temp;
for (int i =2; i<720; i++){
list thing = new list();
thing.setpos(i);
temp.setnext(thing);
temp = thing;
}
list tail = new list(720);
temp.setnext(tail);
tail.setnext(head);
//creates the moving display
boolean run = true;
while(run==true){
head.display(head);
//try {
//Thread.sleep(10);
//} catch(InterruptedException ex) {
// Thread.currentThread().interrupt();
//}
g.clearRect(0, 0, getWidth(), getHeight());
head = head.next ;
}
}
public static void main(String[] args) {
DisplayGraphics m=new DisplayGraphics();
JFrame f=new JFrame();
f.add(m);
f.setSize(720,400);
//f.setLayout(null);
f.setVisible(true);
}
}
Тем не менее, программа работает не очень гладко. Есть ли предложения, чтобы он работал быстрее и плавнее?
2 ответа
public class DisplayGraphics extends Canvas{
Не смешивайте Swing и AWT. Компоненты Swing (все, что является JComponent
) по умолчанию с двойной буферизацией. Это помогает избежать рваного рендеринга.
public void paint(Graphics g) {
setForeground(Color.RED);
Всякий раз, когда мы перезаписываем любой метод рисования, мы должны немедленно вызывать супер метод, чтобы стереть исходный рисунок. Но для свинга мы бы переопределили paintComponent(Graphics)
вместо paint(Graphics)
,
Установка цвета переднего плана должна быть сделана в конструкторе один раз, затем оставлена в покое. Повторный вызов вызывает краску!
this.setSize(720,440);
И это еще одна вещь, которая вызовет перекрас!
Далее лучше переопределить размер getPreferredSize()
метод и pack()
окно верхнего уровня, в котором оно содержится. Какую бы информацию, сайт, книгу вы использовали, найдите новую и лучшую версию. Этот код показывает плохие практики во многих важных частях.
Есть ли предложения, чтобы он работал быстрее и плавнее?
Используйте компонент Swing (например, JPanel
) вместо Canvas
, Внесите изменения и переопределите методы, упомянутые выше. Создать качели Timer
что вызывает repaint()
в части цикла.
См. Выполнение пользовательской рисования и Как использовать Swing Timers для улучшения учебных ресурсов.
Хорошо, есть некоторые недостатки, которые нужно исправить ^^
1) вызвать вашу картину через темы
//set isRunning=false to stop repaint
private boolean isRunning = true;
private void startUpdateThread(){
Runnable r = new Runnable() {
public void run() {
while(isRunning){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//repaint calls the paint(Graphics g)-method
repaint();
}
}
};
Thread t = new Thread(r);
t.setDaemon(true);
t.start();
}
2) не усложняйте ситуацию: просто вычислите f(x)=y во время рисования ^^
3) делать только то, что нужно, в краске: не устанавливайте размер каждый раз, когда рисуете
private int xCount = 0;
public void paint(Graphics g) {
//setSize(...)
xCount = xCount + 1;
for (int dx = 1; dx < 721; dx++) {
int x = (xCount%721)+dx;
int y = (int) (Math.sin(Math.toRadians(x)) * 200) + 200;
g.fillOval(dx, y, 3, 3);
}
}
что осталось? ваши настройки ^^
public static void main(String[] args) {
DisplayGraphic m = new DisplayGraphic();
m.startUpdateThread();
m.setSize(720, 440);
JFrame f = new JFrame();
f.add(m);
f.setSize(720, 400);
f.setVisible(true);
}
Возможно, вы захотите взглянуть на буферизацию... если вам не нравится это делать, просто используйте JPanel
вместо холста (вам придется перезаписать paintComponent(Graphics g)
вместо paint(Graphics g)
)
public class DisplayGraphic extends JPanel {
private int xCount = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
//...
//same as paint in above
}
}
}