Event Handling Neu zeichnen nur wenn Berechnung fertig ist

Ich habe ein Programm mit drei Klassen (siehe Code)
In Test finden langwierige Berechnungen statt, deren Ergebnisse graphisch dargestellt werden sollen.
(Statt der langen Berechnungen habe ich hier nur "sleep(1000)" geschrieben)
Ich möchte, dass die Graphik nicht alle 20 Millisekunden neu gezeichnet wird (wie es durch "Timer...ActionListener...ActionEvent...repaint" geschehen würde), sondern immer nur, wenn eine Berechnung abgeschlossen ist. Das ist mir wahrscheinlich auch gelungen, aber sehr umständlich.
Kann mir jemand erklären, wie es elegant geht?

[CODE lang="java" title="Klasse: Test"]public class Test {

static int i;

public static void main(String[] args) {
new Window();
for (i=1; i<6; i++) {sleep(1000);}
}

private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignored) {
}
}
}[/CODE]

[CODE lang="java" title="Klasse: Window"]import javax.swing.JFrame;

public class Window extends JFrame{
private final Panel Pan;

public Window() {
this.Pan = new Panel();
add(Pan);
pack();
setVisible(true);
}
}[/CODE]

[CODE lang="java" title="Klasse: Panel"]import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Panel extends JPanel {

private final Dimension prefSize = new Dimension(200, 300);
private Timer t;
int j;
public Panel() {

setPreferredSize(prefSize);


t = new Timer(20, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {repaint();}
}
);
j=Test.i;
t.start();
}

@Override
public void paint(Graphics g)
{
if (Test.i!=j) {
g.drawLine(50, 50+Test.i*20, 100, 100);
j=Test.i;
}
}
}[/CODE]

Danke
 
Du lagerst die langwierige Berechnung in einen eigenen Thread aus und wenn sie fertig ist, rufst Du repaint() auf. Das kannst Du direkt per Thread machen, per ExecutorService oder auch per SwingWorker. Letzterer erleichtert die Zusammenarbeit mit dem UI ein wenig.
 
[CODE lang="java" title="TestDurationCalc"]public class TestDurationCalc {

public static void main(String[] args) {
JFrame frame = new JFrame("Duration calc");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CalcPanel(600, 400));
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}

}[/CODE]
[CODE lang="java" title="CalcPanel" highlight="36-37, 62-66, 12"]import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JList;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class CalcPanel extends JPanel implements DurationCalulationListener {
private JTextField[] input = new JTextField[3];
private final static int K = 0;
private final static int X = 1;
private final static int D = 2;
private DefaultListModel<String> model = new DefaultListModel<>();
private JList<String> list = new JList<String>(model);
private JButton ok = new JButton("ok");

public CalcPanel(int width, int height) {
setPreferredSize(new Dimension(width, height));
add(list);
int w = (int) ((width - width / 2) * .9) / 4;
for (int i = 0; i < input.length; i++) {
input = new JTextField();
input.setPreferredSize(new Dimension(w, 30));
input.setPreferredSize(new Dimension(w, 30));
add(input);
}
list.setPreferredSize(new Dimension(width / 2, height));
add(ok);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LineCalc calc = getCalculation();
calc.calculate();
}

});

}

private LineCalc getCalculation() {
return new LineCalc(this, getParam());
}

private double[] getParam() {
double[] param = new double[3];
for (int i = 0; i < input.length; i++) {
try {
param = Double.parseDouble(input.getText());
} catch (NumberFormatException e) {
input.setText("0");
param = 0;
}
}
return param;
}

@Override
public void update(Object sender, double[] param, double[] result) {
model.addElement(result[0] + " = " + param[K] + "x" + param[X] + "+" + param[D]);
list.setSelectedIndex(model.getSize() - 1);
list.repaint();
}
}[/CODE]
[CODE lang="java" title="Listener Interface"]public interface DurationCalulationListener {
public void update(Object sender, double[] param, double[] result);
}[/CODE]
Java:
public abstract class DurationCalculation implements Runnable {
    private DurationCalulationListener listener;
    /**
     * Vector for results.
     */
    protected double[] param;
    protected double[] result;

    public DurationCalculation(DurationCalulationListener listener, double[] param) {
        if (listener == null)
            throw new IllegalArgumentException("Listener null not allowes!");
        this.listener = listener;
        this.param = param;
    }

    public void calculate() {
        (new Thread(this)).start();
    }

    /**
     * Do calculation here. Use {@link #result} and {@link #param}.
     */
    protected abstract void doCalculation();

    @Override
    public final void run() {
        doCalculation();
        listener.update(this, param, result);
    }

}
[CODE lang="java" title="Geradengleichung" highlight="16-23, 9"]public class LineCalc extends DurationCalculation {

private final static int K = 0;
private final static int X = 1;
private final static int D = 2;

public LineCalc(DurationCalulationListener listener, double... param) {
super(listener, param);
result = new double[1]; // y = k*x+d
}

/**
* Calculates y of a line by given parameters. y = k*x+d
*/
@Override
protected void doCalculation() {
result[0] = param[K] * param[X] + param[D];
try { // delay simulates long time calculation
Thread.sleep(2000, 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}[/CODE]
 
Danke für die schnellen Antworten.
Leider habe ich (Anfänger im objektorientierten Programmieren) beide nicht verstanden.
Ich denke, dass ich mich mal mit zugleich ablaufenden Threads befassen sollte.
Kann mir jemand ein Tutorial dazu empfehlen?
 

Neue Themen


Zurück
Oben