java - java- repaint() 方法行为不端 - 2?
问题描述
这个问题是java-repaint() 方法 的扩展,行为不端?(阅读它,是可选的)
我正在做一个Music Player
我正在使用JSlider
搜索栏并使用 aJLabel
在屏幕上绘制文本,例如歌曲名称。
我是新手Graphics2D
这是最小化的代码:
public class JSliderDemo extends JFrame
{
JLabel label;
JSlider seek = new JSlider();
int y = 10;
public JSliderDemo()
{
setSize(400, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
createWindow();
setVisible(true);
startThread();
}
public void createWindow()
{
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(true);
panel.setBackground(Color.BLUE);
panel.setBorder(new LineBorder(Color.YELLOW));
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
label = new Component();
label.setSize(300, 300);
createSlider();
layeredPane.add(seek, new Integer(50));
layeredPane.add(label, new Integer(100));
panel.add(layeredPane);
add(panel);
}
protected void createSlider()
{
seek.setUI(new SeekBar(seek, 300, 10, new Dimension(20, 20), 5,
Color.DARK_GRAY, Color.RED, Color.RED));
seek.setOrientation(JProgressBar.HORIZONTAL);
seek.setOpaque(false);
seek.setLocation(10, 50);
seek.setSize(300, 20);
seek.setMajorTickSpacing(0);
seek.setMinorTickSpacing(0);
seek.setMinimum(0);
seek.setMaximum(1000);
seek.setBorder(new MatteBorder(5, 5, 5, 5, Color.CYAN));
}
protected void startThread()
{
Thread thread = new Thread(new Runnable(){
@Override
public void run()
{
try
{
while(true)
{
if(y == label.getHeight()){y = 1;}
label.repaint();
y += 1;
Thread.sleep(100);
}
}
catch(Exception ex){}
}
});
thread.start();
}
protected class Component extends JLabel
{
@Override
public void paintComponent(Graphics g)
{
Graphics2D gr = (Graphics2D) g;
gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gr.setColor(Color.RED);
gr.setFont(new Font("Calibri", Font.PLAIN, 16));
gr.drawString("Song Name", 50, y);
gr.dispose();
}
}
public static void main(String[] args)
{
new JSliderDemo();
}
}
问题是,当我调用它时repaint()
,JLabel
它会自动重新绘制JSlider
,即使它JSlider
不包含在JLabel
.
输出 :
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........
现在,如果我label.repaint()
从 中删除Thread
,则JSlider
不会重新绘制。
输出:
Slider re-painted
Slider re-painted
该repaint()
方法应该像这样工作吗?
在我的最后一个问题中,我被告知要使用Layout Manager
,当我确实使用GridLayout
它只是为了检查它是否是解决方案时,它就起作用了!
只是JLabel
被重新粉刷了。
但我想在 上重叠JLabel
,JSlider
所以我想到了使用JLayeredPane
. 而现在,问题又回来了。
我该如何解决这个问题?
底线:如何JLabel
在JSlider
不导致repaint()
方法不当的情况下重叠?
或者
repaint()
方法是这样工作的吗?
解决方案
正如评论中已经提到的那样,您JSlider
被重新绘制的原因是它与JLabel
. 即使您的标签没有在滑块区域上绘制,swing 仍会将重叠区域标记为脏(即滑块的重叠部分需要重新绘制),因为 swing 不知道您只在一个区域中绘制组件的一部分。
为了减少重绘的数量,您需要JLabel
缩小尺寸。最好仅通过调用其getPreferredSize()
方法所需的大小。然后,您可以通过移动标签的位置来移动文本。
此外,您不应该在 plain 中对 gui 进行更新Thread
。改为使用javax.swing.Timer
。它确保对 gui 的所有更新都发生在摇摆事件线程上,这是应该进行的地方。
在对您的代码进行这些调整后,只有在标签实际上在滑块上方时才重新绘制滑块。
public class JSliderDemo extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(JSliderDemo::new);
}
private final JLabel label = new CustomLabel();
public JSliderDemo() {
setSize(400, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
createWindow();
setVisible(true);
startTimer();
}
public void createWindow() {
JPanel panel = new JPanel(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
label.setLocation(0, 0);
label.setBorder(new LineBorder(Color.RED));
label.setSize(label.getPreferredSize());
layeredPane.add(createSlider(), Integer.valueOf(50));
layeredPane.add(label, Integer.valueOf(100));
panel.add(layeredPane);
setContentPane(panel);
}
protected JSlider createSlider() {
JSlider seek = new CustomSlider();
seek.setOrientation(JProgressBar.HORIZONTAL);
seek.setOpaque(false);
seek.setLocation(10, 50);
seek.setSize(300, 20);
seek.setMajorTickSpacing(0);
seek.setMinorTickSpacing(0);
seek.setMinimum(0);
seek.setMaximum(1000);
seek.setBorder(new LineBorder(Color.BLUE));
return seek;
}
private void startTimer() {
new Timer(100, e -> {
int y = label.getY();
int maxY = label.getParent().getHeight();
if (y == maxY) {
y = -label.getHeight();
}
label.setLocation(label.getX(), y + 1);
label.repaint();
}).start();
}
private static class CustomLabel extends JLabel {
protected CustomLabel() {
setFont(new Font("Calibri", Font.PLAIN, 16));
setText("Song Name");
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Painting Label");
}
}
protected static class CustomSlider extends JSlider {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Painting Slider");
}
}
}
推荐阅读
- ios - iOS ReactNative React 依赖问题
- python - 如何将两个文本文件合并为一个?
- gradle - 无法实例化“InvalidJavadocPosition”类
- c# - 将 2 个 ienumerable 与不同类型结合起来(一对多)
- azure - 从已部署的 WCF 服务中获取 404 但可以获取服务定义
- android - 如何将 Camera2Config.Extender 与 CameraX 一起使用
- android - 将 DialogFragment 放在所有活动的前面(即使是在显示 DialogFragment 之后创建的活动)
- php - 更改 wordpress 小部件内的默认 HTML 标记
- python - 使用 dict.values() 迭代时无法替换 dicts 列表中的字符串值
- java - 如何禁用 JMeter 日志信息输出到控制台(在 java 中)