Frage

Wie kann ich Marquee Effekt in Java Swing implementieren

War es hilfreich?

Lösung

Hier ist ein Beispiel unter Verwendung von javax.swing.Timer.

Marquee.png

import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

/** @see http://stackoverflow.com/questions/3617326 */
public class MarqueeTest {

    private void display() {
        JFrame f = new JFrame("MarqueeTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        String s = "Tomorrow, and tomorrow, and tomorrow, "
        + "creeps in this petty pace from day to day, "
        + "to the last syllable of recorded time; ... "
        + "It is a tale told by an idiot, full of "
        + "sound and fury signifying nothing.";
        MarqueePanel mp = new MarqueePanel(s, 32);
        f.add(mp);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        mp.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MarqueeTest().display();
            }
        });
    }
}

/** Side-scroll n characters of s. */
class MarqueePanel extends JPanel implements ActionListener {

    private static final int RATE = 12;
    private final Timer timer = new Timer(1000 / RATE, this);
    private final JLabel label = new JLabel();
    private final String s;
    private final int n;
    private int index;

    public MarqueePanel(String s, int n) {
        if (s == null || n < 1) {
            throw new IllegalArgumentException("Null string or n < 1");
        }
        StringBuilder sb = new StringBuilder(n);
        for (int i = 0; i < n; i++) {
            sb.append(' ');
        }
        this.s = sb + s + sb;
        this.n = n;
        label.setFont(new Font("Serif", Font.ITALIC, 36));
        label.setText(sb.toString());
        this.add(label);
    }

    public void start() {
        timer.start();
    }

    public void stop() {
        timer.stop();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        index++;
        if (index > s.length() - n) {
            index = 0;
        }
        label.setText(s.substring(index, index + n));
    }
}

Andere Tipps

Ich weiß, das ist eine späte Antwort, aber ich sah nur noch eine Frage zu einem Zelt, das geschlossen wurde, weil es ein Duplikat dieser Antwort betrachtet wurde.

Also ich dachte, dass ich meinen Vorschlag hinzufügen würde, die einen Ansatz unterscheidet sich von den anderen Antworten nimmt hier vorgeschlagen.

Die MarqueePanel scrollt Komponenten auf einem Panel nicht nur Text. So können Sie so alle Vorteile einer Swing-Komponente zu nehmen. Ein einfaches Festzelt kann durch Zugabe einen JLabel mit Text verwendet werden. Ein ausgefallenes Festzelt könnte einen JLabel mit HTML verwenden, so dass Sie verschiedene Schriftarten und Farben für den Text verwenden können. Sie können sogar eine zweite Komponente mit einem Bild hinzuzufügen.

Ich habe gerade für sie gegoogelt und gefunden Link . Ich lief den Code und es scheint zu tun, was Sie wollen.

Grund Antwort ist, dass Sie Ihren Text / Grafik in eine Bitmap zeichnen und dann eine Komponente implementieren, dass Farben die Bitmap um einen gewissen Betrag versetzt. Normalerweise marquees / tickers scroll links, so dass die Offset erhöht, was bedeutet, das Bitmap bei -offset gemalt. Ihre Komponente läuft ein Timer, der ausgelöst wird periodisch, Inkrementieren der Offset und ungültig zu machen selbst, damit es neu zeichnet.

Dinge wie Verpackung sind ein wenig komplizierter zu behandeln, aber recht einfach. Wenn der Offset überschreitet die Bitmap Breiten Sie es wieder auf 0 zurückgesetzt, wenn die Offset + -Komponente Breite> Bitmap Breiten Sie den Rest der Komponente ausgehend vom Beginn des Bitmap malen.

Der Schlüssel zu einem anständigen Ticker ist das Scrollen so glatt und als flimmerfrei wie möglich zu machen. Daher kann es notwendig sein, um das Ergebnis zu prüfen, doppelte Pufferung, zuerst das Scrollen Bit in eine Bitmap-Malerei und dann machen, dass in einem Rutsch, anstatt direkt in den Bildschirm zu malen.

Hier ist ein Code, dass ich warf zusammen, um Ihnen den Start. Normalerweise würde ich nehmen Sie die Action Code und setze, dass in einer Art MarqueeController Klasse diese Logik von der Platte getrennt zu halten, aber das ist eine andere Frage über die MVC-Architektur zu organisieren und in einer einfachen genug Klasse wie diese kann es nicht so wichtig sein, .

Es gibt auch verschiedene Animations Bibliotheken, die Sie tun dies helfen würde, aber ich normalerweise nicht wie Bibliotheken in Projekte, um nur ein Problem wie dieses zu lösen.

public class MarqueePanel extends JPanel {
  private JLabel textLabel;
  private int panelLocation;
  private ActionListener taskPerformer;
  private boolean isRunning = false;

  public static final int FRAMES_PER_SECOND = 24;
  public static final int MOVEMENT_PER_FRAME = 5;

  /**
   * Class constructor creates a marquee panel.
   */

  public MarqueePanel() {
    this.setLayout(null);
    this.textLabel = new JLabel("Scrolling Text Here");
    this.panelLocation = 0;
    this.taskPerformer = new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        MarqueePanel.this.tickAnimation();
      }
    }
  }

  /**
   * Starts the animation.
   */

  public void start() {
    this.isRunning = true;
    this.tickAnimation();
  }

  /**
   * Stops the animation.
   */

  public void stop() {
    this.isRunning = false;
  }

  /**
   * Moves the label one frame to the left.  If it's out of display range, move it back
   * to the right, out of display range.
   */

  private void tickAnimation() {
    this.panelLocation -= MarqueePanel.MOVEMENT_PER_FRAME;
    if (this.panelLocation < this.textLabel.getWidth())
      this.panelLocaton = this.getWidth();
    this.textLabel.setLocation(this.panelLocation, 0);
    this.repaint();
    if (this.isRunning) {
      Timer t = new Timer(1000 / MarqueePanel.FRAMES_PER_SECOND, this.taskPerformer);
      t.setRepeats(false);
      t.start();
    }
  }
}

Fügen Sie eine JLabel an den Rahmen oder Platte.

ScrollText s=   new ScrollText("ello Everyone.");
jLabel3.add(s);


public class ScrollText extends JComponent {
private BufferedImage image;

private Dimension imageSize;

private volatile int currOffset;

private Thread internalThread;

private volatile boolean noStopRequested;

public ScrollText(String text) {
currOffset = 0;
buildImage(text);

setMinimumSize(imageSize);
setPreferredSize(imageSize);
setMaximumSize(imageSize);
setSize(imageSize);

noStopRequested = true;
Runnable r = new Runnable() {
  public void run() {
    try {
      runWork();
    } catch (Exception x) {
      x.printStackTrace();
    }
  }
};

internalThread = new Thread(r, "ScrollText");
internalThread.start();
}

private void buildImage(String text) {
RenderingHints renderHints = new RenderingHints(
    RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);

renderHints.put(RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY);

BufferedImage scratchImage = new BufferedImage(1, 1,
    BufferedImage.TYPE_INT_RGB);

Graphics2D scratchG2 = scratchImage.createGraphics();
scratchG2.setRenderingHints(renderHints);

Font font = new Font("Serif", Font.BOLD | Font.ITALIC, 24);

FontRenderContext frc = scratchG2.getFontRenderContext();
TextLayout tl = new TextLayout(text, font, frc);
Rectangle2D textBounds = tl.getBounds();
int textWidth = (int) Math.ceil(textBounds.getWidth());
int textHeight = (int) Math.ceil(textBounds.getHeight());

int horizontalPad = 600;
int verticalPad = 10;

imageSize = new Dimension(textWidth + horizontalPad, textHeight
    + verticalPad);

image = new BufferedImage(imageSize.width, imageSize.height,
    BufferedImage.TYPE_INT_RGB);

Graphics2D g2 = image.createGraphics();
g2.setRenderingHints(renderHints);

int baselineOffset = (verticalPad / 2) - ((int) textBounds.getY());

g2.setColor(Color.BLACK);
g2.fillRect(0, 0, imageSize.width, imageSize.height);

g2.setColor(Color.GREEN);
tl.draw(g2, 0, baselineOffset);

// Free-up resources right away, but keep "image" for
// animation.
scratchG2.dispose();
scratchImage.flush();
g2.dispose();
 }
public void paint(Graphics g) {
// Make sure to clip the edges, regardless of curr size
g.setClip(0, 0, imageSize.width, imageSize.height);

int localOffset = currOffset; // in case it changes
g.drawImage(image, -localOffset, 0, this);
g.drawImage(image, imageSize.width - localOffset, 0, this);

// draw outline
g.setColor(Color.black);
g.drawRect(0, 0, imageSize.width - 1, imageSize.height - 1);
  }
private void runWork() {
while (noStopRequested) {
  try {
    Thread.sleep(10); // 10 frames per second

    // adjust the scroll position
    currOffset = (currOffset + 1) % imageSize.width;

    // signal the event thread to call paint()
    repaint();
  } catch (InterruptedException x) {
    Thread.currentThread().interrupt();
  }
  }
 }

public void stopRequest() {
noStopRequested = false;
internalThread.interrupt();
}

public boolean isAlive() {
return internalThread.isAlive();
}


}

Dies soll eine Verbesserung der @camickr MarqueePanel sein. Bitte siehe oben.

Um Mausereignisse auf die spezifischen Komponenten der Karte hinzugefügt MarqueePanel

außer Kraft setzen add(Component comp) von MarqueePanel um alle Mausereignisse der Komponenten zu richten

Ein Problem hier ist, was zu tun mit den Mausevents aus den einzelnen Komponenten gebrannt. Mein Ansatz ist die Maus Zuhörer die zusätzlichen Komponenten bilden zu entfernen und lassen Sie die MarqueePanel das Ereignis an die richtige Komponente umgeleitet werden.

In meinem Fall dieser Komponenten sollen Links sein.

    @Override
    public Component add(Component comp) {
        comp = super.add(comp);

        if(comp instanceof MouseListener)
             comp.removeMouseListener((MouseListener)comp);

        comp.addMouseListener(this);

        return comp;
    }

Karte dann die Komponente x zu einem MarqueePanel x und schließlich die richtigen Komponente

@Override
public void mouseClicked(MouseEvent e)
{
    Component source = (Component)e.getSource();
    int x = source.getX() + e.getX();
    int y = source.getY();

    MarqueePanel2 marqueePanel = (MarqueePanel2) ((JComponent)e.getSource()).getParent();
    double x2 = marqueePanel.getWidth();
    double x1 = Math.abs(marqueePanel.scrollOffset);



    if(x >= x1 && x <= x2)
    {
        System.out.println("Bang " + x1);
        Component componentAt = getComponentAt(x+marqueePanel.scrollOffset, y);

        if(comp instanceof MouseListener)
             ((MouseListener) componentAt).mouseClicked(e);

        System.out.println(componentAt.getName());
    }
    else
    {
        return;
    }


    //System.out.println(x);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top