Вопрос

Как я могу реализовать эффект MARQuee в Java Swing

Это было полезно?

Решение

Вот пример, используя 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));
    }
}

Другие советы

Я знаю, что это поздний ответ, но я только что видел еще один вопрос о шарке, который был закрыт, потому что это считалось дубликатом этого ответа.

Поэтому я подумал, что добавлю свое предложение, которое делает подход, отличный от других ответов, предложенных здесь.

То Marqueepanel. Компоненты прокрутки на панели не просто текста. Таким образом, это позволяет вам воспользоваться любым качающимся компонентом. Простая шатер может использоваться путем добавления JLabel с текстом. Fancier Marquee может использовать JLABEL с HTML, чтобы вы могли использовать разные шрифты и цвет для текста. Вы даже можете добавить второй компонент с изображением.

Я просто гурил за это и нашел эта ссылка. Отказ Я провел код, и кажется, что вы хотите.

Базовый ответ - вы нарисуете свой текст / график в растровое изображение, а затем реализуете компонент, который рисует смещение растрового изображения на некоторое количество. Обычно маркистые / тикеры прокручивают оставшиеся, поэтому смещение увеличивается, что означает, что растровое изображение окрашено на сонсе. Ваш компонент работает таймером, который периодически пожаровал, увеличивая смещение и недействительна сама по себе, чтобы он перекрасил.

Такие, как упаковка, немного сложнее иметь дело, но довольно простой. Если смещение превышает ширину растровых изображений, вы перезагрузите его к 0. Если ширина смещения + компонент> ширина растровой карты, которую вы рисуете оставшуюся часть компонента, начиная с начала растрового изображения.

Ключ к приличному тикену - сделать прокрутку как можно гладко, а как можно более мягкое. Поэтому может потребоваться рассмотреть вопрос о двойной буферизации результата, сначала окрашивайте прокрутку в растровое изображение, а затем рендурируйте, что в одном идут, а не покраска прямо на экран.

Вот какой-то код, который я вместе бросил, чтобы начать. Я обычно возьму бы код действий и поставил это в каком-то MarqueeController Класс, чтобы сохранить эту логику отдельно от панели, но это другой вопрос о организации архитектуры MVC, а в простом классе, подобном этому, это может быть не так важно.

Существуют также различные библиотеки анимации, которые помогут вам сделать это, но я обычно не люблю включать библиотеки в проекты только для решения подобной такой проблемы.

Открытый класс Marqueepanel расширяет JPanel {Private Jlabel TextLabel; частное int panellocation; Задача частных действий Частный логический Isrunning = false; Общественные статические окончательные INT FRAMES_PER_SECOND = 24; Public Static Final INT MOVILE_PER_FRAME = 5; / ** * Class Constructor создает маркированную панель. * / Public Marqueepanel () {it.etlayout (null); this.textLabel = новый JLabel («прокрутка текста здесь»); this.panellocation = 0; this.taskperformer = новый ActionListener () {Public Void ActionPerformed (ActionEvent EVT) {marqueepanel.this.tickanimation (); }}} / ** * запускает анимацию. * / Public Void Start () {this.isrunning = true; Это. Таканимация (); } / ** * останавливает анимацию. * / Public Void Stop () {this.isrunning = false; } / ** * перемещает метку один кадр влево. Если он не имеет диапазона дисплея, переместите его назад * вправо, из диапазона дисплея. * / Частный пустотный тиканимация () {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) {таймер t = новый таймер (1000 / marqueepanel.frames_per_second, this.taskperformer); t.setrupeats (false); t.cstart (); }}}

Добавьте JLABEL на свой кадр или панель.

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();
}


}

Это должно быть улучшение @Camickr Marqueepanel. Пожалуйста, смотрите выше.

Чтобы сопоставить события мыши к конкретным компонентам, добавленным в Marqueepanel

Переопределять add(Component comp) Marqueepanel, чтобы направить все события мыши компонентов

Выпуск здесь - это то, что делают с мышевантами, выпущенными из отдельных компонентов. Мой подход состоит в том, чтобы удалить слушатели мыши, образующие добавленные компоненты и позволяют Marqueepanel перенаправить событие на правильный компонент.

В моем случае эти компоненты должны быть ссылками.

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

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

        comp.addMouseListener(this);

        return comp;
    }

Затем сопоставьте компонент X к Marqueepanel X и, наконец, правильный компонент

@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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top