Swing JTable: Eigene Zeichnung im Header

Status
Nicht offen für weitere Antworten.

rik0

Mitglied
Hallo,

ich möchte in einem JTableHeader per paintComponent zeichnen. Diese Zeichnung soll beim Scrollen der Tabelle nach links/rechts mitbewegt werden - also immer über den gleichen Spalten stehen. Da sich die Zeichnung über mehrere Spalten erstreckt, kann ich imo nicht über den CellRenderer gehen.

Ich habe es so versucht:

Dies ist mein Tableheader:

Code:
		public class MyTableHeader extends JTableHeader {
			
			JTableHeader defaultHeader;
			
			public MyTableHeader(JTableHeader defaultHeader) {
				super();
				this.defaultHeader = defaultHeader;
				setPreferredSize(new Dimension(defaultHeader.getWidth(),50));
				
				GroupLayout gl = new GroupLayout(this);
				this.setLayout(gl);
				
				gl.setHorizontalGroup(gl.createSequentialGroup()
						.addComponent(defaultHeader));
				
				gl.setVerticalGroup(gl.createSequentialGroup()
						.addGap(0,0,Integer.MAX_VALUE)
						.addComponent(defaultHeader));
				
			}

			@Override
			protected void paintComponent(Graphics g) {
				super.paintComponent(g);
				
				//beispielhafte Zeichnung
				g.fillRect(20, 20, this.getWidth(), 5);
				
			}
		}

Von der ursprünglichen Tabelle setze ich dann den neuen Header mittels

Code:
table.setTableHeader(new MyTableHeader(table.getTableHeader()));

und adde sie zu einer Scrollpane.

Die Zeichnung wird zwar richtig mitgescrollt, allerdings wird der ursprüngliche Tableheader (der ja in meinem neuen enthalten ist) nicht richtig dargestellt, wenn ich nach rechts scrolle - es entstehen Artefakte (siehe Anhang).

Hat jemand eine Idee, wie ich dieses Problem beheben könnte? Oder gibt es evtl eine andere Möglichkeit als einen eigenen Header zu schreiben?
Meine Variante hat nämlich noch den Nachteil, dass ich die Spalten nicht resizen kann.
 

Anhänge

  • header.png
    header.png
    3,3 KB · Aufrufe: 60

Ebenius

Top Contributor
Kannst Du mal das Bild hochladen das gezeichnet werden soll? Und vielleicht mal ein manipulierter Screenshot wie das ganze aussehen soll?

Ebenius
 

rik0

Mitglied
Es soll gar kein Bild sein, sondern nur ein paar Markierungslinien über Spalten mit dazugehöriger Beschreibung. Siehe Anhang.
Das Problem ist halt, dass das ganze nach links und rechts mitscrollen soll, da die Markierungen sinnvollerweise immer über den gleichen Spalten stehen sollen.
 

Anhänge

  • header2.png
    header2.png
    6,4 KB · Aufrufe: 46

André Uhres

Top Contributor
Code:
table.setTableHeader(new MyTableHeader(table.getTableHeader()));
Statt mit einem eigenen TableHeader, versuch's mal mit einer eigenen TableHeaderUI nehmen, etwa so:
Java:
table.getTableHeader().setUI(new UIHeader());
...
class UIHeader extends BasicTableHeaderUI {
    private final static int ADDITIONAL_HEIGHT = 20;
    public UIHeader() {
        super();
        Runnable noReordering = new Runnable() {
            public void run() {
                header.setReorderingAllowed(false);
                header.getTable().setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            }
        };
        SwingUtilities.invokeLater(noReordering);
    }

    @Override
    public Dimension getPreferredSize(JComponent c) {
        Dimension d = super.getPreferredSize(c);
        d.height += ADDITIONAL_HEIGHT;
        return d;
    }

    @Override
    public void paint(final Graphics g, final JComponent c) {
        int numColumns = header.getTable().getColumnCount();
        for (int column = 0; column < numColumns; column++) {
            Rectangle rect = header.getHeaderRect(column);
            rect.y += ADDITIONAL_HEIGHT;
            rect.height -= ADDITIONAL_HEIGHT;
            paintCell(g, rect, column);
        }
        drawText(g, "Text1", 0, 1);
        drawText(g, "Text2Text2", 3, 6);
        drawText(g, "Text3", 8, 9);
        drawText(g, "Text4Text4", 12, 15);
    }
    private void drawText(Graphics g, String text, int fromColumn, int toColumn) {
        int max = header.getTable().getColumnCount() - 1;
        if(fromColumn > max){
            throw new IllegalArgumentException(text + " fromColumn " + fromColumn + " > " + max);
        }
        if(toColumn > max){
            toColumn = max;
        }
        if(toColumn < fromColumn){
            throw new IllegalArgumentException(text + " toColumn " + toColumn + " < " + fromColumn);
        }
        Rectangle picRect = header.getHeaderRect(fromColumn);
        for (int i = fromColumn; i <= toColumn; i++) {
            picRect = picRect.union(header.getHeaderRect(i));
        }
        g.setColor(Color.BLACK);
        FontMetrics f = g.getFontMetrics();
        String str = text;
        int w = f.stringWidth(str);
        int textY = picRect.y + ADDITIONAL_HEIGHT - 8;
        g.drawString(str, picRect.x + (picRect.width - w) / 2, textY);
        int lineY = picRect.y + ADDITIONAL_HEIGHT - 5;
        g.drawLine(picRect.x + 2, lineY, picRect.x + picRect.width - 4, lineY);
    }
    private void paintCell(final Graphics g, final Rectangle cellRect, final int column) {
        TableCellRenderer renderer = header.getDefaultRenderer();
        if (renderer == null) {
            return;
        }
        TableColumn aColumn = header.getColumnModel().getColumn(column);
        Component component = renderer.getTableCellRendererComponent(header.getTable(),
                aColumn.getHeaderValue(), false, false, 0, column);
        if (component.getParent() == null) {
            rendererPane.add(component);
        }
        rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
                cellRect.width - 1, cellRect.height - 1, true);
    }
}
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Ich würde das Problem nicht per TableHeaderUI lösen. Daraus ergibt sich immer das Problem, dass das Aussehen der Komponenten sich nicht dem jeweiligen LookAndFeel anpassen. Anbei eine sehr umfangreiche (wenn auch nicht ganz zu Ende getestete) Lösung. Zwei LayoutManager und eine main()-Methode die zeigt, wie's funktionieren kann:

TableHeaderContainerLayout
Legt einen JTableHeader und mehrere Komponenten übereinander. Die Höhe wird durch die PreferredSize der Komponenten bestimmt. Die Breite richtet sich nach der Breite der Spalten im JTableHeader.
Java:
/* (@)TableHeaderContainerLayout.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.widget;

import java.awt.*;

import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;

/**
 * A layout manager, managing the size of a table header container inside the
 * column header section of a scroll pane. The last {@link JTableHeader table
 * header} added to {@code this} layout adjusts the width of the whole target
 * container. All components are stacked on top of each other, in component
 * order from top to bottom. The vertical gap property defines the gap between
 * two components stacked. If no table header is contained in the target
 * container, the client area of this layout has a size of {@code 0px x 0px}.
 * 
 * @version $Revision: 1.1 $ as of $Date: 2009/04/21 00:04:20 $
 * @author Sebastian Haufe
 */
public class TableHeaderContainerLayout
  implements LayoutManager, java.io.Serializable {

  /** Serial version UID */
  private static final long serialVersionUID = 8582579879030376805L;

  // -------------------------------------------------------------------------
  // Instance fields
  // -------------------------------------------------------------------------

  private JTableHeader tableHeader;
  private int verticalGap = 5;

  // -------------------------------------------------------------------------
  // Implementing LayoutManager
  // -------------------------------------------------------------------------

  public void layoutContainer(Container parent) {
    final Insets ins = parent.getInsets();
    final int x = ins.left;
    final int width = parent.getWidth() - ins.left - ins.right;

    final Rectangle headerRect = getHeaderRect();
    final int slaveWidth = headerRect.width;
    final int slaveX = headerRect.x + ins.left;

    /* align children */
    final int count = parent.getComponentCount();
    int y = ins.top;
    for (int i = 0; i < count; i++) {
      final Component c = parent.getComponent(i);
      final int height = c.getPreferredSize().height;
      if (c == tableHeader) {
        c.setBounds(x, y, width, height);
      } else {
        c.setBounds(slaveX, y, slaveWidth, height);
      }
      y += height;
      y += verticalGap;
    }
  }

  private Rectangle getHeaderRect() {
    final JTableHeader th = tableHeader;
    final TableColumnModel cm = th == null ? null : th.getColumnModel();
    final int cols = cm == null ? 0 : cm.getColumnCount();
    switch (cols) {
    case 0:
      return new Rectangle();
    case 1:
      return th.getHeaderRect(0);
    default:
      return th.getHeaderRect(0).union(th.getHeaderRect(cols - 1));
    }
  }

  public Dimension minimumLayoutSize(Container parent) {
    return preferredLayoutSize(parent);
  }

  public Dimension preferredLayoutSize(Container parent) {
    final Insets ins = parent.getInsets();
    final Dimension dim =
          new Dimension(ins.left + ins.right, ins.top + ins.bottom);
    final int count = tableHeader == null ? 0 : parent.getComponentCount();
    for (int i = 0; i < count; i++) {
      final Component c = parent.getComponent(i);
      final Dimension pref = c.getPreferredSize();
      if (c == tableHeader) {
        dim.width += pref.width;
      } else {
        dim.height += verticalGap;
      }
      dim.height += pref.height;
    }

    return dim;
  }

  public void addLayoutComponent(String name, Component comp) {
    if (comp instanceof JTableHeader) {
      tableHeader = (JTableHeader) comp;
    }
  }

  public void removeLayoutComponent(Component comp) {
    if (comp instanceof JTableHeader) {
      tableHeader = null;
    }
  }

  // -------------------------------------------------------------------------
  // Bean getters and setters
  // -------------------------------------------------------------------------

  /**
   * Get the vertical gap. By default this value is {@code 5px}.
   * 
   * @return the vertical gap in pixels
   */
  public int getVerticalGap() {
    return verticalGap;
  }

  /**
   * Set the vertical gap. By default this value is {@code 5px}.
   * 
   * @param verticalGap the vertical gap in pixels
   */
  public void setVerticalGap(int verticalGap) {
    this.verticalGap = verticalGap;
  }
}
TableHeaderAdapterLayout
Legt beliebig viele Komponenten nebeneinander (ggf. überlappend), anhand einer Spaltenangabe mit Spaltenanzahl (col span). Adaptiert die Breiten Spalten vom angegebenen JTableHeader und übernimmt die Höhe der Komponenten von deren PreferredSize.
Java:
/* (@)TableHeaderAdapterLayout.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.widget;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;

import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;

/**
 * A layout manager implementation using the component widths from the
 * {@link JTableHeader#getHeaderRect(int) header rectangles} of the assigned
 * {@link #getTableHeader() table header}. All components of a target
 * container must be added with instances of the nested {@link Constraints}
 * type.
 * 
 * @version $Revision: 1.1 $ as of $Date: 2009/04/21 00:04:20 $
 * @author Sebastian Haufe
 */
public class TableHeaderAdapterLayout
  implements LayoutManager2, java.io.Serializable {

  /** Serial version UID */
  private static final long serialVersionUID = -5450006896544005754L;

  // -------------------------------------------------------------------------
  // Instance fields
  // -------------------------------------------------------------------------

  private final Map<Component, Constraints> compConstraints =
        new HashMap<Component, Constraints>();
  private JTableHeader tableHeader;

  // -------------------------------------------------------------------------
  // Constructors
  // -------------------------------------------------------------------------

  /**
   * Creates a new <code>TableHeaderAdapterLayout</code>.
   * 
   * @param tableHeader the table header used to layout the columns
   * @see #setTableHeader(JTableHeader)
   */
  public TableHeaderAdapterLayout(JTableHeader tableHeader) {
    this.tableHeader = tableHeader;
  }

  // -------------------------------------------------------------------------
  // Implementing LayoutManager
  // -------------------------------------------------------------------------

  public void layoutContainer(Container parent) {
    final Insets ins = parent.getInsets();
    final int count = parent.getComponentCount();
    final JTableHeader th = tableHeader;
    final TableColumnModel cm = th == null ? null : th.getColumnModel();
    final int columnCount = cm == null ? 0 : cm.getColumnCount();
    final int consumableHeight = parent.getHeight() - ins.top - ins.bottom;
    final int consumableWidth = parent.getWidth() - ins.left - ins.right;
    for (int i = 0; i < count; i++) {
      final Component c = parent.getComponent(i);
      final Constraints constraints = compConstraints.get(c);
      if (constraints == null
            || columnCount == 0
            || constraints.columnIndex >= columnCount) {
        c.setBounds(0, 0, 0, 0);
      } else {
        final int first = Math.max(constraints.columnIndex, 0);
        final int last =
              Math.min(columnCount, constraints.columnIndex
                    + constraints.columnSpan) - 1;
        final Rectangle rect =
              th.getHeaderRect(first).union(th.getHeaderRect(last));
        final int prefHeight = c.getPreferredSize().height;
        final int height = Math.min(consumableHeight, prefHeight);
        int y = ins.top;
        if (height < consumableHeight) {
          y += (consumableHeight - prefHeight) * c.getAlignmentY();
        }
        c.setBounds(ins.left + rect.x, y, Math.min(rect.width,
              consumableWidth - rect.x), height);
      }
    }
  }

  public Dimension minimumLayoutSize(Container parent) {
    return preferredLayoutSize(parent);
  }

  private Rectangle getHeaderRect() {
    final JTableHeader th = tableHeader;
    final TableColumnModel cm = th == null ? null : th.getColumnModel();
    final int cols = cm == null ? 0 : cm.getColumnCount();
    switch (cols) {
    case 0:
      return new Rectangle();
    case 1:
      return th.getHeaderRect(0);
    default:
      return th.getHeaderRect(0).union(th.getHeaderRect(cols - 1));
    }
  }

  public Dimension preferredLayoutSize(Container parent) {
    final Rectangle headerRect = getHeaderRect();
    final int count = parent.getComponentCount();
    final JTableHeader th = tableHeader;
    final TableColumnModel cm = th == null ? null : th.getColumnModel();
    final int columnCount = cm == null ? 0 : cm.getColumnCount();
    int consumableHeight = 0;
    for (int i = 0; i < count; i++) {
      final Component c = parent.getComponent(i);
      final Constraints constraints = compConstraints.get(c);
      if (constraints == null
            || columnCount == 0
            || constraints.columnIndex >= columnCount) {} else {
        final Dimension prefSize = c.getPreferredSize();
        consumableHeight = Math.max(consumableHeight, prefSize.height);
      }
    }

    final Insets ins = parent.getInsets();
    return new Dimension(ins.left + ins.right + headerRect.width, ins.top
          + ins.bottom
          + consumableHeight);
  }

  public void addLayoutComponent(String name, Component comp) {
    throw new UnsupportedOperationException(
          "Use addLayoutComponent(Component, Object) instead"); //$NON-NLS-1$
  }

  public void removeLayoutComponent(Component comp) {
    compConstraints.remove(comp);
  }

  // -------------------------------------------------------------------------
  // Implementing LayoutManager2
  // -------------------------------------------------------------------------

  public void addLayoutComponent(Component comp, Object constraints) {
    if (!(constraints instanceof Constraints)) {
      throw new IllegalArgumentException( //
            "Wrong type: Constraints expected"); //$NON-NLS-1$
    }
    this.compConstraints.put(comp, (Constraints) constraints);
  }

  public float getLayoutAlignmentX(Container target) {
    return 0.5f;
  }

  public float getLayoutAlignmentY(Container target) {
    return 0.5f;
  }

  public void invalidateLayout(Container target) {}

  public Dimension maximumLayoutSize(Container target) {
    return preferredLayoutSize(target);
  }

  // -------------------------------------------------------------------------
  // Bean getters and setters
  // -------------------------------------------------------------------------

  /**
   * Returns the table header used to align component widths. If {@code null},
   * the components are hidden.
   * 
   * @return the table header &ndash; possibly {@code null}
   */
  public JTableHeader getTableHeader() {
    return tableHeader;
  }

  /**
   * Sets the table header used to align component widths. If {@code null},
   * the components are hidden.
   * 
   * @param tableHeader the tableHeader to set &ndash; possibly {@code null}
   */
  public void setTableHeader(JTableHeader tableHeader) {
    this.tableHeader = tableHeader;
  }

  // -------------------------------------------------------------------------
  // Inner classes
  // -------------------------------------------------------------------------

  /** Column constraints. */
  public static class Constraints implements java.io.Serializable {

    /** Serial version UID */
    private static final long serialVersionUID = 8449128772804052156L;

    /** The column index (view coordinates) */
    public final int columnIndex;

    /** The column span */
    public final int columnSpan;

    /**
     * Creates a new {@code Constraints} instance with a column span of
     * {@code 1}.
     * 
     * @param columnIndex the index of the column (view coordinates)
     */
    public Constraints(int columnIndex) {
      this(columnIndex, 1);
    }

    /**
     * Creates a new {@code Constraints} instance.
     * 
     * @param columnIndex the index of the column (view coordinates)
     * @param columnSpan the column span
     */
    public Constraints(int columnIndex, int columnSpan) {
      this.columnIndex = columnIndex;
      this.columnSpan = columnSpan;
    }

  }
}
Beispielanwendung
Und so könnte alles zusammenspielen.
Java:
public static void main(String[] args) {
  /* table without auto-added table header */
  final JTable table = new JTable(100, 10) {

    @Override
    protected void configureEnclosingScrollPane() {}
  };
  final JTableHeader th = table.getTableHeader();

  /* this panel contains the column labels */
  final JPanel labelPanel = new JPanel(new TableHeaderAdapterLayout(th));

  /* add a label */
  final JLabel label1 = new JLabel("2-4", SwingConstants.CENTER);
  label1.setBorder(new MatteBorder(new Insets(0, 0, 1, 0), Color.RED));
  labelPanel.add(label1, new TableHeaderAdapterLayout.Constraints(1, 3));

  /* add another label */
  final JLabel label2 = new JLabel("7-7", SwingConstants.CENTER);
  label2.setBorder(new MatteBorder(new Insets(0, 0, 1, 0), Color.BLACK));
  labelPanel.add(label2, new TableHeaderAdapterLayout.Constraints(6, 1));

  /* this panel contains the table header and the label panel */
  final JPanel headerPanel = new JPanel(new TableHeaderContainerLayout());
  headerPanel.add(labelPanel, BorderLayout.CENTER);
  headerPanel.add(th, BorderLayout.PAGE_END);

  /* create the scroll pane */
  final JScrollPane scrollPane = new JScrollPane(table);
  scrollPane.setColumnHeaderView(headerPanel);

  /* update the label panel's layout, whenever columns change */
  table.getColumnModel().addColumnModelListener(
        new TableColumnModelListener() {

          public void columnSelectionChanged(ListSelectionEvent e) {}

          public void columnMarginChanged(ChangeEvent e) {
            labelPanel.revalidate();
          }

          public void columnRemoved(TableColumnModelEvent e) {
            labelPanel.revalidate();
          }

          public void columnMoved(TableColumnModelEvent e) {
            labelPanel.revalidate();
          }

          public void columnAdded(TableColumnModelEvent e) {
            labelPanel.revalidate();
          }
        });

  /* show the test frame */
  final JFrame f = new JFrame("Test Frame: TableHeaderTest");
  f.setContentPane(scrollPane);
  f.pack();
  f.setLocationRelativeTo(null);
  f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  f.setVisible(true);
}
Screenshoot
voodoo table header.png
Ebenius
 
Zuletzt bearbeitet:

André Uhres

Top Contributor
Ich würde das Problem nicht per TableHeaderUI lösen. Daraus ergibt sich immer das Problem, dass das Aussehen der Komponenten sich nicht dem jeweiligen LookAndFeel anpassen.
Ich verstehe jetzt nicht genau, was du damit meinst. Das sind ja eigentlich nur JLabels. Insofern passen sie sich an jedes Laf an. Ausser vielleicht bei "Exoten", die das umgehen.
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Das TableHeaderUI ist für das LookAndFeel des Tabellenkopfes zuständig. Synthetica LookAndFeels (e.i. Nimbus) installieren per SynthTableHeaderUI einen eigenen CellRenderer für den Spaltenkopf. Das Windows LookAndFeel installiert ebenfalls per WindowsTableHeaderUI einen eigenen CellRenderer für den Spaltenkopf. Das GTK+-LookAndFeel verhält sich genauso. Einen Mac hab ich nicht zur Hand; ich gehe aber davon aus, das Mac L&F verhält sich ähnlich. Wenn man sein eigenes TableHeaderUI schreibt, dann bekommt man eben nicht mehr das vom L&F vorgegebene Aussehen der Spaltenköpfe. Deswegen: Eigenes UI
  • entweder gar nicht, oder
  • passend für ein bestimmtes LookAndFeel, oder
  • als delegierendes UI zum Original
implementieren.

Hier mal ein Screenshot ([SIZE="-1"]hab endlich mal das neue GroupLayout ausprobiert, juchuu[/SIZE]), der zeigt, wie die vier L&Fs auf meinem System mit jeweils LAF-Standard-TableHeaderUI und neu gesetztem BasicTableHeaderUI nebenander aussehen.
table header LaF tests.png

Ebenius
 

rik0

Mitglied
Bevor ich es mit dem eigenen TableHeader probiert habe, wollte ich meine Custom-Komponente als ColumnHeaderView der ScrollPane setzen. Das hat aber nicht geklappt, da immer der Header der enthaltenen JTable verwendet wurde.
In Ebenius' Lösung habe ich nun entdeckt, dass es an configureEnclosingScrollPane() liegt.
Wenn man sie leer überschreibt, funktioniert es. Jetzt klappts auch mit dem Column-Resize.

Also danke euch beiden für die Anregungen.

Hier noch ein lauffähiges Beispiel:

Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;


public class Main {

	public static void main(String[] args) {
		
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		Object[][] data = new Object[][]{{"11","12","13","14"},{"21","22","23","24"},{"31","32","33","34"},{"41","42","43","44"}};
		Object[] colNames = new Object[]{"A","B","C","D"};
		
		JTable tab = new JTable(data,colNames){			
			@Override
			protected void configureEnclosingScrollPane() {}			
		};
				
		JScrollPane sp = new JScrollPane(tab);
		sp.setColumnHeaderView(new myHeader(tab.getTableHeader()));
		sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
				
		JFrame frame = new JFrame();
		frame.setContentPane(sp);
		
		frame.setSize(800, 600);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLocationRelativeTo(null);
		frame.pack();
		
		frame.setVisible(true);
	}
	
	
	static class myHeader extends JPanel {
		
		JTableHeader defaultHeader;
		
		public myHeader(JTableHeader defaultHeader) {
			this.defaultHeader = defaultHeader;
			this.defaultHeader.setReorderingAllowed(false);
			
			this.defaultHeader.getColumnModel().addColumnModelListener(new TableColumnModelListener(){
				
				@Override
				public void columnAdded(TableColumnModelEvent e) {}

				@Override
				public void columnMarginChanged(ChangeEvent e) {
					myHeader.this.repaint();				
				}

				@Override
				public void columnMoved(TableColumnModelEvent e) {}

				@Override
				public void columnRemoved(TableColumnModelEvent e) {}

				@Override
				public void columnSelectionChanged(ListSelectionEvent e) {}
				
			});
			
			this.setPreferredSize(new Dimension(defaultHeader.getPreferredSize().width,50));
			
			GroupLayout gl = new GroupLayout(this);
			this.setLayout(gl);
			
			gl.setHorizontalGroup(gl.createSequentialGroup()
					.addComponent(defaultHeader));
			
			gl.setVerticalGroup(gl.createSequentialGroup()
					.addGap(0,0,Integer.MAX_VALUE)
					.addComponent(defaultHeader));
		}

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			
			TableColumnModel colModel = defaultHeader.getColumnModel();
			int markingStart = colModel.getColumn(0).getWidth();
			int markingWidth = colModel.getColumn(1).getWidth()+colModel.getColumn(2).getWidth();
			
			g.setFont(new Font(g.getFont().getName(),Font.BOLD,g.getFont().getSize()));			
			
			g.fillRect(markingStart, 20, markingWidth, 3);
			
			g.drawString("2 - 3", markingStart+markingWidth/2-g.getFontMetrics().stringWidth("2-3")/2, 14);

		}	
		
	}

}


PS: Ja, GroupLayout ist mein Favorit - inzwischen verwende ich es auch bei so einfachen Fällen wie diesem mit nur einer Komponente ;)
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Java:
static class myHeader extends JPanel {
Klassennamen in CamelCase, also MyHeader.
PS: Ja, GroupLayout ist mein Favorit - inzwischen verwende ich es auch bei so einfachen Fällen wie diesem mit nur einer Komponente ;)
Favoriten hab ich nicht. Ich benutze immer den LayoutManager der am besten passt. Der Grund warum ich mich so gefreut hatte: Das GroupLayout gefällt mir für einige Anwendungsbeispiele. Leider muss ich beruflich aber noch immer kompatibel zu Java 5 bleiben und kann es deswegen eigentlich gar nicht benutzen. :)

Ebenius
 

Ebenius

Top Contributor
Dafür gibt's auch eine extra Lib, falls du die einsetzen kannst oder willst:

https://swing-layout.dev.java.net/
Wusste ich schon und will eher nicht. :) Inzwischen (also in den letzten sechs Jahren :) ) hab ich LayoutManager selber gebaut wenn sich die Vorstellung nicht recht mit den Standards abbilden ließ. Hab auch viel gelernt und bin inzwischen ziemlich flink. Die Resultate können sich ebenfalls sehen lassen. Und ich baue nicht so gern eine 3pp-Bibliothek ein, wenn ich nur eine Klasse benötige, weil das die Applikationen zu sehr vergrößert und den Wartungsaufwand erhöht.

Trotzdem: Guter Hinweis für andere die das gleiche Problem wie ich haben. Danke!

Ebenius
 
Zuletzt bearbeitet:

André Uhres

Top Contributor
Java:
GroupLayout gl = new GroupLayout(this);
this.setLayout(gl);
gl.setHorizontalGroup(gl.createSequentialGroup()
		.addComponent(defaultHeader));
gl.setVerticalGroup(gl.createSequentialGroup()
		.addGap(0,0,Integer.MAX_VALUE)
		.addComponent(defaultHeader));
PS: Ja, GroupLayout ist mein Favorit - inzwischen verwende ich es auch bei so einfachen Fällen wie diesem mit nur einer Komponente ;)
GroupLayout finde nicht, gelinde gesagt, nicht gerade benutzerfreundlich (es sei denn, man überlässt die Arbeit einem GUI Builder Tool). Einfacher:
Java:
setLayout(new BorderLayout());
add(defaultHeader, BorderLayout.SOUTH);
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
P Swing Alle Zeilen einer Spalte (jTable) zusammen zählen und in eine eigene Zeile das Ergebnis schreiben. AWT, Swing, JavaFX & SWT 7
MrMilti eigene Klasse in JTable ablegen AWT, Swing, JavaFX & SWT 12
M JTable mit JCombobox eigene Auswahl pro Zeile ? AWT, Swing, JavaFX & SWT 3
J Drag und drop aus einer JTable - bitte um Unterstützung AWT, Swing, JavaFX & SWT 2
S HPRO und UPRO gemeinsame JTABLE gemeinsamer RENDERER ? AWT, Swing, JavaFX & SWT 1
F Swing JTable - MultiHeader inkl. Eingabemöglichkeit AWT, Swing, JavaFX & SWT 1
S JTable - Feldinhalte anzeigen AWT, Swing, JavaFX & SWT 15
D Swing JTable Spaltenbreite AWT, Swing, JavaFX & SWT 1
W Gibt es einen "automatischen Listener" in Swing oder JTable oder der ATM-Klasse? AWT, Swing, JavaFX & SWT 14
G jTable - getSelectedRow() AWT, Swing, JavaFX & SWT 3
I JTable mit einem Button zu einer Detail Seite springen AWT, Swing, JavaFX & SWT 4
P JTable Listener für die Änderung einzelner Zellen oder Rows AWT, Swing, JavaFX & SWT 2
D Tastaturabfragen CTRL+t, CTRL+E bei eine JTable, bestehend aus JTextAteas AWT, Swing, JavaFX & SWT 4
P Checkboxes in JTable nicht editable AWT, Swing, JavaFX & SWT 9
F Best-Practise: JTable Text in Zelle zu groß AWT, Swing, JavaFX & SWT 2
izoards JTable in CSV File schreiben... AWT, Swing, JavaFX & SWT 23
Kohl Jedes Objekt einer JTable um ein Zeichen verkürzen AWT, Swing, JavaFX & SWT 7
I JTable, DefaultTableModel, zwei Zahlen multiplizieren. AWT, Swing, JavaFX & SWT 26
M JTABLE / wie oft wurde gewürfelt. AWT, Swing, JavaFX & SWT 1
F JTable vergrößern AWT, Swing, JavaFX & SWT 2
H JTable: Diverse NullPointer-Exceptions zur Laufzeit AWT, Swing, JavaFX & SWT 3
J Swing Werte des JTable werden nicht angezeigt AWT, Swing, JavaFX & SWT 9
T Swing JTable cellRenderer mit jpg Hintergrundfarbe lässt sich nicht ändern. AWT, Swing, JavaFX & SWT 1
HoT Einzelne Zelle in JTable Rahmen unten setzen AWT, Swing, JavaFX & SWT 24
B JTable Zellen zusammenfügen AWT, Swing, JavaFX & SWT 3
M Swing Cell Renderer für Zeilenumbruch in JTable AWT, Swing, JavaFX & SWT 0
H JTable im JSplitPane darstellen AWT, Swing, JavaFX & SWT 2
MadMax2506 Swing JTable lädt sehr lange AWT, Swing, JavaFX & SWT 1
D Zeilenumbruch in einer JTable AWT, Swing, JavaFX & SWT 9
R Swing JTable und Spaltenausrichtung AWT, Swing, JavaFX & SWT 8
G JTable füllen AWT, Swing, JavaFX & SWT 1
H JTable TableCellEditor-Problem AWT, Swing, JavaFX & SWT 0
W Swing JTable Zeilenumbruch innerhalb einer Zelle AWT, Swing, JavaFX & SWT 3
J Datensatz in jTable ausgeben AWT, Swing, JavaFX & SWT 3
M Swing Automatischer Editorstart in JTable-Zelle AWT, Swing, JavaFX & SWT 5
ralfb1105 Swing JTable aktualisieren AWT, Swing, JavaFX & SWT 5
adiko01 JTable: Nur markierte Zeilen aus der Tabelle in CSV exportiern AWT, Swing, JavaFX & SWT 9
M JTable.setDefaultRenderer(...) greift nicht AWT, Swing, JavaFX & SWT 0
J JTable: Eingabe in Tabellenzelle korrigieren AWT, Swing, JavaFX & SWT 4
T Problem mit JTable Sortierung AWT, Swing, JavaFX & SWT 2
D JTable nach INSERT aktualisieren /refreshen AWT, Swing, JavaFX & SWT 1
D MySQL Daten in JTable anzeigen AWT, Swing, JavaFX & SWT 2
H Swing Jtable extra spalte AWT, Swing, JavaFX & SWT 6
S Swing Rechteck über JTable zeichnen (per MouseListener) AWT, Swing, JavaFX & SWT 1
S Swing Mal wieder JTable Ansicht aktualisieren AWT, Swing, JavaFX & SWT 10
A JTable mit Daten füllen AWT, Swing, JavaFX & SWT 1
VfL_Freak Swing Einzelne Zeile in jTable selektieren klappt nicht AWT, Swing, JavaFX & SWT 7
N AWT jTable CellRenderer AWT, Swing, JavaFX & SWT 6
T Swing JTable valueChanged datensatz löschen AWT, Swing, JavaFX & SWT 1
0 Swing JTable aus anderer Klasse updaten AWT, Swing, JavaFX & SWT 5
S Jtable defaultRenderer wohin damit ? AWT, Swing, JavaFX & SWT 23
T Swing JTable / FocusListener AWT, Swing, JavaFX & SWT 0
it_is_all Warum wird die JTable im JDialog nicht angezeigt? AWT, Swing, JavaFX & SWT 1
L Swing JTable im Panel darstellen AWT, Swing, JavaFX & SWT 8
T Swing Double Click bei Buttons in JTable AWT, Swing, JavaFX & SWT 9
J addRow bei JTable AWT, Swing, JavaFX & SWT 6
M Jtable gibt -1 wert bei selectedRow und Column AWT, Swing, JavaFX & SWT 3
Meeresgott Swing JTable AWT, Swing, JavaFX & SWT 4
J JTable Selection Listener funktioniert nicht AWT, Swing, JavaFX & SWT 4
C Swing Daten in JTable wiedergeben per TableModel und MVC Pattern AWT, Swing, JavaFX & SWT 16
Z Swing Drag&Drop zwischen JTable und JTree AWT, Swing, JavaFX & SWT 4
Thallius JTable dynamisch Spaltenanzahl verändern AWT, Swing, JavaFX & SWT 2
Thallius JTable dynamisch laden? AWT, Swing, JavaFX & SWT 2
B Swing JTable sortieren AWT, Swing, JavaFX & SWT 2
T Swing JTable auslesen und befüllen AWT, Swing, JavaFX & SWT 8
B JTable wird nicht angezeigt AWT, Swing, JavaFX & SWT 1
J JTable und Suchlogik AWT, Swing, JavaFX & SWT 4
Viktim Swing JTable mit Tab verlassen AWT, Swing, JavaFX & SWT 1
F Swing Spaltenbreite einer Column eines JTable auslesen AWT, Swing, JavaFX & SWT 5
Viktim Swing JTable Mit Tab druch Zeilen Wechseln AWT, Swing, JavaFX & SWT 5
Thallius Warum refrehsed mein JTable nicht? AWT, Swing, JavaFX & SWT 5
Ghostman1711 Hinzufügen ausgewählter Dateinen des Filechoosers zu einem JTable AWT, Swing, JavaFX & SWT 9
S Swing JTable - Einzelne Rows einfärben AWT, Swing, JavaFX & SWT 11
M Wert einer Zelle aus JTable ziehen AWT, Swing, JavaFX & SWT 4
K JTable getValueAt() klappt nicht immer AWT, Swing, JavaFX & SWT 1
K JTable in extra Klasse, Zugriff in einer anderen klasse nicht möglich AWT, Swing, JavaFX & SWT 26
B Swing Tabelle(JTable) filtern swing GUI AWT, Swing, JavaFX & SWT 3
P JTable - bei Eingabe Selektion AWT, Swing, JavaFX & SWT 0
P Fokus auf Zelle in JTable AWT, Swing, JavaFX & SWT 1
S Swing Deselektion in JTable verhindern AWT, Swing, JavaFX & SWT 0
D Problem mit JTable AWT, Swing, JavaFX & SWT 1
N Swing Print JTable mit AbstractTableModel AWT, Swing, JavaFX & SWT 1
Ananaskirsche Swing jTable Reihen zuviel eingefügt AWT, Swing, JavaFX & SWT 12
P im JTable die Schriftfarbe ändern AWT, Swing, JavaFX & SWT 19
T Swing JTable wird nicht angezeigt AWT, Swing, JavaFX & SWT 4
S Dreiecke in bestimmte Zellen einer JTable AWT, Swing, JavaFX & SWT 9
LexeB4F Zelle in JTable gezielt einfärben AWT, Swing, JavaFX & SWT 4
LexeB4F JTable mehrere Zelle selektieren und inhalte Löschen.. Ideen gesucht AWT, Swing, JavaFX & SWT 1
D Swing JTable Renderer Grafikfehler AWT, Swing, JavaFX & SWT 0
K Swing JTable mit ImageIcon und Text in einer Zelle AWT, Swing, JavaFX & SWT 1
M Swing JTable GroupableHeader Background Color AWT, Swing, JavaFX & SWT 4
K Swing JTable updaten AWT, Swing, JavaFX & SWT 9
thet1983 Swing MySQL >> JTable AWT, Swing, JavaFX & SWT 5
J JTable bounds ändern durch resizing des Fensters AWT, Swing, JavaFX & SWT 9
F JTable Zellen-Hintergrund ändern AWT, Swing, JavaFX & SWT 7
O JTable linksbündig drucken (nicht der Zelleninhalt) AWT, Swing, JavaFX & SWT 2
Crazynet xls Datei in JTable AWT, Swing, JavaFX & SWT 3
O JTable ohne Rahmen printen AWT, Swing, JavaFX & SWT 3
L Swing JTable refresht die Column Namen nicht AWT, Swing, JavaFX & SWT 0
K JTable komplett durch andere ersetzen AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben