Daten sortieren/ausgeben

Wie würdet ihr folgendes Problem lösen?

Ich habe eine Collection mit einigen (vielen, Performance und v.a. Speicherverbrauch ist wichtig!) relativ komplexen Objekten darin. Diese müssen sortiert werden und ausgegeben, wenn 2 “gleich gut” (ich kanns grad nich besser ausdrücken) sind, sollen sie auf dem gleichen Platz ausgegeben werden. Es ist IMO nicht möglich den Objekten beim Sortieren eine einfache Punktwertung zu geben, ich kann nur per Comparator sagen besser/schlechter/gleich.

Das Sortieren ist demach nicht soo das Problem. Aber wie soll ich die Ausgabe machen? Ich würde eigentlich ungern bei der Ausgabe jedes Objekt nochmal mit dem davor vergleichen, ob es auf den gleichen Platz kommt, da das ganze wie gesagt performancekritisch ist…

Entweder eine neue Klasse schreiben oder die bestehende erweitern um das Interface Comparable mit der Methode compareTo
dann kannst du wenn du einen Vector nimmst einfach sagen Collections.sort(vector) oder eine andere Klasse benutzen die von Collenction ist

also sortieren sollten klar sein - wegen der ausgabe

was mir spontan einfaellen waere (hat kein anspruch auf sinnvolles und korrektes Handeln *g)

Direkt ins Sortieren eingreifen halte ich fuer unmoeglich, da du eine Reihenfolge erstellen musst und somit kein Objekt als „gleich“ behandeln kannst

Die Objekte haben eine boolean flag der dann gesetzt wird, wenn ein Objekt gleich einem anderen ist. Bei der ausgabe wird ueberprueft ob der flag gesetzt ist - wenn ja in die gleiche Zeile z.b. wenn nicht dann in eine neue - respektiv wie du die Ausgabe erstellst.

edit: Oeh war ich (deathbyaclown)… war net eingeloggt irgendwie :slight_smile:

andere moeglichkeit die auch gern genommen wird, wenn man z.b. ein int in seinem Objekt hat dass sichergestellt ist einen bestimmten werte bereich zu haben, so dass man ein bit zur freien verfuegung hat… dann einfach per bitmaskierung das eine bit setzen falls gleich.

Dann muss man aber aufpassen das int wieder richtig bei der ausgabe zu manipulieren

Thx @all
Ich glaube ich habe doch eine Möglichkeit gefunden, den Objekten einen int-Wert zuzuordnen, nach dem ich sortieren könnte…
falls das nicht klappt, werde ich es mit dbacs Ansatz probieren.

@Eagle: Ich glaube du hattest das Problem nicht ganz verstanden :wink:

Hi,

jede halbwegs reale Application hat heutzutage einen Splashscreen. Ich habe heute nacht mal einen Splashscreen geschrieben der sich einblendet und wieder ausblendet. Hierbei kann man die Zeit die benötigt wird angeben. Das ganze ist bis jetzt nur auf einem Desktop mit 32 Bit farbtiefe getestet, sollte unter Linux (meist nur 24 bit) etc aber laufen denke ich. Evtl hat ja jemand daran interresse. Ich habe das ganze mit einem .png bild getestet, jedes andere bildformat sollte ebenfalls funktionieren, aber gerade png’s oder gif bilder sind interresant da der desktop hintergrund weiterhin durchscheint.

Die Klasse SplashScreen braucht im Konstruktor einfach den relativen pfad zu dem Bild welches eingeblendet werden soll. Bei mir hier liegt das bild im resourcen verzeichniss unter „de/nicedezigns/musicbox/gui/resources/logo_big.png“.

Für das eigendliche zeichnen des Splashscreen benutze ich einfach ein JLabel welches das aktuelle Bild kennt und dieses zeichnet. bei der übergabe des Bildes an das JLabel wird auch immer dessen grösse gesetzt sonst würde man das JLabel nicht sehen da es sonst eine grösse von 0,0 pixeln hätte was eher schlecht wäre :wink:

Falls ihr das ganze nutzen wollt solltet ihr es folgendermassen anwenden:

```	public MeineApplication()
	{
		SplashScreen splashScreen = null;
	
		try
		{
			splashScreen = new SplashScreen("de/nicedezigns/musicbox/gui/resources/logo_big.png");			
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	  // hier startet ihr eure Application
	  doSomething();
	  // Die Application ist bereit zum anzeigen, also Splashscreen ausblenden
	  splashScreen.blendOut();
	  // Zeige Application
	  setVisible(true);

	}```

…hier aus eclipse herausgestartet sieht man den Editor durscheinen.

Anbei die beiden Klassen die ihr braucht:


import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

/**
 * <p>
 * Title: SplashScreen
 * </p>
 * <p>
 * Description: Animated Splashscreen
 * </p>
 * <p>
 * Copyright: Copyright (c) 2006
 * </p>
 * <p>
 * Company: Nice Dezigns
 * </p>
 * 
 * @author Jens Hohl
 * @date 05.08.2006
 * @time 01:14:25
 */
public class SplashScreen implements ActionListener
{
	// desktop
	private final BufferedImage background;

	// Your logo
	private final BufferedImage image;

	// actual image
	private BufferedImage currentImage;

	private SplashPainter label;

	private final int speed = 1000 / 20;

	/**
	 * Duration in Time Mills
	 */
	private float duration = 3000.0f;

	private long startTime = 0;

	private boolean isBlendIn = true;

	private final Timer timer;

	public SplashScreen(String path) throws IOException, AWTException
	{
		final URL url = this.getClass().getClassLoader().getResource(path);
		image = ImageIO.read(url);

		currentImage = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(image.getWidth(null), image.getHeight(null));

		final Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
		final int x = (int) (screenDimension.getWidth() / 2 - image.getWidth(null) / 2);
		final int y = (int) (screenDimension.getHeight() / 2 - image.getHeight(null) / 2);
		final int w = image.getWidth(null);
		final int h = image.getHeight(null);

		final Robot robot = new Robot();
		final Rectangle rectangle = new Rectangle(x, y, w, h);
		background = robot.createScreenCapture(rectangle);
		drawImage(0f);

		label = new SplashPainter();
		label.setImage(background);
		final JWindow f = new JWindow(new JFrame());
		f.getContentPane().add(label);
		f.pack();
		f.setLocationRelativeTo(null);

		timer = new Timer(speed, this);
		timer.setCoalesce(true);
		timer.start();
		startTime = System.currentTimeMillis();
		f.setVisible(true);
	}

	public void blendOut()
	{
		isBlendIn = false;
		startTime = System.currentTimeMillis();
		timer.start();
	}

	public void actionPerformed(ActionEvent e)
	{
		float percent;

		if (isBlendIn)
		{
			percent = (System.currentTimeMillis() - startTime) / duration;
			percent = Math.min(1.0f, percent);
		}
		else
		{
			percent = (System.currentTimeMillis() - startTime) / duration;
			percent = Math.min(1.0f, percent);
			percent = 1.0f - percent;
		}

		float alphaValue = percent;

		if (percent >= 1.0)
		{
			timer.stop();
			// blendOut(); // Einkommentieren damit die animation sofort wieder
			// ausgeblendet wird
		}
		else if (alphaValue <= 0.0f)
		{
			timer.stop();
			SwingUtilities.getWindowAncestor(label).dispose();
		}

		drawImage(alphaValue);
		label.setImage(currentImage);
		label.repaint();
	}

	/**
	 * Draws Background, then draws image over it
	 * 
	 * @param alphaValue
	 */
	private void drawImage(float alphaValue)
	{
		final Graphics2D g2d = (Graphics2D) currentImage.getGraphics();
		g2d.drawImage(background, 0, 0, null);
		g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphaValue));
		g2d.drawImage(image, 0, 0, null);
		g2d.dispose();
	}

	public static void main(String[] args) throws Exception
	{
		new SplashScreen("de/nicedezigns/musicbox/gui/resources/logo_big.png");
	}
}

Und das JLabel:


import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JLabel;

/**
 * <p>
 * Title: SplashPainter
 * </p>
 * <p>
 * Description: Displays Spashimage 
 * </p>
 * <p>
 * Copyright: Copyright (c) 2006
 * </p>
 * <p>
 * Company: Nice Dezigns
 * </p>
 * 
 * @author Jens Hohl
 * @date 05.08.2006
 * @time 03:36:39
 */
public class SplashPainter
	extends JLabel
{
	private Image image;
	
	public void setImage(Image image)
	{
		this.image = image;
		setPreferredSize(new Dimension(image.getWidth(null),image.getHeight(null)));
	}
	
	@Override
	public void paintComponent(Graphics g)
	{
		super.paintComponents(g);
		g.drawImage(image,0,0,this);
	}
}




Den code könnt ihr frei verwenden, ohne anspruch auf korrektheit. Verbesserungsvorschläge sind jederzeit willkommen. :smiley:

mfg,
Jens

Wenn wir schon dabei sind: Ich hab sowas auch schon geschrieben :wink:

package de.illu.swing;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferStrategy;
import java.util.Hashtable;
import java.util.Set;

import javax.swing.JFrame;

import de.illu.util.Util;

/**
 * @author Illuvatar
 */
public class Splashscreen extends JFrame
{
    /**
     * Diese Variable wird von Java5 verlangt.
     */
    public static final long serialVersionUID = 159372468L;
    private short alpha;
    private Image img;
    private Image bg;
    private BufferStrategy strategy;
    private Rectangle rect;
    private Hashtable<String, String> info;
    private boolean fadeinfo;

    /**
     * Constructor
     * 
     * @param img
     *            Das Image, das in dem Splashscreen gezeichnet werden soll
     * @param alpha
     *            Der alpha-Wert (0 = durchsichtig, 255 = undurchsichtig)
     * @param inFade
     *            Die Zeit zum einfaden in Millisekunden
     * @param title
     *            Der Titel, der in der Taskleiste erscheint
     * @param info
     *            Key/Value - Paare, die als zusätzliche Information unten in
     *            den Splashscreen geschrieben werden. Kann null sein.
     * @param fadeinfo
     *            Soll diese Info mitgefadet werden?
     */
    public Splashscreen(Image img, short alpha, long inFade, String title,
            Hashtable<String, String> info, boolean fadeinfo)
    {
        super(title);
        this.alpha = alpha;
        this.img = img;
        this.info = info;
        this.fadeinfo = fadeinfo;
        setSize(img.getWidth(this), img.getHeight(this));
        setLocationRelativeTo(null);
        rect = getBounds();
        try {
            Robot robot = Swingutil.createDefaultRobot();
            bg = robot.createScreenCapture(rect);
        } catch (AWTException e) {
            e.printStackTrace();
        }
        setUndecorated(true);
        setAlwaysOnTop(true);
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        setIgnoreRepaint(true);
        setResizable(false);
        addComponentListener(new ComponentAdapter() {
            public void componentMoved(ComponentEvent evt)
            {
                setLocationRelativeTo(null);
            }
        });
        addWindowListener(new WindowAdapter() {
            public void windowIconified(WindowEvent evt)
            {
                setState(Frame.NORMAL);
            }
        });
        setVisible(true);
        getGraphics().drawImage(bg, 0, 0, this);
        createBufferStrategy(2);
        strategy = getBufferStrategy();
        setIgnoreRepaint(false);
        if (inFade > 0) {
            setIgnoreRepaint(true);
            long start = System.currentTimeMillis();
            long now;
            loop: while (true) {
                now = System.currentTimeMillis();
                if ((now - start) >= inFade) {
                    break loop;
                }
                this.alpha = (short) ((((double) (now - start)) / inFade) * alpha);
                paint(getGraphics());
                Util.sleep(7); // Performance
            }
            this.alpha = alpha;
            setIgnoreRepaint(false);
            repaint();
        }
    }

    /**
     * Die Methode wird zum Zeichnen des Fensters verwendet.
     */
    public void paint(Graphics gr)
    {
        Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
        g.clearRect(rect.x, rect.y, rect.width, rect.height);
        g.drawImage(bg, 0, 0, this);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                alpha / 255.0F));
        g.drawImage(img, 0, 0, this);
        if (info != null) {
            if (!fadeinfo)
                g.setComposite(AlphaComposite.getInstance(
                        AlphaComposite.SRC_OVER, 1));
            Font f = new Font("Serif", Font.BOLD, 16);
            g.setFont(f);
            Set<String> s = info.keySet();
            int height = getSize().height;
            int halfwidth = getSize().width / 2;
            for (String key : s) {
                height -= (f.getSize() + 4);
                String value = info.get(key);
                g.drawString(key, halfwidth
                        - 4
                        - (int) (f.getStringBounds(key, g
                                .getFontRenderContext()).getWidth()), height);
                g.drawString(value, halfwidth + 4, height);
            }
        }
        g.dispose();
        strategy.show();
    }

    /**
     * Fadet den Splashscreen aus, und macht ihn invisible.
     * 
     * @param time
     *            Die Zeit zum Ausfaden
     * @param captureNew
     *            Gibt an, ob ein neues Bild gemacht werden soll.<br/><b>Achtung:</b>
     *            Wenn der Wert true ist, wird das Fenster kurz flackern, um dem
     *            Robot die "Sicht" auf das dahinterliegende zu geben.
     */
    public void fadeOut(long time, boolean captureNew)
    {
        if (captureNew)
            try {
                Robot robot = Swingutil.createDefaultRobot();
                setVisible(false);
                bg = robot.createScreenCapture(rect);
            } catch (AWTException e) {
                e.printStackTrace();
            }
        setVisible(true);
        short alpha = this.alpha;
        setIgnoreRepaint(true);
        long start = System.currentTimeMillis();
        long now;
        loop: while (true) {
            now = System.currentTimeMillis();
            if ((now - start) >= time) {
                break loop;
            }
            this.alpha = (short) ((((double) (time - (now - start))) / time) * alpha);
            paint(getGraphics());
            Util.sleep(7); // Performance
        }
        this.alpha = alpha;
        setVisible(false);
    }
}

Verwendung:

Splashscreen ss = new Splashscreen (someImage, (short)255, 2000, "Splash", null, false);
//doSth
ss.fadeOut(1000, false);

Wo ich das anschau: Ein-zwei Sachen sind etwas unschön im Code. Aber er ist auch schon älter :wink:

Vielleicht wäre das noch ganz geil wenn man das hinkriegen würde das der Screen solange angezeigt wird bis das Programm wirklich geladen ist?!
So eine Art MediaTracker.

Ich gehe davon aus das wenn du in deinem Programm setVisible(true) aufrufst es geladen ist :wink:

Indem fall einfach die methode blendOut(); aufrufen und der splash verschwindet…

-jens