Обновление повернутого JLabel с использованием Graphics2D приводит к объединению старого и нового текста - PullRequest
0 голосов
/ 12 мая 2018

Я пытаюсь повернуть JLabel на 90 градусов, который показывает текущее время на 90 градусов. После некоторых исследований большинство людей порекомендовали использовать Graphics2D и AffineTransform. Это почти работает, но когда обновляется минута времени, появляется новая цифра, которая сливается со старой цифрой.

https://i.stack.imgur.com/sn5Ej.jpg

Это не происходит в течение нескольких секунд. Кто-нибудь знает, как решить эту проблему или есть альтернативное решение?

Класс водителя:

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:

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 Класс:

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

1 Ответ

0 голосов
/ 13 мая 2018

Несколько вещей бросаются в глаза:

  • Я бы не использовал JLabel для этой цели, это сложный компонент, начиная с JPanel, и просто рисовать текстбудь проще.В моем тестировании было очень трудно заставить подсказки по размеру работать правильно, когда вращался графический контекст.
  • Вы не управляете «новыми» подсказками по размеру компонента, это может быть проблемой в сочетании с дополнительнымисложные макеты, так как ширина компонента теперь должна быть высотой и наоборот
  • Я бы рекомендовал API привязок клавиш over KeyListener
  • Swing isНЕ потокобезопасен, обновление пользовательского интерфейса вне контекста пользовательского интерфейса может вызвать любое количество проблем;вместо использования Thread вы должны использовать Swing Timer, и, поскольку вы, вероятно, действительно хотите обновить только секунды, запустив его на гораздо более медленной скорости.См. Параллельность в Swing и Как использовать Swing Timers для получения более подробной информации
  • И Calendar и Date эффективно устарели.См. Стандартный календарь для более подробной информации

Например ...

Rotated text

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, тогда я рекомендую вместо этого использовать JLayer.

Неохотно, у меня не было временичтобы обновить мои примеры для использования JLayer, но они используют библиотеку предшественника, JXLayer

...