Mittwoch, 13. Januar 2010

 

Ringbuffer Simulation

Sie finden unter ringbuffer.jar eine Simulation eines Ringbuffers (bzw. Queue).


Aufrufen mit
java -jar ringbuffer.jar


Hier noch ein paar Worte zur Implementierung. Die Klasse Queue ist ganz herkömmlich implementiert. Bei einem Über- bzw. Unterlauf wird eine IndexOutOfBoundsException geworfen. Die Felder der Klasse wurden ohne private definiert, damit die Klasse GraphView im selben Paket direkt darauf zugreifen kann (erspart Schreibarbeit...).
package queuegraph;

/**
* Ringbuffer.
*
* @author Harald R. Haberstroh (hp)
*
*/
public class Ringbuffer {
String[] ring;
int usedSize = 0;
int size = 0;
int getIndex = 0;
int putIndex = 0;
final static int DEFAULTSIZE = 12;

public Ringbuffer(int size) {
this.size = size;
ring = new String[this.size];
}

public Ringbuffer() {
this(DEFAULTSIZE);
}

public void put(String c) throws IndexOutOfBoundsException {
usedSize++;
if (usedSize > size) {
throw new IndexOutOfBoundsException("Ringbufferüberlauf");
}
ring[putIndex] = c;
putIndex = (putIndex + 1) % size;
}

public String get() throws IndexOutOfBoundsException {
usedSize--;
if (usedSize < 0) {
throw new IndexOutOfBoundsException("Ringbuffer schon leer");
}
String ret = ring[getIndex];
getIndex = (getIndex + 1) % size;
return ret;
}

public int getSize() {
return size;
}

public boolean isEmpty() {
return usedSize == 0;
}
}

Die Klasse GraphView erweitert ein JPanel und "zeichnet" das Array mit Inhalt. Zusätzlich werden die "Zeiger" getIndex und putIndex durch die Position dargestellt.

Bei einem Über- bzw. Unterlauf wird der Fehler angezeigt und die Funktion "deaktiviert", indem put() und get() immer prüfen, ob error == null (also kein Fehler gesetzt ist).

Das Fenster wird in main() aufgebaut.

package queuegraph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
* graphische Darstellung eines Ringbuffers.
*
* @author Harald R. Haberstroh (hp)
*
*/
public class GraphView extends JPanel {
private static final long serialVersionUID = -5311802173756493369L;

private Ringbuffer ringbuffer;

private String error;

/**
* Hier wird das Array mit Inhalt, die Indices und und die Ampel gezeichnet.
*
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int maxx = 0; // für Panelgröße
int maxy = 0;
int x = 10;
int y = 10;

// das Array
for (int i = 0, j = ringbuffer.getIndex; i < ringbuffer.usedSize; i++) {
String s = ringbuffer.ring[j];
Rectangle2D box = g.getFontMetrics().getStringBounds(s, 0, s.length(), g);
int hpos = (int) (15.0 - box.getCenterX());
int vpos = (int) (15.0 - box.getCenterY());
g.drawString(s, j * 30 + hpos + 10, y + vpos);
j = (j + 1) % ringbuffer.getSize();
x = j * 30 + 10;
if (x > maxx)
maxx = x;
if (y > maxy)
maxy = y;
}

// die Indices
x = 10;
y = 10;
for (int i = 0; i < ringbuffer.getSize(); i++) {
g.drawRect(x, y, 30, 30);
if (i == ringbuffer.getIndex) {
pfeil(g, x + 15, y + 30, "getIndex");
}
if (i == ringbuffer.putIndex) {
pfeil(g, x + 15, y + 30, "putIndex");
}
x += 30;
if (x > maxx)
maxx = x;
if (y > maxy)
maxy = y;
}

// Panelgröße
maxx += 10;
maxy += 100;
setPreferredSize(new Dimension(maxx, maxy));

// die Ampel
if (!ringbuffer.isEmpty() && ringbuffer.getIndex == ringbuffer.putIndex) {
g.setColor(Color.RED);
g.fillOval(20, maxy - 5, 10, 10);
} else if (!ringbuffer.isEmpty()) {
g.setColor(Color.YELLOW);
g.fillOval(35, maxy - 5, 10, 10);
} else {
g.setColor(Color.GREEN);
g.fillOval(50, maxy - 5, 10, 10);
}
g.setColor(getForeground());
g.drawOval(20, maxy - 5, 10, 10);
g.drawOval(35, maxy - 5, 10, 10);
g.drawOval(50, maxy - 5, 10, 10);
g.drawString("Füllstand", 80, maxy - 5 + g.getFontMetrics().getAscent());

// Fehlermeldung
if (error != null) {
g.setFont(new Font(Font.MONOSPACED, Font.BOLD, 35));
g.setColor(Color.YELLOW);
Rectangle2D box = g.getFontMetrics().getStringBounds(error, 0,
error.length(), g);
g.drawString(error, (int) (getWidth() / 2.0 - box.getCenterX()) + 2,
(int) (getHeight() / 2.0 - box.getCenterY()) - 2);
g.setColor(Color.RED);
g.drawString(error, (int) (getWidth() / 2.0 - box.getCenterX()),
(int) (getHeight() / 2.0 - box.getCenterY()));
}
}

private void pfeil(Graphics g, int x, int y, String bez) {
// FIXME: ist noch kein Pfeil, nur Linie
g.drawLine(x, y, x, y + 30);
Rectangle2D box = g.getFontMetrics().getStringBounds(bez, 0, bez.length(),
g);
int hpos = (int) (x - box.getCenterX());
int vpos = (int) (y + 30 + box.getHeight());
g.drawString(bez, hpos, vpos);
}

public GraphView() {
ringbuffer = new Ringbuffer();
}

public void put(String c) {
if (error != null)
return;
try {
ringbuffer.put(c);
} catch (IndexOutOfBoundsException e) {
error = "Ringbufferüberlauf";
}
repaint();
}

public String get() {
String ret = null;
if (error != null)
return ret;
try {
ret = ringbuffer.get();
} catch (IndexOutOfBoundsException e) {
error = "Ringbuffer schon leer";
}
repaint();
return ret;
}

static int element = 0;

/**
* Gesamtes Fenster zeichnen mit Buttons etc.
*
* @param args
*/
public static void main(String[] args) {
final GraphView view = new GraphView();
JFrame f = new JFrame("Ringbuffer");
f.setSize(500, 200);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane pane = new JScrollPane(view);
JPanel panel = new JPanel(new BorderLayout());
panel.add(pane, BorderLayout.CENTER);
JPanel buttons = new JPanel(new FlowLayout());
JButton putButton = new JButton("put");
putButton.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
element++;
view.put("" + element);
}

});
JButton getButton = new JButton("get");
getButton.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
view.get();
}

});
buttons.add(putButton);
buttons.add(getButton);
panel.add(buttons, BorderLayout.SOUTH);
f.setContentPane(panel);
f.setVisible(true);
}
}


Der Code ist kein gutes Beispiel für Programmierstil, weil ziemlich viele Konstante für die grafische Aufbereitung einfach im Code stehen.

Labels: , ,


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]