【问题标题】:How does JList repaint?JList 如何重绘?
【发布时间】:2010-11-21 19:52:09
【问题描述】:

请尝试运行以下示例并向我解释为什么重绘有时会失败,尤其是当您单击一行时。看起来 JList 忘记了行的首选大小。 我的意思是,当以固定间隔运行此代码时,JList 会在某个随机间隔变为空白。

 import javax.swing.JList;
 import javax.swing.ListCellRenderer;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JFrame;
 import javax.swing.BorderFactory;
 import javax.swing.DefaultListModel;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.Timer;
 import java.util.TimerTask;
class ListItem
{
 private Color color;
 private String value;
 public ListItem(Color c, String s)
 {
  color = c;
  value = s;
 }
 public Color getColor()
 {
  return color;
 }
 public String getValue()
 {
  return value;
 }
}

class MyCellRenderer extends 
JLabel implements ListCellRenderer
{
 public MyCellRenderer ()
 {
  setOpaque(true);
 }
 public Component getListCellRendererComponent(JList list,
   Object value, // value to display
         int index,    // cell index
         boolean iss,  // is selected
         boolean chf)  // cell has focus?
 {
  System.out.println(" i cell-rendering "+CustomList.tid + " " 
    + CustomList.model.getSize() + " " + index+" "+CustomList.statusList.getValueIsAdjusting() + " ");
  setText(((ListItem)value).getValue());
  setBackground(((ListItem)value).getColor());
  if (iss)
  {
   setBorder(BorderFactory.createLineBorder(Color.blue, 1));
  }
  else
  {
   setBorder(BorderFactory.createLineBorder(list.getBackground(), 1));
  }
  return this;
 }
}

public class CustomList
{
 public static DefaultListModel model;
 public static JList statusList;
 public static int tid = 0;

 public static void tidUr()
 {
  int delay = 1000;
  int period = 1000; 
  Timer timer = new Timer(); 
  timer.scheduleAtFixedRate(new TimerTask()
  { 
   public void run()
   { 
    // model = new DefaultListModel();
    // statusList.setModel(model);
    // statusList.setCellRenderer(new MyCellRenderer());
    model.clear();
    tid++;
    ListItem li = new ListItem(Color.cyan, "test line one "+tid);
    model.addElement(li);
    li = new ListItem(Color.yellow, "foo foo foo foo foo");
    model.addElement(li);
    li = new ListItem(Color.green, "quick brown fox");
    model.addElement(li);
   }
  }, delay, period); 
 }

 public static void main(String args[])
 {
  JFrame frame = new JFrame("Custom List Demo");
  frame.addWindowListener( new WindowAdapter()
  {
   public void windowClosing( WindowEvent e)
   {
    System.exit(0);
   }
  }
   );

  model = new DefaultListModel();
  statusList = new JList(model);
  statusList.setCellRenderer(new MyCellRenderer());

  ListItem li = new ListItem(Color.cyan, "test line one");
  model.addElement(li);
  li = new ListItem(Color.yellow, "foo foo foo foo foo");
  model.addElement(li);
  li = new ListItem(Color.green, "quick brown fox");
  model.addElement(li);

  JPanel panel = new JPanel();
  panel.add(statusList);
  frame.getContentPane().add("Center", panel);
  frame.setLocation(300, 400);
  frame.setSize(200, 200);
  //frame.pack();
  frame.setVisible(true);

  // tidUr();
    ActionListener actionListener = new ActionListener() {
        public void actionPerformed(ActionEvent actionEvent) {
          System.out.println("Hello World Timer");
            model.clear();
            tid++;
            ListItem li = new ListItem(Color.cyan, "test line one "+tid);
            model.addElement(li);
            li = new ListItem(Color.yellow, "foo foo foo foo foo");
            model.addElement(li);
            li = new ListItem(Color.green, "quick brown fox");
            model.addElement(li);
        }
      };

    javax.swing.Timer t2 = new javax.swing.Timer(1000, actionListener);
    t2.start();

 }
}

【问题讨论】:

    标签: java swing jlist


    【解决方案1】:

    不确定您要描述的重绘问题到底是什么。

    但是,快速浏览一下代码,明显的问题是您应该使用 Swing Timer 来进行更新。对 Swing 组件的所有更改都应在 Event Dispatch Thread 上完成。由于模型的更改会通知 Swing 组件自行更新,因此模型更新应在 EDT 上完成。

    阅读 Concurrency 上的 Swing 教程部分了解更多信息。

    【讨论】:

    • 谢谢大家!!!这解决了问题,我了解到 java.util.Timer 不适合与 Swing 结合使用
    • ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { System.out.println("Hello World Timer");模型.clear();时间++; ListItem li = new ListItem(Color.cyan, "测试第一行"+tid);模型.addElement(li); li = new ListItem(Color.yellow, "foo foo foo foo foo");模型.addElement(li); li = new ListItem(Color.green, "quick brown fox");模型.addElement(li); } }; javax.swing.Timer t2 = new javax.swing.Timer(1000, actionListener); t2.start();
    【解决方案2】:

    您应该使用javax.swing.Timer 而不是使用java.util.Timer,它旨在与Swing 组件一起使用,这很可能是您的问题。

    Swing 组件只能Event Dispatch Thread 上进行修改,并且当 EDT 之外的另一个线程更新GUI,它可能看起来工作正常,但突然发生了一些“奇怪”的事情。

    【讨论】:

    • JTable 同时适用于 java.util.Timer 和 javax.swing.Timer。 JList 仅适用于 javax.swing:Timer
    • 它可能看起来与 java.util.Timer 一起工作得很好,但你违反了 Swing 单线程策略,因此你永远无法确定。
    猜你喜欢
    • 2021-07-24
    • 2023-03-18
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 2021-05-10
    • 2017-09-07
    相关资源
    最近更新 更多