昨日私がJTable
と(JButton
を含む)をJScrollPane
に追加したときにエラーが発生しました。 JButton
はテーブルの下部に固定され、クリックするとJTable
に行が追加されました。なぜsetPreferredSize()がsetMinimumSize()より先になるのはなぜですか?
テーブルがJScrollPane
よりも大きくなった場合は、JTable
の下部までスクロールすることができます。あなたはもうJButton
に行くことができませんでした。今日、私はMCVEに手伝ってもらうようにしましたが、まず最初に私はそれに猿をつけて問題を解決しましたが、回答よりも多くの質問を残しました...私が準備したMCVEは、
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class MCVE extends JFrame{
private JButton addRow;
private MCVEModel tableModel;
private JTable table;
private JScrollPane pane;
private JPanel scrollPanel, panel;
public static void main (String[] args) {
new MCVE();
}
public MCVE() {
initialize();
}
public void initialize() {
this.setTitle("Halp");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(50, 50, 500, 300);
this.setResizable(false);
JPanel mainPanel = new JPanel(new GridBagLayout());
/** The JPanel everything is put into **/
scrollPanel = new JPanel();
scrollPanel.setLayout(new BoxLayout(scrollPanel, BoxLayout.Y_AXIS));
/** The JScrollPane we're using **/
pane = new JScrollPane(scrollPanel);
pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
pane.getVerticalScrollBar().setUnitIncrement(10);
/** The button which keeps getting cut off.... **/
addRow = new JButton("...");
addRow.setBackground(Color.WHITE);
addRow.setMnemonic('R');
addRow.setFocusable(false);
addRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNewRow();
}
});
/** I wrap the button into this panel so I can affix it to the left **/
panel = new JPanel();
panel.setMinimumSize(new Dimension(0, 20));
panel.setLayout(null);
addRow.setBounds(0, 0, 35, 15);
panel.add(addRow);
/** Faking some data to get the table to populate **/
ArrayList<List<String>> allData = new ArrayList<List<String>>();
ArrayList<String> fakeData = new ArrayList<String>();
fakeData.addAll(Arrays.asList(
new String[]{"this", "is", "just", "sample", "data"}));
for(int i = 0; i < 5; i++)
allData.add(fakeData);
List<String> columnNames = Arrays.asList(new String[] {"", "", "", "", ""});
tableModel = new MCVEModel(columnNames, allData);
table = new JTable();
table.setModel(tableModel);
/** Adding it all together **/
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
scrollPanel.add(table);
scrollPanel.add(panel);
mainPanel.add(pane, c);
this.add(mainPanel);
this.setVisible(true);
}
public void addNewRow() {
tableModel.addRow(tableModel.getRowCount(),
new String[]{"true", "", "", "false", "false"});
tableModel.fireTableRowsInserted(
tableModel.getRowCount(), tableModel.getRowCount());
}
}
/**
* Just here to keep things compilable. Seriously cut back for the MCVE,
* but still replicates the problem without any errors.
* Nothing below here should be relevant to the issue.
*/
class MCVEModel extends DefaultTableModel {
private static final long serialVersionUID = -6598574844380686148L;
private List<String> columnNames;
private List<List<String>> values;
public MCVEModel (List<String> columnNames, List<List<String>> strings) {
this.columnNames = columnNames;
this.values = strings;
}
public int getColumnCount() {
return columnNames.size();
}
public int getRowCount() {
return values == null || values.size() == 0 ? 0 : values.get(0).size();
}
public String getColumnName(int col) {
return columnNames.get(col);
}
public Object getValueAt(int row, int col) {
return values.get(col).get(row);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Class getColumnClass(int c) {
return String.class;
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
values.get(col).set(row, (String) value);
fireTableCellUpdated(row, col);
}
public void removeRow(int row) {
for(int i = 0; i < values.size(); i++)
values.get(i).remove(row);
this.fireTableRowsDeleted(row, row);
}
public void addRow(int row, String[] strings) {
for(int i = 0; i < values.size(); i++)
values.get(i).add(row, strings[i]);
fireTableRowsInserted(row, row);
}
}
問題は、この行を次のとおりです。
panel.setMinimumSize(new Dimension(0, 20));
はより正確には、単語 "最小" でです。これを次のように変更します:
panel.setPreferredSize(new Dimension(0, 20));
私は必要な機能を正確に取得しました。テーブルがJScrollPanel
のために大きすぎると、今でもスクロールしてJButton
を見ることができます。もはや切断されていない。
これは、JPanel
の親がその最小寸法を守っておらず、好ましい寸法を守ったと仮定しています。どうしてこれなの? setPreferredSize()
、setMinimumSize()
、setMaximumSize()
は、「私はこの大きなものが好きですが、自分の最小値よりも小さくても、最大値よりも小さくてもいけません」と考えていましたが、これはそうではないようです場合。私はこれらの方法のどれも頻繁に使用されるべきではないことを知っていますが、setMinimumSize()
をsetPreferredSize()
以上に使う必要がありますか?
nullレイアウトまたはsetPreferredSize()を使用しないでください。パネルの好ましいサイズを動的に決定するのは、レイアウトマネージャーの仕事です。 'fireTableRowsInserted'を使わないでください。その方法を呼び出すのはテーブルモデルの仕事なので、2回行う必要はありません。 – camickr
私は 'fireTableRowsInserted'を認めます。なぜなら、コードはそれがなくても同じように動くからです。しかし、私は 'JButton'にJavaのレイアウトマネージャのいずれかでこの動作をさせることができませんでした。もし私が新しいものを書いたのであれば、この1つのボタンを除いて' BoxLayout'と同じように動作します。私が完全にコントロールしていた 'JPanel'にボタンをラップし、そのパネルを' JScrollPane'に入れて、私の現在のレイアウトマネージャを動かす必要はないでしょう。 nullレイアウトやsetPreferredSize()を使用せずにJButtonを動作させる別の方法はありますか?' –
'JButtonにこの動作を持たせることができませんでした」 - どのような振る舞いですか?余分なパネルは必要ありません。 BoxLayoutを使用してテーブルとボタンをパネルに追加すれば、すべてうまく動作します。ヌルレイアウトを使用したり、getPreferredSize()メソッドで再生したりするときにのみ問題が発生します。このアドバイスに従うと、スクロールが適切に機能します。 – camickr