使用Graphics2D更新旋转的JLabel会导致新旧文本合并在一起 [英] Updating a rotated JLabel using Graphics2D causes old and new text to merge together

查看:106
本文介绍了使用Graphics2D更新旋转的JLabel会导致新旧文本合并在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将JLabel旋转90度,以将当前时间显示90度.经过研究后,大多数人建议使用Graphics2D和AffineTransform.这几乎可行,但是当时间中的分钟更新时,新数字似乎与旧数字合并.

I am trying to rotate a JLabel 90 degrees that shows the current time 90 degrees. After doing some research, most people have recommended using Graphics2D and AffineTransform. This almost works, but when the minute in the time is updated, the new digit appears to merge with the old digit.

这几秒钟不会发生.是否有人知道如何解决此问题或有其他解决方案?

This does not happen for the seconds. Does anybody have any idea how to fix this issue or have an alternate solution?

驱动程序类:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Driver extends JFrame implements KeyListener {

    private boolean running = true;
    ClockWidget clockWidget;
    static Dimension screenSize;


public static void main(String[] args) {
    screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    DisplayMode displayMode = new DisplayMode((int) screenSize.getWidth(), (int) screenSize.getHeight(), 32,
            DisplayMode.REFRESH_RATE_UNKNOWN);
    new Driver().run(displayMode);
}



public void run(DisplayMode displayMode) {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(null);
    getContentPane().setBackground(Color.BLACK);
    setFont(new Font("Arial", Font.PLAIN, 24));

    Screen screen = new Screen();
    screen.setFullScreen(displayMode, this);

    initClockWidgit();

    addKeyListener(this);
    System.out.println("RUNNING");
    while (running) {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    quitProgram(screen);
    return;
}

public void initClockWidgit() {
    clockWidget = new ClockWidget();
    clockWidget.setFont(new Font("Arial", Font.PLAIN, 36));
    clockWidget.setForeground(Color.WHITE);
    clockWidget.setBackground(Color.BLUE);
    clockWidget.setBounds((int) (screenSize.getWidth() * 0.90), (int) (screenSize.getHeight() * 0.10), 250, 100);

    add(clockWidget);
    new Thread(clockWidget).start();
}

public void quitProgram(Screen screen) {
    screen.restoreScreen();
    clockWidget.disable();
}

@Override
public void keyPressed(KeyEvent keyEvent) {
    int keyCode = keyEvent.getKeyCode();
    if (keyCode == KeyEvent.VK_SPACE) {
        running = false;
    }
    keyEvent.consume();
}

@Override
public void keyReleased(KeyEvent keyEvent) {
    keyEvent.consume();
}

@Override
public void keyTyped(KeyEvent keyEvent) {
    keyEvent.consume();
}
}

ClockWidget类:

ClockWidget Class:

import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.swing.JLabel;

public class ClockWidget extends RotatedJLabel implements Runnable{

    private String currentTime;
    private boolean running;

    public ClockWidget() {
        running = true;
    }

    @Override
    public void run() {
        while(running) {
            Calendar calendar = Calendar.getInstance();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss a");
            currentTime = simpleDateFormat.format(calendar.getTime());
            setText(currentTime);   
        }
    }

    public void disable() {
        running = false;
    }

}

RotatedJLabel类别:

RotatedJLabel Class:

[import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;

import javax.swing.Icon;
import javax.swing.JLabel;

public class RotatedJLabel extends JLabel {

    public RotatedJLabel() {
        super();
    }

    public RotatedJLabel(Icon image) {
        super(image);
    }

    public RotatedJLabel(Icon image, int horizontalAlignment) {
        super(image, horizontalAlignment);
    }

    public RotatedJLabel(String text) {
        super(text);
    }

    public RotatedJLabel(String text, Icon icon, int horizontalAlignment) {
        super(text, icon, horizontalAlignment);
    }

    public RotatedJLabel(String text, int horizontalAlignment) {
        super(text, horizontalAlignment);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
        AffineTransform aT = g2.getTransform();
        Shape oldshape = g2.getClip();
        double x = getWidth()/2.0;
        double y = getHeight()/2.0;
        aT.rotate(Math.toRadians(90), x, y);
        g2.setTransform(aT);
        g2.setClip(oldshape);
        super.paintComponent(g);
    }
}

推荐答案

一些事情突然出现在我身上:

A few things jump out at me:

  • 我不会为此目的使用JLabel,它是一个复杂的组件,以JPanel开头,简单地绘制文本会更简单.在我的测试中,当旋转图形上下文时,很难获得大小调整提示以使其正常工作.
  • 您不是要管理组件的新"大小提示,而在与更复杂的布局结合使用时可能会出现问题,因为组件的宽度现在应该是高度,反之亦然
  • 我建议通过键绑定API KeyListener
  • Swing不是线程安全的,从UI上下文外部更新UI可能会产生许多问题;而不是使用Thread,您应该使用Swing Timer,并且由于您可能只想更新秒数,因此以慢得多的速度运行它.请参见 Swing中的并发标准日历
  • I wouldn't use a JLabel for this purpose, it's a complicate component, starting with a JPanel and simply painting the text would be simpler. In my testing it was very hard to get the sizing hints to work correctly when the graphics context was rotated.
  • You're not managing the component's "new" sizing hints, this could be an issue when coupled with more complex layouts, as the width of the component should now be the height and visa-versa
  • I'd recommend the key bindings API over KeyListener
  • Swing is NOT thread safe, updating the UI from outside the context of the UI could produce any number of issues; instead of using a Thread, you should be using a Swing Timer, and since you probably really only want to update the seconds, running it at a much slower speed. See Concurrency in Swing and How to Use Swing Timers for more details
  • And Calendar and Date are effectively deprecated. See Standard Calendar for more details

例如...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private RotatedLabel timeLabel;
        private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a");

        public TestPane() {
            setLayout(new GridBagLayout());
            timeLabel = new RotatedLabel(currentTime());
            add(timeLabel);

            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    timeLabel.setText(currentTime());
                }
            });
            timer.start();
        }

        public String currentTime() {
            LocalTime lt = LocalTime.now();
            return lt.format(formatter);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class RotatedLabel extends JPanel {

        private String text;

        public RotatedLabel() {
            super();
            setOpaque(false);
            setFont(UIManager.getDefaults().getFont("label.font"));
        }

        public RotatedLabel(String text) {
            this();
            this.text = text;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
            revalidate();
            repaint();
        }

        protected Dimension getTextBounds() {
            FontMetrics fm = getFontMetrics(getFont());
            return new Dimension(fm.stringWidth(text), fm.getHeight());
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = getTextBounds();
            return new Dimension(size.height, size.width);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
            AffineTransform aT = g2.getTransform();
            double x = getWidth() / 2.0;
            double y = getHeight() / 2.0;
            aT.rotate(Math.toRadians(90), x, y);
            g2.setTransform(aT);

            FontMetrics fm = g2.getFontMetrics();
            float xPos = (getWidth() - fm.stringWidth(getText())) / 2.0f;
            float yPos = ((getHeight() - fm.getHeight()) / 2.0f) + fm.getAscent();
            g2.drawString(text, xPos, yPos);
            g2.dispose();
        }
    }
}

现在,如果您绝对,必须,不问任何问题"使用类似Label的组件,那么我建议使用

Now, if you "absolutely, must, no questions asked" use a component like Label, then I recommend using JLayer instead.

毫无疑问,我还没有时间更新示例以使用JLayer,但是它们使用了以前的库JXLayer

Unfourtantly, I've not had time to update my examples to use JLayer, but they use the predecessor library, JXLayer

  • Java rotating non-square JPanel component
  • Is there any way I can rotate this 90 degrees?

这篇关于使用Graphics2D更新旋转的JLabel会导致新旧文本合并在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆