使用Graphics2D旋转JLabel后更新文本,新旧文本重叠
解决旋转JLabel时间更新时文字重叠的问题
首先咱们来拆解下你遇到的问题:分钟更新时新旧数字重叠,秒更新却没异常,核心是两个原因在作怪:
问题根源
- 过度频繁的重绘请求:你的
ClockWidget类里每1毫秒就调用一次setText,这会导致大量重绘请求积压,Swing的事件调度线程忙不过来,旧内容还没被清除就绘制了新内容,自然出现重叠。 - 旋转绘制时背景清除不彻底:在
RotatedJLabel的paintComponent方法中,你直接在原Graphics对象上做旋转,裁剪区域还是旋转前的旧范围,导致super.paintComponent(g)无法完整清除组件背景——尤其是分钟文本宽度变化时(比如从09变成10),旧的像素没被完全覆盖。
修复方案(基于现有代码修改)
步骤1:降低时间更新频率
先把ClockWidget的更新频率改成每秒一次,完全没必要毫秒级刷新:
@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); try { // 每秒更新一次,减轻重绘压力 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
步骤2:修复旋转绘制逻辑
修改RotatedJLabel的paintComponent方法,创建独立的Graphics对象,确保背景被彻底清除:
@Override protected void paintComponent(Graphics g) { // 创建Graphics2D副本,避免干扰全局绘制状态 Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); double centerX = getWidth() / 2.0; double centerY = getHeight() / 2.0; // 以组件中心为原点旋转90度 g2.rotate(Math.toRadians(90), centerX, centerY); // 先绘制背景,彻底清除旧内容 g2.setColor(getBackground()); g2.fillRect(0, 0, getWidth(), getHeight()); // 调用父类方法绘制文本 super.paintComponent(g2); // 释放创建的Graphics对象 g2.dispose(); }
替代方案:自定义JPanel绘制旋转文本
如果想更灵活地控制绘制逻辑,可以放弃继承JLabel,改用JPanel自己绘制旋转文本,完全避开JLabel默认绘制逻辑的干扰:
自定义RotatedClockPanel类
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JPanel; public class RotatedClockPanel extends JPanel implements Runnable { private String currentTime; private boolean running; private Font font; private Color textColor; public RotatedClockPanel() { running = true; font = new Font("Arial", Font.PLAIN, 36); textColor = Color.WHITE; setBackground(Color.BLUE); } @Override public void run() { while(running) { Calendar calendar = Calendar.getInstance(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss a"); currentTime = simpleDateFormat.format(calendar.getTime()); repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override protected void paintComponent(Graphics g) { // 先绘制组件背景,清除旧内容 super.paintComponent(g); Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 计算组件中心 int centerX = getWidth() / 2; int centerY = getHeight() / 2; // 以中心为原点旋转90度 g2.rotate(Math.toRadians(90), centerX, centerY); // 设置字体和文本颜色 g2.setFont(font); g2.setColor(textColor); // 计算文本居中的位置 int textWidth = g2.getFontMetrics().stringWidth(currentTime); int textHeight = g2.getFontMetrics().getAscent(); int drawX = centerX - textWidth / 2; int drawY = centerY + textHeight / 2; // 绘制时间文本 g2.drawString(currentTime, drawX, drawY); g2.dispose(); } public void disable() { running = false; } @Override public void setFont(Font font) { this.font = font; repaint(); } public void setForeground(Color textColor) { this.textColor = textColor; repaint(); } }
在Driver中替换使用这个Panel
注意旋转后组件的宽高要互换(原来的250宽100高,旋转90度后设置为100宽250高,适配文本显示):
public void initClockWidgit() { RotatedClockPanel clockPanel = new RotatedClockPanel(); clockPanel.setFont(new Font("Arial", Font.PLAIN, 36)); clockPanel.setForeground(Color.WHITE); clockPanel.setBackground(Color.BLUE); // 旋转后宽高互换,让文本显示更合理 clockPanel.setBounds((int) (screenSize.getWidth() * 0.90), (int) (screenSize.getHeight() * 0.10), 100, 250); add(clockPanel); new Thread(clockPanel).start(); }
这样修改后,无论是分钟还是秒更新,都不会出现文字重叠的问题了,绘制逻辑也更清晰可控。
内容的提问来源于stack exchange,提问作者Matt Miller
相关产品推荐
相关产品推荐

