7

我希望 JTable 的单元格与所选面板水平对齐。
这是一个 SSCCE 来说明我的问题。谢谢你的帮助。

public class TableCellAlignment {

    private final static int MAX = 50;
    private static SelectablePanel[] selectablePanels = new SelectablePanel[MAX];
    private static JScrollPane slaveScrollPane = new JScrollPane();
    private static JScrollPane masterScrollPane = new JScrollPane();
    private static JTable slaveTable = new JTable();

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TableCellAlignment().createGUI();
            }
        });
    }

    private static void createGUI() {
        JFrame f = new JFrame("TableCellAlignment");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel masterPanel = new JPanel(new GridLayout(MAX, 1));
        Integer[][] objs = new Integer[MAX][1];
        for (int i = 0; i < MAX; i++) {
            objs[i][0] = new Integer(i);
            SelectablePanel masterSelectablePanel = new SelectablePanel();
            masterSelectablePanel.setNum(i);
            selectablePanels[i] = masterSelectablePanel;
            masterPanel.add(masterSelectablePanel);
        }
        DefaultTableModel model = new DefaultTableModel(objs, new Object[]{"Column1"});
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        slaveTable.setRowHeight(20);
                    }
                });
            }
        });
        model.addRow(objs);
        slaveTable.setModel(model);
        final JPanel p = new JPanel(new GridLayout(1, 2));
        masterScrollPane.setViewportView(masterPanel);
        slaveScrollPane.setViewportView(slaveTable);
        p.add(masterScrollPane);
        p.add(slaveScrollPane);
        f.add(p);

        f.setSize(400, 200);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class SelectablePanel extends JPanel {

        private PropertyChangeSupport cs;
        private int num;
        private boolean selected = false;

        public SelectablePanel() {
            cs = new PropertyChangeSupport(this);
            cs.addPropertyChangeListener(new SelectedPropertyChangeListener());
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    setSelected(true);
                }
            });
        }

        public int getNum() {
            return num;
        }

        public void setNum(int num) {
            this.num = num;
        }

        public boolean isSelected() {
            return selected;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (selected) {
                Color c = g.getColor();
                g.setColor(Color.blue);
                g.fillRect(0, 0, getWidth(), getHeight());
                g.setColor(Color.white);
                FontMetrics fm = g.getFontMetrics();
                g.drawString("" + getNum(), getWidth() / 2, (getHeight() + (fm.getAscent() - fm.getDescent())) / 2);
                g.setColor(c);
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 20);
        }

        public void setSelected(boolean selected) {
            boolean oldVal = isSelected();
            this.selected = selected;
            cs.firePropertyChange("selected", oldVal, selected);
            repaint();
        }

        private class SelectedPropertyChangeListener implements PropertyChangeListener {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals("selected")) {
                    boolean selected = (boolean) evt.getNewValue();
                    if (selected) {
                        for (int i = 0; i < MAX; i++) {
                            SelectablePanel masterSelectablePanel = selectablePanels[i];
                            if (i != getNum() && masterSelectablePanel.isSelected()) {
                                masterSelectablePanel.setSelected(false);
                            }

                        }
                        slaveTable.setRowSelectionInterval(getNum(), getNum());
                        final JViewport viewport = slaveScrollPane.getViewport();
                        Rectangle rect = new Rectangle(getBounds().x, getBounds().y, 1, 1);
                        Rectangle r2 = viewport.getVisibleRect();
                        slaveTable.scrollRectToVisible(new Rectangle(rect.x, rect.y, (int)r2.getWidth(), (int)r2.getHeight()));
                    }
                }
            }
        }
    }
}
4

2 回答 2

4

视口。设置视图位置(点);如此处所示

于 2013-04-07T20:38:15.220 回答
3

这是基本的数学运算,不需要访问视口:

// in the isSelected block of the propertyChangeListener:
JComponent current = (JComponent) evt.getSource();
slaveTable.setRowSelectionInterval(getNum(), getNum());
// get the cellRect of the selected cell
Rectangle cellRect = slaveTable.getCellRect(getNum(), 0, false);
// get the bounds of the selected panel
Rectangle panelRect = current.getBounds();
// get the visible rect of the selected panel's parent
Rectangle parentVisibleRect = ((JComponent) current.getParent()).getVisibleRect(); 
// the diff above the current (to the parent's visible rect)
int aboveCurrent = panelRect.y - parentVisibleRect.y;
// translate the cell rect 
cellRect.y = Math.max(cellRect.y - aboveCurrent, 0);
// adjust size to slaveTable's visible height
cellRect.height = slaveTable.getVisibleRect().height;
slaveTable.scrollRectToVisible(cellRect);

请注意,此代码段假定面板的父视图和表格的视图的视口具有相同的大小,因此要么从表格中删除标题,要么将标题添加到面板的 scrollPane,或者使用可以对齐视口的 LayoutManager两个滚动窗格。

于 2013-04-08T11:13:01.320 回答