6

我创建了自己的 CellRenderer,其中包括一些字符串和 JList 项目中的 JProgressBar ...但是 JProgressBar 和整个 JList 项目将绘制一次,我正在寻找一种重新绘制项目的方法......我试过了启动一个线程,这将永久重新绘制......但我不知道我必须重新绘制什么才能得到结果......

JList repaint ...没有结果 CellRenderer repaint ...没有结果 JFrame repaint ...没有结果

有人了解我的问题并知道出路吗?

非常感谢!

更新:[更新已删除]

下一个更新:

import java.awt.Component;
import java.awt.Dimension;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.ListCellRenderer;


public class Main extends JFrame{

public DefaultListModel contentListModel = new DefaultListModel();
public MyCellRenderer MCR = new MyCellRenderer();
public JList contentList = new JList(contentListModel);

public Main(){
    super("Example");
    setMinimumSize(new Dimension(300,300));
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    contentList.setCellRenderer(MCR);
    contentListModel.addElement("");
    contentListModel.addElement("");
    add(contentList);
}

public static void main(String[] args){
    new Main().setVisible(true);
}

class MyCellRenderer extends JPanel implements ListCellRenderer{

    public MyCellRenderer(){
        JProgressBar jpb = new JProgressBar();
        jpb.setIndeterminate(true);
        add(jpb);
    }

    @Override
    public Component getListCellRendererComponent(JList arg0, Object arg1,
            int arg2, boolean arg3, boolean arg4) {
        // TODO Auto-generated method stub
        return this;
    }



}

}
4

5 回答 5

4

如前所述,渲染器不是实时组件,它不是组件层次结构的一部分。因此,“自然”动画效果(如不确定进度条的移动)会丢失。一个可能有效的技巧 - 但请注意:这高度依赖 LAF!- 是对系统撒谎,并且总是将酒吧报告为可支付的。结合每 x ms 伪造一个新值的计时器可能会再次显示动画:

public static class ProgressBarRenderer implements TableCellRenderer {

    /** The bar. */
    private JProgressBar indeterminate = new JProgressBar() {
        // fake displayable to trigger ui animation
        @Override
        public boolean isDisplayable() {
            return true;
        };
    };

    /** The bar. */
    private JProgressBar determinate = new JProgressBar() ;

    public ProgressBarRenderer() {
        indeterminate.setStringPainted(true);
        indeterminate.setIndeterminate(true);
        indeterminate.setString(null);
    }    

    @Override
    public Component getTableCellRendererComponent(JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row,
            int column) {
        int pbi = (Integer) value;
        if (pbi < 0) {
            return indeterminate;
        }
        determinate.setValue(pbi);
        return determinate;
    }
}

// a timer driving the animation
Action update = new AbstractAction() {

    int count;
    @Override
    public void actionPerformed(ActionEvent e) {
        table.setValueAt(-1, 0, AncientSwingTeam.INTEGER_COLUMN);
    }

};
new Timer(100, update).start();
于 2013-04-17T11:42:02.247 回答
3
  • +1 有趣的问题,

  • Renderer在 Swing 中并没有指定显示动画,这只是静态绘画、幻觉、快照,

  • 你必须在你的代码中为这个对象设置动画,但JProgressBar.setIndeterminate(true);如果没有肮脏的黑客,这不是一件容易的事,

    1. 需要自己的JProgressBar

    2. 需要自己的动画ListCellRenderer,并且结果可能与JProgressBar放置在JPanel例如


  • 我认为JList不合适JComponents,使用JTable一列和/或不使用JTableHeader

  • 与for一起使用JPanel(由 放置GridLayout)的简单解决方法,然后输出到 Swing GUI 将与(不带or )非常相似JProgressBarsJProgressBar.setIndeterminate(true);JTableJTableHeaderJList

    1. 把这个JPanel放到JScrollPane

    2. 覆盖getPreferredSizefor JScrollPane,然后您将正确模拟JList.setVisibleRowCount

    3. 使用 JComponents 和 , 更改JScrollBar.setUnitIncrement实现自然滚动JPanelJListJTableJTextAreaJScrollPane

于 2013-04-17T07:28:21.867 回答
3

单元格渲染器是组件的静态/橡皮图章,它们不是“真实的”活动组件。它们只是简单地“绘制”到使用它们的视图的表面上。

这意味着(真的)不可能重新绘制它们。您可以通过更改要更改的行的值来鼓励列表更新。这将导致模型触发更新,从而导致列表重新绘制。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestProgressListCellRenderer {

    public static void main(String[] args) {
        new TestProgressListCellRenderer();
    }

    public TestProgressListCellRenderer() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                final DefaultListModel<Float> model = new DefaultListModel<>();
                model.addElement(0f);

                JList<Float> list = new JList<>(model);
                list.setCellRenderer(new ProgressListCellRenderer());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(list));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Timer timer = new Timer(125, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        float value = model.getElementAt(0);
                        value += 0.01;
                        if (value >= 1f) {
                            value = 1f;
                            ((Timer)e.getSource()).stop();
                        }
                        model.setElementAt(value, 0);
                    }
                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();

            }
        });
    }

    public class ProgressListCellRenderer extends JProgressBar implements ListCellRenderer<Float> {

        @Override
        public Component getListCellRendererComponent(JList<? extends Float> list, Float value, int index, boolean isSelected, boolean cellHasFocus) {
            setValue(Math.round(value * 100));
            return this;
        }            
    }        
}

这是一个简单的例子,我尝试使用setIndeterminate,但我无法更新它(非常烦人),但这可能会引发一些想法

于 2013-04-17T07:13:58.017 回答
3

您可以javax.swing.Timer自定义驱动动画ProgressBarUI,见这里incrementAnimationIndex()看起来很有希望,但我还没有尝试过。

图片

如果没有更好的解决方案,您可以在 a 中使用ProgressIcona DefaultListCellRenderer;该方法在此处的 a 中进行了说明JTabbedPane

图片

于 2013-04-17T11:28:19.820 回答
0

这很简单。

public void updateListData(final JList myList) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      ListModel lm = myList.getModel();
      DefaultListModel dlm = new DefaultListModel();
      for (int i = 0; i < lm.getSize(); i++) {
        dlm.addElement(lm.getElementAt(i));
      }
      myList.setModel(dlm);
    }
  });
}

上面的代码可以从 EDT 和另一个线程调用。但是您还应该阅读如何处理 Swing 组件并了解模型(ListModel、TableModel 等)。要让 JList 中的元素重新绘制,您应该在模型中修改它的对象。

于 2013-04-17T07:12:18.183 回答