Gleiche Komponentenbreite in Box- oder GridBagLayout

Hallo zusammen,
Mir vergeht langsam die Lust: ich versuche in einem GridBaglayout unter eine JTable eine Zeile mit einer Checkbox und 4 Textboxen nebeneinander zu setzen. Allerdings hat jede Textbox eine unterschiedliche Größe, was optisch einfach furchtbar aussieht. Ich versuche, jeder der 5 Komponenten die gleiche Größe zuzuweisen, (Tabellenbreite - Offset) / 5, aber alles spinnt nur rum.

Zuerst habe ich sie direkt in das GridbagLayout gesetzt. Als das nicht funktionierte dachte ich “Hey du bist schlau, setze sie in eine Box, die wird das richten!”. Aber auch hier Fehlanzeige:

Hat jemand eine Idee, wie ich den Textfelder OHNE IHNEN EINE BESTIMMTE PIXELZAHL ZUZUWEISEN auf die gleiche Breite bringe? Das mit der Pixelzahl ist mir wichtig, da ich evtl. noch mit die Gesamtbreite ändern muss und ich nicht jede Komponente einzeln wieder verändern möchte.

Wäre super wenn ihr was wisst, ich habe es langsam echt satt…

Grüße,
TheAceOfSpades

Hm… in einem GridLayout (ohne Bag) haben alle Components automatisch die gleiche Größe. Hier also ein new GridLayout(1,5) …

Einfach new GridLayout() am Container setzen würde auch gehen.
Guck mal in unser Wiki: http://wiki.byte-welt.net/wiki/GridLayout

Ich denke, was Du eigentlich willst ist dies: http://stackoverflow.com/questions/9131355/footer-for-jtable

ich habe das mal etwas überarbeitet, so dass es als Komponente nutzbar ist:[SPOILER]```public class TableFooterTest extends JPanel {

private static final long serialVersionUID = 1L;
private JPanel filterRow;
private JTable table;

public TableFooterTest(TableModel tableModel) {
    super(new BorderLayout());
    table = new JTable(tableModel);
    add(new JScrollPane(table));

    // Panel for text fields
    filterRow = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
    for (int i = 0; i < tableModel.getColumnCount(); i++) {
        filterRow.add(Boolean.class.equals(tableModel.getColumnClass(i))//
        ? createCheckBox()
                : new JTextField(" Sum at - " + i));
    }
    add(new JScrollPane(filterRow), BorderLayout.SOUTH);

    ColumnWithdSynchonizer columnWithdSynchonizer = new ColumnWithdSynchonizer();
    table.getColumnModel().addColumnModelListener(columnWithdSynchonizer);
    columnWithdSynchonizer.columnMarginChanged(new ChangeEvent(table
            .getColumnModel()));
    setBorder(BorderFactory.createLineBorder(Color.BLUE, 10));
}

private JCheckBox createCheckBox() {
    JCheckBox checkBox = new JCheckBox();
    checkBox.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
    checkBox.setHorizontalAlignment(SwingConstants.CENTER);
    return checkBox;
}

class ColumnWithdSynchonizer implements TableColumnModelListener {
    // Implement TableColumnModelListener methods
    // (Note: instead of implementing a listener you should be able to
    // override the columnMarginChanged and columMoved methods of JTable)
    @Override
    public void columnMarginChanged(ChangeEvent e) {
        TableColumnModel tcm = table.getColumnModel();
        int columns = tcm.getColumnCount();

        for (int i = 0; i < columns; i++) {
            Component textField = filterRow.getComponent(i);
            Dimension d = textField.getPreferredSize();
            d.width = tcm.getColumn(i).getWidth();
            textField.setPreferredSize(d);
        }

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                filterRow.revalidate();
            }
        });
    }

    @Override
    public void columnMoved(TableColumnModelEvent e) {
        Component moved = filterRow.getComponent(e.getFromIndex());
        filterRow.remove(e.getFromIndex());
        filterRow.add(moved, e.getToIndex());
        filterRow.validate();
    }

    @Override
    public void columnAdded(TableColumnModelEvent e) {
    }

    @Override
    public void columnRemoved(TableColumnModelEvent e) {
    }

    @Override
    public void columnSelectionChanged(ListSelectionEvent e) {
    }
}

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.getContentPane().setLayout(new GridLayout(0, 1));
    TableModel tableModel = new DefaultTableModel(9, 15) {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return 0 == columnIndex ? Boolean.class : String.class;
        }

    };

    frame.getContentPane().add(new TableFooterTest(tableModel));
    tableModel = new DefaultTableModel(11, 11) {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return getColumnCount() - 1 == columnIndex ? Boolean.class
                    : String.class;
        }

    };
    frame.getContentPane().add(new TableFooterTest(tableModel));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setSize(800, 300);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

}```[/SPOILER]Verbesserungspotenzial gibt’s noch bei der Auswahl der Footerkomponente, da muss zum einen noch Funktionalität angebunden und zum anderen andere Datentypen unterstützt werden.

bye
TT

In der Tat, das ist genau das was ich suche :wink:

Für die Überarbeitung danke ich dir. Wenn ich es recht sehe muss ich nur noch meine gewünschten Funktionen in die FooterKomponenten einbauen, stimmts?
Aber da bin ich ja mit ActionCommands und eigenen Listenern schnell durch. Ich probiere das alles mal aus :slight_smile:

@Timothy_Truckle : TT, woher wusstest du…?
Ich glaube das Modell meiner Glaskugel ist wohl völlig veraltet. :wink: :smiley:

Also das ganze sieht jetzt super aus, ungefähr so:

Das einzige was ein wenig stört ist der Rand nach unten.
Außerdem funktioniert es nicht, wenn ich eigene von JTextField abgeleitete Klassen verwende. Da muss ich evtl noch ein wenig rumschauen, aber fürs erste ist das schonmal mehr als genug :slight_smile:

@L-ectron-X : Unbedingt neue Glaskugel besorgen, dann muss niemand mehr stundenlang das Internet durchforsten um dann doch was anderes zu machen :smiley:

Danke an euch :wink:

Ich musste neulich die Größe des Panels verändern. Damit ist die Tabelle jetzt breiter geworden, aber das Alignment mit den Textfeldern stimmt nicht mehr :(. Die Checkbox unter der ersten Spalte passt, aber die Suchfelder sind kleiner als die Spaltenbreite.

Das verstehe ich aber nicht, da doch bei dem Quellcode die Spaltenbreite aus der Table ausgelesen wird und auf die Textfelder übertragen wird. Wisst ihr was da schief läuft (oder wahrscheinlicher wo mein Denkfehler ist) ?

Zeig mal einen KSKB mit dem neuen Code

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;


public class TableTest {
	
	
	public static void main(String[] args){
		JFrame f = new JFrame();
		f.setSize(780, 600);
		SearchTable s = new SearchTable(new ArrayList());
		f.add(s);		
		f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);	
		f.pack();
		
		f.setVisible(true);
	}	
	
	/*
	 * Tabelle mit zusätzlichen Suchfeldern am Fuß der Tabelle
	 */
	static class SearchTable extends JPanel{
		
		 private static final long serialVersionUID = 1L;
		 private JPanel filterRow;
		 

		private JTable table;

		public SearchTable(ArrayList toEvaluate) {
			
	        super(new BorderLayout());
	        
	        //Border
	        setBorder(new TitledBorder("Getriebe"));
	        
	        //Tabelle erstellen und hinzufügen
	        table = new JTable(new MyTableModel(toEvaluate));
	        MyTableModel tableModel = (MyTableModel) table.getModel();
	        add(new JScrollPane(table));
	        
	        
	        // Panel für die Suchfelder unter der Tabelle
	        filterRow = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
	        for (int i = 0; i < tableModel.getColumnCount(); i++) {
	        	//Erste Spalte als Checkbox
	            if(Boolean.class.equals(tableModel.getColumnClass(i)))
	            		filterRow.add(createCheckBox());
	            //Die restlichen Spalten als Textfelder
	            else{
	            	JTextField searchfield = new JTextField(10);
	            	searchfield.setPreferredSize(new Dimension(searchfield.getWidth(), table.getRowHeight()+3));
	            	
	            	switch(i){
	            	case 1:
	            		//Das erste Feld hat einen vordefinierten Text zur besseren Verständnis
	            		searchfield.setText("Suche...");
	            		searchfield.setForeground(Color.LIGHT_GRAY);
	            	default:
	            		searchfield.getDocument().putProperty("field", searchfield);
	            		searchfield.getDocument().putProperty("column", i);
	            		break;
	            	}
	            	
	            	filterRow.add(searchfield);
	            }
	        }
	        add(new JScrollPane(filterRow), BorderLayout.SOUTH);
	 
	        ColumnWithdSynchonizer columnWithdSynchonizer = new ColumnWithdSynchonizer();
	        table.getColumnModel().addColumnModelListener(columnWithdSynchonizer);
	        columnWithdSynchonizer.columnMarginChanged(new ChangeEvent(table.getColumnModel()));
	    }
	    
	 
		//erste Spalte
	    private JCheckBox createCheckBox() {
	        JCheckBox checkBox = new JCheckBox();
	        checkBox.setActionCommand("selectall");
	        checkBox.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
	        checkBox.setHorizontalAlignment(SwingConstants.CENTER);
	        return checkBox;
	    }
	    

		class ColumnWithdSynchonizer implements TableColumnModelListener {
	        // Implement TableColumnModelListener methods
	        // (Note: instead of implementing a listener you should be able to
	        // override the columnMarginChanged and columMoved methods of JTable)
	        @Override
	        public void columnMarginChanged(ChangeEvent e) {
	            TableColumnModel tcm = table.getColumnModel();
	            int columns = tcm.getColumnCount();
	 
	            for (int i = 0; i < columns-1; i++) {
	                Component textField = filterRow.getComponent(i);
	                Dimension d = textField.getPreferredSize();
	                d.width = tcm.getColumn(i).getWidth();
	                textField.setPreferredSize(d);
	            }
	 
	            SwingUtilities.invokeLater(new Runnable() {
	 
	                @Override
	                public void run() {
	                    filterRow.revalidate();
	                }
	            });
	        }
	 
	        @Override
	        public void columnMoved(TableColumnModelEvent e) {
	            Component moved = filterRow.getComponent(e.getFromIndex());
	            filterRow.remove(e.getFromIndex());
	            filterRow.add(moved, e.getToIndex());
	            filterRow.validate();
	        }
	 
	        @Override
	        public void columnAdded(TableColumnModelEvent e) {
	        }
	 
	        @Override
	        public void columnRemoved(TableColumnModelEvent e) {
	        }
	 
	        @Override
	        public void columnSelectionChanged(ListSelectionEvent e) {
	        }
	    }
	 }
	 
	/*
	 * Das zugehörige Model
	 */
	static class MyTableModel extends DefaultTableModel{

		
		public MyTableModel(ArrayList toEvaluate){
			
			setColumnIdentifiers(new String[]{"Ausgewählt", "Typ","Größe","Stufenzahl","iGes"});
			System.out.println(toEvaluate.size());
			
			//Die erhaltenen Daten in die Tabelle einsetzen
			for(int i=0; i<5000; i++){
				Vector newRow = new Vector();
				
				newRow.add(new Boolean(false));
				newRow.add("AZ");
				newRow.add(2);
				newRow.add(3);
				newRow.add(6.54);
				
				addRow(newRow);
			}
			
			
		}
		
		 public Class<?> getColumnClass(int column) {
		        if(column == 0){
		            return Boolean.class;
		        }
		        return super.getColumnClass(column);
		    }

		
	}

}```

Soviel habe ich eigentlich nicht verändert. Was mich wundert ist, dass es ja zuerst gepasst hat und erst als ich die Rahmengröße verändert habe hats dann nicht mehr gepasst. :(

Bei deinen Textboxen wird die Size gar nicht gesetzt:

                        Dimension d = textField.getPreferredSize();
                        d.width = tcm.getColumn(i).getWidth();
                        System.out.println("Soll gesetzt werden: " + d);
                        System.out.println("Vorher: "+ textField.getPreferredSize());          
                        textField.setPreferredSize(d);
                        System.out.println("Nacher: " + textField.getPreferredSize());```

Danke für den Tipp :). Ich habe dann herausgefunden, dass das benutzte FlowLayout kein PreferredSize beachtet. Nach dem Umsteigen auf ein BoxLayout funktioniert es nun (Leider auch nur mit Strut für den Scrollbalken.

Die Höhe der Suchleiste kann ich leider weder mit Flow noch mit BoxLayout verändern :(. Vielleicht muss ich dann noch auf ein GridBagLayout umsteigen, aber wegen 2 Komponenten ist mir das fast du doof :confused:

Jedenfalls klappt es wieder und sieht gut aus.