具有多个类型JComponent的JPanel的JTable(Swing) [英] JTable for JPanel with multiple type JComponent (Swing)

查看:101
本文介绍了具有多个类型JComponent的JPanel的JTable(Swing)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个很长的问题,但是所有代码都是必需的(我当时在思考一个基本的问题,没有通用的组件).

This is a long question, but all code is needed (I was thinking a basic question, with not common components).

我只需要在一个列中构建一个JTable,其中包含多个具有多个Custom JPanel类型(JSlider + JComboBox + JTextField)的列.

I need to build a JTable with multiple Columns with multiple type Custom JPanel (with JSlider + JComboBox + JTextField) in only one Column.

我正在阅读: http://pekalicious. com/blog/custom-jpanel-cell-with-jbuttons-in-jtable/

在这个问题中,我将仅使用一个列和一个名为PanelSpinnerRadioButton的自定义JPanel的列.

In this question, I will use one Column with only one Customized JPanel with name PanelSpinnerRadioButton.

自定义面板: PanelSpinnerRadioButton.java

public class PanelSpinnerRadioButton extends JPanel {
  private final JRadioButton jrbOption01= new JRadioButton("01");
  private final JRadioButton jrbOption02 = new JRadioButton("12");

  private final JSpinner jspnValues = new JSpinner(new SpinnerNumberModel(5, 0, 10, 1));

  private final JPanel jpPanelSpinnerRadioButton = new JPanel();

  PanelSpinnerRadioButton() {
    this(new PanelSpinnerRadioButtonData(false, 20, 40));
  }

  PanelSpinnerRadioButton(PanelSpinnerRadioButtonData data) {
    super();

    jpPanelSpinnerRadioButton.setLayout(new BoxLayout(jpPanelSpinnerRadioButton, BoxLayout.LINE_AXIS));
    jpPanelSpinnerRadioButton.add(jrbOption01);
    jpPanelSpinnerRadioButton.add(jrbOption02);
    jpPanelSpinnerRadioButton.add(Box.createRigidArea(new Dimension(5,0)));
    jpPanelSpinnerRadioButton.add(new JSeparator(JSeparator.VERTICAL));
    jpPanelSpinnerRadioButton.add(Box.createRigidArea(new Dimension(5,0)));
    jpPanelSpinnerRadioButton.add(jspnValues);
    //Change States of RadioButtons (will be readOnly, ButtonGroup is not needed)
    jrbOption02.setSelected(data.getOption());
    jrbOption01.setSelected(!data.getOption());
    //Change States of Spinner
    ((SpinnerNumberModel)jspnValues.getModel()).setValue(data.getFrom());
    ((SpinnerNumberModel)jspnValues.getModel()).setMaximum(data.getSize());

    init();
  }

  private void init() {
    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
    setBackground(new Color(0, 0, 0, 0/*64*/));
    add(jpPanelSpinnerRadioButton);
  }

  // Used in PSRBTableCellEditor.getCellEditorValue()
  public PanelSpinnerRadioButtonData getData() {
    return new PanelSpinnerRadioButtonData(
        jrbOption02.isSelected(),
        (Integer)((SpinnerNumberModel)jspnValues.getModel()).getValue(),
        (Integer)((SpinnerNumberModel)jspnValues.getModel()).getMaximum()
    );
  }

}

这里是自定义JPanel之前的图像结果

Here the Image Result of before Custom JPanel

自定义面板的数据类型: PanelSpinnerRadioButtonData.java

public class PanelSpinnerRadioButtonData {

  private boolean opt02 = false;

  private Integer from = 0;
  private Integer size = 1;

  PanelSpinnerRadioButtonData() {
    this(false, 5, 10);
  }

  PanelSpinnerRadioButtonData(boolean opt02, Integer from, Integer size) {
    this.opt02 = opt02;
    this.from = from;
    this.size = size;
  }

  public boolean getOption() { return opt02; }
  public Integer getFrom() { return from; }
  public Integer getSize() { return size; }

}

现在通过编码来处理我的Custom JPanel(带有内部JComponents)

Now the coded to handle my Custom JPanel (with inner JComponents)

表模型: PSRBTableModel.java

public class PSRBTableModel extends AbstractTableModel {

  private final Object[][] data;
  private final Object[] columns;

  public PSRBTableModel(Object[][] data, Object[] columns) {
//    super();
    this.data = data;
    this.columns = columns;
  }

  public Object getValueAt(int rowIndex, int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        if (data[rowIndex][columnIndex] instanceof PanelSpinnerRadioButton) {
          return (PanelSpinnerRadioButton)data[rowIndex][columnIndex];
        }
        return data[rowIndex][columnIndex];
      }
    }
    return null;
  }

  public int getColumnCount() {
    return ((columns == null) ? 0: columns.length);
  }

  public int getRowCount() {
    return ((data == null) ? 0: data.length);
  }

  public Class getColumnClass(int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
          return PanelSpinnerRadioButton.class;
        }
        return data[0][columnIndex].getClass();
      }
    }
    return null;
  }

  public boolean isCellEditable(int rowIndex, int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
          //PanelSpinnerRadioButton Is not Editable
          return false;
        }
      }
    }
    return true;
  }

  public void setValueAt(Object value, int row, int col) {
    data[row][col] = value;
    fireTableCellUpdated(row, col);
  }

  public String getColumnName(int columnIndex) {
    return (String)columns[columnIndex];
  }

}

现在是渲染器: PSRBTableCellRenderer.java

public class PSRBTableCellRenderer implements TableCellRenderer {

  public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {

    Object output = null;

    if (value instanceof PanelSpinnerRadioButtonData) {
      output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);
    }
    return (Component)output;
  }

}

和EditorCell : PSRBTableCellEditor.java

public class PSRBTableCellEditor extends AbstractCellEditor implements TableCellEditor {

  protected Object output;

  PSRBTableCellEditor() {
  }

  public Object getCellEditorValue() {
    //Returns the value contained in the editor.
    if (output  instanceof PanelSpinnerRadioButton) {
      return ((PanelSpinnerRadioButton)output).getData();
    }
    return null;
  }

  public Component getTableCellEditorComponent(JTable table, Object value,
      boolean isSelected, int row, int column) {
    //Sets an initial value for the editor.

    if (value instanceof PanelSpinnerRadioButtonData) {
      output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);
      return (PanelSpinnerRadioButton)output;
    }
    return null;
  }

}

测试之前的代码(我正在使用JFrame)

Test the Before Code (I'm working with JFrame)

String[] hdrsObjects = new String[]{"PanelSpinnerRadioButton Class Column"};
Object[][] objectMatrix = new Object[3][hdrsObjects.length];

objectMatrix[0][0] = new PanelSpinnerRadioButton();
objectMatrix[1][0] = new PanelSpinnerRadioButton();
objectMatrix[2][0] = new PanelSpinnerRadioButton();

JTable jtbl = new JTable(new PSRBTableModel(objectMatrix, hdrsObjects));
//jtbl.setDefaultRenderer(PanelSpinnerRadioButton.class, new PSRBTableCellRenderer());
//jtbl.setDefaultEditor(PanelSpinnerRadioButton.class, new PSRBTableCellEditor());
jtbl.getColumn("PanelSpinnerRadioButton Class Column").setCellRenderer(new PSRBTableCellRenderer());
jtbl.getColumn("PanelSpinnerRadioButton Class Column").setCellEditor(new PSRBTableCellEditor());

add(new JScrollPane(jtbl));

但是我看不到JTable具有(带有自定义JPanel'PanelSpinnerRadioButton'的3行)

But I can't see the JTable with (3 rows with Custom JPanel 'PanelSpinnerRadioButton')

我有这个例外...

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
  at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
  at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
  at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
  at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
  at javax.swing.JComponent.paintComponent(JComponent.java:780)
  at javax.swing.JComponent.paint(JComponent.java:1056)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JViewport.paint(JViewport.java:728)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paint(JComponent.java:1065)
  at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
  at javax.swing.JComponent.paintChildren(JComponent.java:889)
  at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
  at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
  at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
  at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:306)
  at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
  at javax.swing.JComponent.paint(JComponent.java:1042)
  at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
  at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
  at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
  at java.awt.Container.paint(Container.java:1975)
  at java.awt.Window.paint(Window.java:3912)
  at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
  at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
  at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
  at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
  at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
  at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
  at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
  at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
  at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
  at java.awt.EventQueue.access$500(EventQueue.java:97)
  at java.awt.EventQueue$3.run(EventQueue.java:709)
  at java.awt.EventQueue$3.run(EventQueue.java:703)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
  at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
  at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
  at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
  at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
  at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

问题

  • 怎么了?
  • 为什么看不到带有3个PanelSpinnerRadioButton的JTable?
  • What's wrong?
  • Why I can't see the JTable with 3 PanelSpinnerRadioButton?

EDITION

请考虑这种情况(由同一TableCellRenderer PSRBTableCellRenderer和TableCellEditor PSRBTableCellEditor处理的另一个自定义JPanel)

Please consider this scenario (Another Custom JPanel handled by the same TableCellRenderer PSRBTableCellRenderer and TableCellEditor PSRBTableCellEditor)

class PanelButton extends JPanel {

  private final JPanel jpPanelButton = new JPanel();
  // the ActionListener does not matter now
  JButton jbtAction = new JButton("Action");

  PanelButton() {
    this(new PanelButtonEmpty());
  }
  PanelButton(PanelButtonEmpty data) {
    super();
    jpPanelButton.setLayout(new BoxLayout(jpPanelButton, BoxLayout.LINE_AXIS));

    jpPanelButton.add(jbtAction);

    /*Overridable method call in constructor*/
    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
    setBackground(new Color(0, 0, 0, 0/*64*/));
    add(jpPanelButton);
  }

  public PanelButtonEmpty getData() {
    return new PanelButtonEmpty();
  }

  public void setData(PanelButtonEmpty data) {
  }
}

我正在考虑一个完全空的类(将值投射到TableCellRenderer PSRBTableCellEditor中)

I was thinking in a totally empty class (to cast the value in TableCellRenderer PSRBTableCellEditor)

class PanelButtonEmpty {
  PanelButtonEmpty() { }
  //public boolean getLazy() { return true; }
  //public void setLazy(boolean b) {}
}

在这种情况下,由于这种原因,我有两种类型的Custom JPanel

In this case I have two types of Custom JPanel for this reason I have

用于 TableCellEditor

public class PSRBTableCellEditor extends AbstractCellEditor implements TableCellEditor {
  private Object output;
  @Override public Object getCellEditorValue() {
    if (output  instanceof PanelSpinnerRadioButton) {
      return ((PanelSpinnerRadioButton)output).getData();
    }
    if (output  instanceof PanelButton) {
      return ((PanelButton)output).getData();
    }
    return null;
  }

  @Override public Component getTableCellEditorComponent(JTable table, Object value,
      boolean isSelected, int row, int column) {
    if (value instanceof PanelSpinnerRadioButtonData) {
      output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);
      return (PanelSpinnerRadioButton)output;
    }
    if (value instanceof PanelButtonEmpty) {
      output = new PanelButton((PanelButtonEmpty)value);
      return (PanelButton)output;
    }
    return null;
  }
}

用于 TableCellRenderer

public class PSRBTableCellRenderer implements TableCellRenderer {
  private Object output = null;
  @Override public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    if (value instanceof PanelSpinnerRadioButtonData) {
      output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);
    }
    if (value instanceof PanelButtonEmpty) {
      output = new PanelButton((PanelButtonEmpty)value);
    }
    return (Component)output;
  }
}

问题

如何避免出现第二次警告(在新情况下)?

  • 每次在TableCellRenderer#getTableCellRendererComponent(...)中创建一个组件都是一种浪费.
  • It is a waste to create each time a component in the TableCellRenderer#getTableCellRendererComponent(...).

如何处理与此处所述不同的对象?

PD:

我不确定将第二部分的问题放在具有相同源代码的另一篇文章中...

I'm not sure to put this second part question in another post with the same source code...

推荐答案

objectMatrix [0] [0] =新的PanelSpinnerRadioButton();

objectMatrix[0][0] = new PanelSpinnerRadioButton();

  • 应将PanelSpinnerRadioButtonData设置为TableModel,而不是诸如PanelSpinnerRadioButton之类的组件.
    • Should be set PanelSpinnerRadioButtonData to the TableModel, rather than a component such as PanelSpinnerRadioButton.
    • output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);

      output = new PanelSpinnerRadioButton((PanelSpinnerRadioButtonData)value);

      • 每次在TableCellRenderer#getTableCellRendererComponent(...)中创建一个组件都是一种浪费.
        • It is a waste to create each time a component in the TableCellRenderer#getTableCellRendererComponent(...).
        • import java.awt.*;
          import javax.swing.*;
          import javax.swing.table.*;
          
          public class TableTest {
            public JComponent makeUI() {
              String[] hdrsObjects = {"PanelSpinnerRadioButton Class Column"};
              Object[][] objectMatrix = new Object[3][hdrsObjects.length];
              objectMatrix[0][0] = new PanelSpinnerRadioButtonData(false, 10, 40);
              objectMatrix[1][0] = new PanelSpinnerRadioButtonData(true,  20, 40);
              objectMatrix[2][0] = new PanelSpinnerRadioButtonData(false, 30, 40);
          
              JTable table = new JTable(new DefaultTableModel(objectMatrix, hdrsObjects));
              table.setRowHeight(30);
          
              TableColumn tc = table.getColumn("PanelSpinnerRadioButton Class Column");
              tc.setCellRenderer(new PSRBTableCellRenderer());
              tc.setCellEditor(new PSRBTableCellEditor());
          
              JPanel p = new JPanel(new BorderLayout());
              p.add(new JScrollPane(table));
              return p;
            }
            public static void main(String... args) {
              EventQueue.invokeLater(() -> {
                try {
                  for (UIManager.LookAndFeelInfo laf: UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(laf.getName())) {
                      UIManager.setLookAndFeel(laf.getClassName());
                    }
                  }
                } catch (Exception e) {
                  e.printStackTrace();
                }
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                f.getContentPane().add(new TableTest().makeUI());
                f.setSize(240, 240);
                f.setLocationRelativeTo(null);
                f.setVisible(true);
              });
            }
          }
          
          class PanelSpinnerRadioButtonData {
            private boolean opt02 = false;
            private Integer from = 0;
            private Integer size = 1;
          
            PanelSpinnerRadioButtonData() {
              this(false, 5, 10);
            }
            PanelSpinnerRadioButtonData(boolean opt02, Integer from, Integer size) {
              this.opt02 = opt02;
              this.from = from;
              this.size = size;
            }
            public boolean getOption() {
              return opt02;
            }
            public Integer getFrom() {
              return from;
            }
            public Integer getSize() {
              return size;
            }
          }
          
          class PanelSpinnerRadioButton extends JPanel {
            public final JRadioButton jrbOption01 = new JRadioButton("01");
            public final JRadioButton jrbOption02 = new JRadioButton("12");
            public final JSpinner jspnValues = new JSpinner(new SpinnerNumberModel(5, 0, 10, 1));
          
            private final JPanel panel = new JPanel();
          
            PanelSpinnerRadioButton() {
              this(new PanelSpinnerRadioButtonData(false, 20, 40));
            }
          
            PanelSpinnerRadioButton(PanelSpinnerRadioButtonData data) {
              super();
          
              panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
              panel.add(jrbOption01);
              panel.add(jrbOption02);
              panel.add(Box.createRigidArea(new Dimension(5, 0)));
              panel.add(new JSeparator(JSeparator.VERTICAL));
              panel.add(Box.createRigidArea(new Dimension(5, 0)));
              panel.add(jspnValues);
              ButtonGroup bg = new ButtonGroup();
              bg.add(jrbOption01);
              bg.add(jrbOption02);
              ((SpinnerNumberModel) jspnValues.getModel()).setMaximum(data.getSize());
              setData(data);
          
              init();
            }
          
            private void init() {
              setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
              setBackground(new Color(0, 0, 0, 0));
              add(panel);
            }
          
            public void setData(PanelSpinnerRadioButtonData data) {
              if (data.getOption()) {
                jrbOption02.setSelected(true);
              } else {
                jrbOption01.setSelected(true);
              }
              ((SpinnerNumberModel) jspnValues.getModel()).setValue(data.getFrom());
            }
          
            // Used in PSRBTableCellEditor.getCellEditorValue()
            public PanelSpinnerRadioButtonData getData() {
              return new PanelSpinnerRadioButtonData(
                       jrbOption02.isSelected(),
                       (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getValue(),
                       (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getMaximum());
            }
          }
          
          class PSRBTableCellRenderer implements TableCellRenderer {
            private final PanelSpinnerRadioButton renderer = new PanelSpinnerRadioButton();
            @Override public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              if (value instanceof PanelSpinnerRadioButtonData) {
                renderer.setData((PanelSpinnerRadioButtonData) value);
              }
              return renderer;
            }
          }
          
          class PSRBTableCellEditor extends AbstractCellEditor implements TableCellEditor {
            private final PanelSpinnerRadioButton editor = new PanelSpinnerRadioButton();
            @Override public Object getCellEditorValue() {
              return editor.getData();
            }
            @Override public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column) {
              if (value instanceof PanelSpinnerRadioButtonData) {
                editor.setData((PanelSpinnerRadioButtonData) value);
              }
              return editor;
            }
          }
          

          这篇关于具有多个类型JComponent的JPanel的JTable(Swing)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆