【问题标题】:Java ListCellRenderer and JList: handle selectionJava ListCellRenderer 和 JList:处理选择
【发布时间】:2016-08-04 22:06:41
【问题描述】:

我被一个必须在学校做的项目困住了。

我试图为“简单”用户界面创建自定义JList:用例应该显示订单列表,用户应该能够选择一个并设置是否通过按两个按钮读取/完成(阅读并完成),它也充当“未设置者”(我在 Order 类中使用 2 个布尔值,它继续通过 t、f、t、f ...)。一旦按下完成,所选行应变为绿色(并永久保持该颜色),直到再次按下该行上的“完成”按钮(=未设置)。与“读取”按钮相同,该按钮应将与 Order 类中的“is_read”标志相关的选定行永久变为黄色。

看了一些相关的帖子,我写了这个自定义ListCellRenderer

public class CookListCellRender extends JLabel implements ListCellRenderer<Order>{

public CookListCellRender(){
    setOpaque(true);
}

@Override
public Component getListCellRendererComponent(JList<? extends Order> list, Order value, int index, boolean isSelected, boolean cellHasFocus) {

    setLayout(new FlowLayout());
    setText(value.getNameEl());
    list.setVisibleRowCount(30);
    list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    setFont(new Font("Arial",Font.ITALIC,17));

    if (isSelected) {
        setBackground(Color.BLUE);
        setForeground(Color.BLUE);
    } else {
        setBackground(getBackground());
        setForeground(getForeground());
    }

    if(value.getOrderRead()){
        setBackground(Color.YELLOW);
    }else{
        setBackground(Color.WHITE);
    }

    if(value.getOrderDone()){
        setBackground(Color.GREEN);
    }else{
        setBackground(Color.WHITE);
    }
    return this;
}

}

我的问题是,一旦运行我的测试文件,一切都会正确弹出,但是当我选择一行并按下这两个按钮中的一个时,在我选择新行之前什么都没有发生:然后一直变绿或变黄(取决于我按下的按钮)我选择的行的颜色。

我很确定这是与我的自定义单元格渲染器有关的问题,也是因为我仍在学习如何使用它,我开始变得很困惑。

这是我与 UI 相关的其余相关代码,也许它很有用。按钮及其侦听器位于单独的类中(自定义 JPanel),但它们工作正常,所以...

InitGraphics(直接由我的测试类调用):

public class InitGraphics {

Cook c;
JList list;

public InitGraphics(Cook cuoco){
    c=cuoco;
    initUi();
  }

private void initUi() {
    JFrame frame = new JFrame("Cucina");
    list =new JList(c.getOrdersCopy().toArray());
    list.setCellRenderer(new CookListCellRender());
    JScrollPane panel = new JScrollPane(list);
    panel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    panel.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    ButtonPanel buttonPanel = new ButtonPanel(c.getOrdersCopy(),list);
    buttonPanel.setLayout(new FlowLayout());
    frame.add(buttonPanel,BorderLayout.NORTH);
    frame.add(panel,BorderLayout.CENTER);
    frame.setVisible(true);
    frame.setSize(600, 400);
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
  }
}

【问题讨论】:

  • 我强烈建议,不,如果您需要认真和及时的帮助,我敦促您创建并发布有效的sscce。否则,您的代码对我们来说几乎是无用的,并限制了我们理解您的问题的能力。
  • 例如:我们没有人可以编译或运行这段代码。我们不希望看到您的整个程序或浏览大量与问题无关的代码,但如果您可以将您的代码压缩为无需修改即可为我们编译和运行的最小示例,这向我们展示了您的问题,并且足够小,可以将您的问题作为代码格式的文本发布在这里,我们可能会很快解决您的问题。
  • 对不起,这里的网络连接不好。顺便说一句,我以前从未听说过 sscce,但我试图......好吧,我得到了 140 行代码,我认为这不是很合适,但可以完成他的工作。不是“java老手”我尽力了,我把它留在这里pastebin只是为了不编辑已经发布的代码
  • 我给了你两个 SSCCE,我的回答如下。请通过help center 提问部分——请不要链接到代码,这里只发布代码。但同样,请检查我的答案

标签: java swing jlist listcellrenderer


【解决方案1】:

这是要了你的命:

    } else {
        setBackground(getBackground());
        setForeground(getForeground());
    }

它根本不会改变任何东西。我认为你想要:

    } else {
        setBackground(null);
        setForeground(null);
    }

请注意,要对这段代码做任何工作,我必须创建自己的SSCCE

import java.awt.*;
import javax.swing.*;

public class InitGraphics {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            final DefaultListModel<Order> orderModel = new DefaultListModel<>();
            orderModel.addElement(new Order("One"));
            orderModel.addElement(new Order("Two"));
            orderModel.addElement(new Order("Three"));
            orderModel.addElement(new Order("Four"));
            orderModel.addElement(new Order("Five"));

            JList<Order> orderList = new JList<>(orderModel);
            orderList.setCellRenderer(new CookListCellRender());

            JPanel panel = new JPanel();
            panel.add(new JScrollPane(orderList));

            JOptionPane.showMessageDialog(null, panel);
        });
    }
}

class CookListCellRender extends JLabel implements ListCellRenderer<Order> {

    public CookListCellRender() {
        setOpaque(true);
    }

    @Override
    public Component getListCellRendererComponent(JList<? extends Order> list, Order value, int index,
            boolean isSelected, boolean cellHasFocus) {

        setLayout(new FlowLayout());
        setText(value.getNameEl());
        list.setVisibleRowCount(30);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setFont(new Font("Arial", Font.ITALIC, 17));

        if (isSelected) {
            setBackground(Color.BLUE);
            setForeground(Color.BLUE);
        } else {
            // TODO: fix!
            // setBackground(getBackground());
            // setForeground(getForeground());
            setBackground(null);
            setForeground(null);
        }

        if (value.getOrderRead()) {
            setBackground(Color.YELLOW);
        } else {
            setBackground(Color.WHITE);
        }

        if (value.getOrderDone()) {
            setBackground(Color.GREEN);
        } else {
            setBackground(Color.WHITE);
        }
        return this;
    }

}

class Order {

    private String nameE1;
    private boolean orderDone;
    private boolean orderRead;

    public Order(String nameE1) {
        this.nameE1 = nameE1;
    }

    public String getNameEl() {
        return nameE1;
    }

    public boolean getOrderDone() {
        return orderDone;
    }

    public boolean getOrderRead() {
        return orderRead;
    }

    public void setOrderDone(boolean orderDone) {
        this.orderDone = orderDone;
    }

    public void setOrderRead(boolean orderRead) {
        this.orderRead = orderRead;
    }

}

以后,请为我们完成这项工作,因为您是寻求帮助的人,而我们是志愿者。

还有这个:

    list.setVisibleRowCount(30);
    list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

永远不要在渲染器中做这种事情。这段代码应该放在你创建 JList 的地方,而不是在渲染器中。

这是我最新的 SSCCE,其中包括清除/读取/完成按钮

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.*;
import java.util.List;

import javax.swing.*;

public class InitGraphics {
    @SuppressWarnings("serial")
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            final DefaultListModel<Order> orderModel = new DefaultListModel<>();
            orderModel.addElement(new Order("One"));
            orderModel.addElement(new Order("Two"));
            orderModel.addElement(new Order("Three"));
            orderModel.addElement(new Order("Four"));
            orderModel.addElement(new Order("Five"));

            final JList<Order> orderList = new JList<>(orderModel);
            orderList.setCellRenderer(new CookListCellRender());
            orderList.setVisibleRowCount(5);

            JPanel panel = new JPanel();
            // panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
            panel.add(new JScrollPane(orderList));

            panel.add(new JButton(new AbstractAction("Read") {

                @Override
                public void actionPerformed(ActionEvent e) {
                    List<Order> selectedOrders = orderList.getSelectedValuesList();
                    for (Order order : selectedOrders) {
                        order.setOrderRead(true);
                    }
                    orderList.repaint();
                }
            }));
            panel.add(new JButton(new AbstractAction("Done") {

                @Override
                public void actionPerformed(ActionEvent e) {
                    List<Order> selectedOrders = orderList.getSelectedValuesList();
                    for (Order order : selectedOrders) {
                        order.setOrderDone(true);
                    }
                    orderList.repaint();
                }
            }));
            panel.add(new JButton(new AbstractAction("Clear") {

                @Override
                public void actionPerformed(ActionEvent e) {

                    for (int i = 0; i < orderModel.size(); i++) {
                        orderModel.getElementAt(i).setOrderDone(false);
                        orderModel.getElementAt(i).setOrderRead(false);
                    }
                    orderList.repaint();
                }
            }));


            JFrame frame = new JFrame("Test List");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

@SuppressWarnings("serial")
class CookListCellRender extends JLabel implements ListCellRenderer<Order> {

    public CookListCellRender() {
        setOpaque(true);
    }

    @Override
    public Component getListCellRendererComponent(JList<? extends Order> list, Order value, int index,
            boolean isSelected, boolean cellHasFocus) {

        // setOpaque(true); // !! 

        // !! setLayout(new FlowLayout());
        setText(value.getNameEl());
        // !! list.setVisibleRowCount(30);
        // !! list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setFont(new Font("Arial", Font.ITALIC, 17));

        if (isSelected) {
            setBackground(Color.BLUE);
            setForeground(Color.BLUE);
        } else {
            // TODO: fix!
            // setBackground(getBackground());
            // setForeground(getForeground());
            setBackground(null);
            setForeground(null);
        }

        if (value.getOrderRead()) {
            setBackground(Color.YELLOW);
        } else {
            setBackground(Color.WHITE);
        }

        if (value.getOrderDone()) {
            setBackground(Color.GREEN);
        } else {
            setBackground(Color.WHITE);
        }
        return this;
    }

}

class Order {

    private String nameE1;
    private boolean orderDone;
    private boolean orderRead;

    public Order(String nameE1) {
        this.nameE1 = nameE1;
    }

    public String getNameEl() {
        return nameE1;
    }

    public boolean getOrderDone() {
        return orderDone;
    }

    public boolean getOrderRead() {
        return orderRead;
    }

    public void setOrderDone(boolean orderDone) {
        this.orderDone = orderDone;
    }

    public void setOrderRead(boolean orderRead) {
        this.orderRead = orderRead;
    }

}

【讨论】:

  • 哇这里有很多新东西...请问AbstractAction是否与您之前使用的invokeLater函数有关?这就是选择新行后我的行颜色发生变化的原因吗?我再次尝试编写它(我发现 sscce 也是一种很好的调试方式,迫使我清理我的代码并深入修改它......完全一团糟,我在 20 个类之间迷路了)现在设置行正确为绿色,但在选择新行后仍然如此。对不起,如果我让你浪费时间,现在我已经了解了 sscce,所以下次我一定会使用它!
  • @A7X: AbstractAction 有点像类固醇上的ActionListener。它为 JButton 提供了它的侦听器,以及其他几个重要的状态字段和功能。 SwingUtilities.invokeLater(...) 用于保证您运行的代码在 Swing 事件线程或 EDT(事件调度线程)上运行。这完全是为了 Swing 线程安全,与你的代码没有运行没有任何关系。
  • 知道了。我还注意到您在列表上使用了重绘,特别是,您将所有应该保持选中的元素放在另一个数组列表中。我认为这是我的代码没有按预期工作的另一个原因......但是如果我强制在列表上进行单选,我就不能这样做,对吗?还是不会影响 getSelectedValueList 方法?
  • @A7X: “你把所有应该被选中的元素放在另一个数组列表中”——不,我的代码只允许多选。
  • “哇,这里有很多新东西……” 我希望你的帖子不长)。你看,@HovercraftFullOfEels 提供的两个示例都是 Sscce(第一个“S”代表“短”),也称为minimal reproducible example(是的,它们也是“最小”!)。
猜你喜欢
  • 2011-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
  • 2016-01-01
  • 2012-04-23
  • 2014-07-28
  • 1970-01-01
相关资源
最近更新 更多