这个问题是java的扩展- repaint((方法行为不端?(阅读它,是可选的(
我正在做一个Music Player
我使用JSlider
作为搜索栏,并使用JLabel
在屏幕上绘制文本,例如歌曲名称。
我是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
不包含在JLabel
中,它也会自动重新绘制JSlider
。
输出:
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........
现在,如果我从Thread
中删除label.repaint()
,则JSlider
不会重新绘制。
输出:
Slider re-painted
Slider re-painted
repaint()
方法应该这样工作吗?
在我的最后一个问题中,我被告知要使用Layout Manager
,当我使用GridLayout
只是为了检查它是否是解决方案时,它就起作用了!
只有JLabel
被重新粉刷。
但是我想在JSlider
上重叠JLabel
,所以我想使用JLayeredPane
。而现在,问题又回来了。
我该如何解决这个问题?
底线:如何在不导致方法行为不端的情况下重叠JLabel
JSlider
repaint()
?
或
repaint()
方法是否像这样工作?
正如评论中已经提到的,您的JSlider
被重新绘制的原因是它与JLabel
有重叠的边界。即使您的标签没有在滑块摆动区域上绘画,仍会将重叠区域标记为脏(即滑块的重叠部分需要重新绘制(,因为摆动不知道您只在组件的一部分上绘画。
为了减少重绘的数量,您需要缩小JLabel
的大小。最好通过调用其getPreferredSize()
方法仅与需要的大小一样大。然后,您可以通过移动标签的位置来移动文本。
此外,您不应该以普通Thread
对 gui 进行更新。请改用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");
}
}
}