Comment puis-je implémenter l'effet de chapiteau dans Java Swing P>
6 Réponses :
Réponse de base Vous dessinez votre texte / graphique dans un bitmap, puis mettez en place un composant qui peint le décalage bitmap par une certaine quantité. Habituellement, les maillots / ticriers défilent à gauche, de sorte que le décalage augmente, ce qui signifie que le bitmap est peint à -Offset. Votre composant exécute une minuterie qui incendie périodiquement, incrémentant le décalage et l'invalidation de lui-même afin qu'il repeint. P>
Des choses comme l'emballage sont un peu plus complexes pour traiter mais assez simple. Si le décalage dépasse la largeur de bitmap, vous le réinitialisez à 0. Si la largeur de la largeur de décalage +> Bitmap, vous peignez le reste du composant à partir du début du bitmap. p>
La clé d'un ticker décent consiste à rendre le défilement aussi lisse et libre que possible. Par conséquent, il peut être nécessaire de prendre en compte la double mise en mémoire tampon du résultat, d'abord de peindre le bit de défilement dans un bitmap, puis de raincre qu'en un lieu plutôt que de peindre directement dans l'écran. P>
Voici un certain code que j'ai jeté ensemble pour vous aider à démarrer. Je prendrais normalement le code ActionListener et mettrai cela dans une sorte de Il existe également diverses bibliothèques d'animation qui vous aideraient à faire cela, mais je n'aime pas normalement inclure des bibliothèques dans des projets uniquement pour résoudre un problème comme celui-ci. P> Marqueecontroller Code> pour garder cette logique séparée du panneau, mais c'est une question différente de l'organisation de l'architecture MVC et d'une classe assez simple comme Ce n'est peut-être pas si important.
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();
}
}
}
Y a-t-il des pièces manquantes?
Je vois toujours des problèmes: je m'attendais à Marquelepanel Code> pour étendre jPanel code>, et tickanimation () code> a besoin d'un type de retour. En outre, start () code> et stop () code> besoin de voir la minuterie code>. Désolé si je sonnais la question.
Aucun problème. Leçon apprise. La prochaine fois que je vais jeter une solution comme celle-ci - Testez-la en premier. :)
Voici un exemple en utilisant javax.swing.timer code>.
p>
+1 pour fournir du code compréhensible complet + capture d'écran du programme en cours d'exécution :) (Juste comme ça que je l'aime !!!) Je pouvais +100
Je sais que c'est une réponse tardive, mais je viens de voir une autre question sur un chapiteau fermé car il était considéré comme un double de cette réponse. P>
Alors je pensais ajouter ma suggestion qui prend une approche différente des autres réponses suggérées ici. P>
the MARQUEPANEL Scrolls Composants sur un panneau non seulement du texte. Cela vous permet donc de tirer pleinement parti de tout composant swing. Un simple chapiteau peut être utilisé en ajoutant un jlabel avec du texte. Un maquis de fantaisiste peut utiliser un Jlabel avec HTML afin que vous puissiez utiliser différentes polices et couleur pour le texte. Vous pouvez même ajouter un deuxième composant avec une image. P>
J'ai ajouté des liens avec des actions au chapiteau, mais je ne peux pas les amener à travailler. Les événements de la souris ne vont pas le bon composant, parfois ils le font, parfois le pas.
@ user905374, ce n'est pas pris en charge. J'ai une version que j'ai jouée il y a quelques années qui tente de redispecter les événements de la souris sur la composante appropriée. Je ne sais pas à quel point cela fonctionne bien. Si vous souhaitez essayer cette version, envoyez-moi un message à l'aide de la page "Contactez-nous" à partir du blog et je vous enverrai cette version.
Merci pour votre réponse, oui en examinant le code, j'ai vite compris que cela n'était pas pris en charge. Je voudrais essayer l'autre version, je vous ai envoyé un message formulaire la page "Contactez-nous". Merci.
S'il vous plaît voir dans ma réponse ci-dessous ce que je suis venu avec
Ajouter un jlabel à votre cadre ou votre panneau.
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();
}
}
Ceci est censé être une amélioration de @camickr Marqueepanel. S'il vous plaît voir ci-dessus.
Pour mapper les événements de la souris sur les composants spécifiques ajoutés à Marquelepanel P>
Supprimer Un problème ici est de quoi faire avec les soureu-souris tamponnés à partir des composants individuels.
Mon approche consiste à supprimer les auditeurs de souris les composants ajoutés et laissez le Marquelepanel rediriger l'événement vers le composant correct. P> Dans mon cas, ces composants sont censés être des liens. P> Ajouter (composant Comp) Code> de MarquePepanel afin de diriger tous les événements de la souris des composants P> @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);
}
Utilisez des méthodes dans les pull-oscillants au lieu de getparent () etc. pour les souris de souris
Je ne suis pas sûr de quelles méthodes utiliser des oscillabilités
getDeSpestComponTATAT, convertir (xxx) xxx mais assurez-vous que mes commentaires ici sont sur le confort car il pourrait y avoir getparent (). GetParent () :-)