# JScrollbar + JTable + Zeilen wie in Excel hinzufügen



## MathiasBauer (12. Mai 2008)

Hallo,

Teile meines Problems habe ich schon unter folgenden Beiträgen gepostet:

www.java-forum.org/de/topic68160_listener-button-auf-jscrollbar.html
java-forum.org/de/viewtopic.php?t=68364&highlight=
java-forum.org/de/viewtopic.php?t=68644&highlight=

Jetzt habe aber noch zwei Probleme:

1. Leider komme ich nicht ohne 
	
	
	
	





```
final JButton b0 = (JButton)bar.getAccessibleContext().getAccessibleChild(0);
```
 aus. Das soll aber ein Hack sein, den man nicht verwenden soll!!!

2. Folgende Rechnung stimmt bei mir nicht (nur am Anfang stimmt sie, später nicht mehr):


```
if(bar.getValue()==bar.getMaximum()-bar.getVisibleAmount()){
```

Damit man sich besser ein Bild machen kann, habe ich mein Problem zu einem zusammenhängenden Code zusammengestückelt:


```
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;


public class JScrollBarTest extends JFrame implements Runnable{
	private static boolean isPressed=false;
	private static JScrollBar bar;
	private static DefaultTableModel model;
	private static JScrollPane scrollPane;
	
	
	public void run() {
		while(isPressed){
			try {
				Thread.sleep(50);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			System.out.println("MouseDown");
			System.out.println("Value vor:"+bar.getValue());
			System.out.println("max vor:"+bar.getMaximum());
			System.out.println("visibleAmount vor:"+bar.getVisibleAmount());
			if(bar.getValue()==bar.getMaximum()-bar.getVisibleAmount()){
				System.out.println("Value in:"+bar.getValue());
				System.out.println("visibleAmount in:"+bar.getVisibleAmount());
				System.out.println("max in:"+bar.getMaximum());
				Vector newDatas = createRow(false,"test","test","test","test","test");
				model.addRow( newDatas ); 
				scrollPane.validate();		
				bar.setMaximum(bar.getMaximum());
				bar.setValue(bar.getMaximum());
				try {
					Thread.sleep(50);
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String args[]){
		JScrollBarTest scrollbar = new JScrollBarTest();
		scrollbar.setSize(400,400);
		scrollbar.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JTable table = new JTable();
		String[] titles = new String[]{ "", "Name", "Vorname", "Strasse", "PLZ", "Ort"}; 
		model = new TableModelDefault(titles, 41); 
		table.setModel( model ); 
		scrollPane= new JScrollPane(table);
		scrollbar.getContentPane().add(scrollPane, BorderLayout.CENTER);
		scrollbar.setVisible(true);
		
		bar = scrollPane.getVerticalScrollBar();
		final JButton b0 = (JButton)bar.getAccessibleContext().getAccessibleChild(0);
		b0.addMouseListener(new MouseListener(){

			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub

			}

			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub
			}

			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub
			}

			public void mousePressed(MouseEvent e) {
				isPressed=true;
				new Thread(new JScrollBarTest()).start();
			}

			public void mouseReleased(MouseEvent e) {
				isPressed=false;
				System.out.println("MouseUp");
			}
		});	
	}
	
	public static Vector createRow(Boolean selected, String name, String vorname, String strasse, String plz, String ort){
		Vector vector = new Vector();
		vector.add(selected);
		vector.add(name);
		vector.add(vorname);
		vector.add(strasse);
		vector.add(plz);
		vector.add(ort);
		return vector;
	} 	
}

class TableModelDefault extends DefaultTableModel{
	
	public TableModelDefault(String[]titles, int rowSize){
		super(titles, rowSize);
	}
	
	public TableModelDefault(){
		super();
	}

	public Class getColumnClass(int columnIndex) {
		switch( columnIndex ){
		case 0: return Boolean.class;
		case 1: return String.class;
		case 2: return String.class;
		case 3: return String.class;
		case 4: return String.class;
		case 5: return String.class;
		case 6: return String.class;
		case 7: return String.class;
		default: return null;
		}  
	}
}
```

Vielen Dank im Voraus.


----------



## Marco13 (12. Mai 2008)

Ich will dich ja nicht desillusionieren oder demotivieren, aber ... sieh' das folgende einfach als Tipp an, der ganz unverbindlich ist, und nur meine subjektive Meinung widerspiegelt: 

Lass' es einfach bleiben. Mach' da nen Scheiß-Button in die Ecke, wo draufsteht: "Add a new Line", und hör auf, deine Zeit zu verschwenden mit irgendwelchen Accessibles und verqueren Listenern, die irgendwelche abstusen Threads starten und versuchen aus irgendwelchen Layout-Spezifika und visiblen amounts irgendwas zu berechnen, und etwas zu machen, wovon nichmal klar ist, ob der Benutzer das will (und bei dem noch weniger klar ist, wie er das ganze wieder rückgängig macht - außer mit einem "Remove last line"-Button). 

Wie gesagt, ist nur ein gut gemeinter Ratschlag. Du murkst da jetzt schon seit einiges Zeit dran rum, also entweder ist dir sehr langweilig, oder du hast nichts besseres zu tun, oder das ist SO wichtig, dass ich nich umhinkommen würde, zu fragen, warum es denn nun genau so sein muss.


----------



## Marco13 (12. Mai 2008)

Abgesehen davon hatte ich, für den Fall, dass du wenigstens auf das kontinuierliche Hinzufügen neuer Zeilen, wenn man den Button gedrückt hält, verzichten kannst, schon einen Lösungsansatz gepostet

```
// [url]http://www.java-forum.org/de/viewtopic.php?t=69186&highlight=&sid=a34cc8f7bbcc1bc2015fa94e063ce9f9[/url]
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;


public class JScrollBarTest2 extends JFrame {
   private static boolean isPressed=false;
   private static JScrollBar bar;
   private static DefaultTableModel model;
   private static JScrollPane scrollPane;


   public static void main(String args[]){
      final JScrollBarTest2 scrollbar = new JScrollBarTest2();
      scrollbar.setSize(400,400);
      scrollbar.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      JTable table = new JTable();
      String[] titles = new String[]{ "", "Name", "Vorname", "Strasse", "PLZ", "Ort"};
      model = new TableModelDefault(titles, 41);
      table.setModel( model );
      scrollPane= new JScrollPane(table);
      scrollbar.getContentPane().add(scrollPane, BorderLayout.CENTER);
      scrollbar.setVisible(true);

      bar = scrollPane.getVerticalScrollBar();
      BoundedRangeModel brm = new DefaultBoundedRangeModel(bar.getValue(), bar.getModel().getExtent(), bar.getMinimum(), bar.getMaximum())
      {
          public void setValue(int value)
          {
              if (value > getMaximum()-getExtent())
              {
                Vector newDatas = createRow(false,"test","test","test","test","test");
                model.addRow(newDatas);
                scrollPane.validate();
                super.setValue(getMaximum()-getExtent());
              }
              else
              {
                  super.setValue(value);
              }
          }
      };
      bar.setModel(brm);
   }

   public static Vector createRow(Boolean selected, String name, String vorname, String strasse, String plz, String ort){
      Vector vector = new Vector();
      vector.add(selected);
      vector.add(name);
      vector.add(vorname);
      vector.add(strasse);
      vector.add(plz);
      vector.add(ort);
      return vector;
   }
}

class TableModelDefault extends DefaultTableModel{

   public TableModelDefault(String[]titles, int rowSize){
      super(titles, rowSize);
   }

   public TableModelDefault(){
      super();
   }

   public Class getColumnClass(int columnIndex) {
      switch( columnIndex ){
      case 0: return Boolean.class;
      case 1: return String.class;
      case 2: return String.class;
      case 3: return String.class;
      case 4: return String.class;
      case 5: return String.class;
      case 6: return String.class;
      case 7: return String.class;
      default: return null;
      }
   }
}
```


----------



## MathiasBauer (12. Mai 2008)

Ich habe deinen Lösungsansatz auch ausprobiert, aber ich kann auf das kontinuierliche Hinzufügen nicht verzichten, da es  irgendwie funktionieren muss. In Excel geht es ja auch...


----------



## André Uhres (13. Mai 2008)

MathiasBauer hat gesagt.:
			
		

> ich kann auf das kontinuierliche Hinzufügen nicht verzichten


Versuch's mal mit einem AdjustmentListener. Beispiel:

EDIT 18.05.2008: Ich hab den Code jetzt nochmal angepasst, gemäss den folgenden Beiträgen vom 13.05.2008.


```
package demo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class DynamicRows extends JFrame implements AdjustmentListener {
    private JScrollPane jScrollPane1;
    private JTable jTable1;
    private DefaultTableModel model;
    private int yVisible, yVisibleOld;
    private boolean valueIsAdjusting;
    public DynamicRows() {
        super("DynamicRows");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400, 300);
        setLocationRelativeTo(null);
        jScrollPane1 = new JScrollPane();
        jTable1 = new JTable();
        jTable1.setModel(new DefaultTableModel(
                new Object[][]{},
                new String[]{
                    "Title 1", "Title 2", "Title 3", "Title 4"
                }));
        jScrollPane1.setViewportView(jTable1);
        getContentPane().add(jScrollPane1, BorderLayout.CENTER);
        model = (DefaultTableModel) jTable1.getModel();
        for (int i = 0; i < 20; i++) {
            model.addRow(new Object[]{null, null, null, null});

        }
        jScrollPane1.getVerticalScrollBar().addAdjustmentListener(this);
    }
    public void adjustmentValueChanged(final AdjustmentEvent e) {
        if(e.getValueIsAdjusting()){
            valueIsAdjusting = true;
            return ;
        }
        Adjustable a = e.getAdjustable();
        Rectangle rectBottom = jTable1.getCellRect(model.getRowCount() - 1, 0, true);
        int yBottom = rectBottom.y + rectBottom.height;
        Rectangle rectVisible = jTable1.getVisibleRect();
        yVisible = rectVisible.y + rectVisible.height;
        //if we are scrolling upwards:
        if (yVisible != 0 && yVisible < yVisibleOld) {
            //remove all invisible rows if they area empty (from bottom to top):
            boolean remove = true;
            for (int row = jTable1.getRowCount() - 1; row > -1; row--) {
                if (jTable1.getCellRect(row, 0, true).y > yVisible) {//if row is invisible
                    for (int column = 0; column < jTable1.getColumnCount(); column++) {
                        Object value = jTable1.getValueAt(row, column);
                        if (value != null) {//if the row is not empty
                            remove = false;//do not remove any more rows
                        }
                    }
                    if (remove) {
                        model.removeRow(row);
                    }
                }
            }
        } else {
            //here we are scrolling downwards
            //if visible area is at bottom:
            if (yVisible > yBottom - 5 && yVisible < yBottom + 5) {
                a.removeAdjustmentListener(this);
                //add new row and scroll to visible:
                if (valueIsAdjusting) {
                    valueIsAdjusting = false;
                    rectVisible.y = rectVisible.y - 2;
                    yVisible = yVisible - 2;
                    jTable1.scrollRectToVisible(rectVisible);
                }else{
                    model.addRow(new Object[]{null, null, null, null});
                    rectBottom = jTable1.getCellRect(model.getRowCount() - 1, 0, true);
                    rectBottom.height = rectBottom.height - 5;
                    jTable1.scrollRectToVisible(rectBottom);
                }
                a.addAdjustmentListener(this);
            }
        }
        yVisibleOld = yVisible;
    }
    public static void main(final String args[]) {
        EventQueue.invokeLater(new 
              Runnable() {
                 public void run() {
                new DynamicRows().setVisible(true);
            }
        });
    }
}
```


----------



## MathiasBauer (13. Mai 2008)

Genial!!!! Danke !!!


----------



## MathiasBauer (13. Mai 2008)

So ganz funktioniert es leider doch nicht... 
Es dürfen nur neue Zeilen bei Buttondruck hinzugefügt oder gelöscht werden. Aber so kommt es schon ziemlich nahe an Excel ran...


----------



## Tobias (13. Mai 2008)

Von JScrollBar eine neue Klasse ableiten, die bei Buttondruck einen Event rausschickt. Diese Unterklasse als VerticalScrollBar an der ScrollPane registrieren. Wie man die JScrollBar überschreiben muss, damit sie einen Event rausschickt, wenn der Button gedrückt, aber nicht, wenn der "Knob" bewegt wird, weiß ich nicht. Mußt du selber rauskriegen. Wird am ehesten durch Codestudium von JScrollBar rauszufinden sein.

mpG
Tobias


----------



## André Uhres (13. Mai 2008)

MathiasBauer hat gesagt.:
			
		

> Es dürfen nur neue Zeilen bei Buttondruck hinzugefügt oder gelöscht werden. Aber so kommt es schon ziemlich nahe an Excel ran...


Bei Excel 2000 werden *immer *neue Zeilen beim Scrollen hinzugefügt oder gelöscht, egal auf welche Art man scrollt
(z.B. mit Mausrad, mit den Pfeiltasten, usw.). Die einzige Ausnahme ist, 
wenn man den senkrechten Schieber direkt mit der Maus verschiebt:
man muss also lediglich diesen Fall ausklammern.


----------



## MathiasBauer (13. Mai 2008)

Genau. Und um diesen Fall ausklammern zu können, muss ich leider an die Buttons ran...


----------



## Marco13 (13. Mai 2008)

Nein. DAS geht Ansatzweise mit 

        JScrollBar b = (JScrollBar)e.getAdjustable();
        if (b.getValueIsAdjusting()) return;

EINE Zeile wird dann zwar doch immer eingefügt, aber das kannst du bestimmt noch irgendwie raushacken.


----------



## MathiasBauer (15. Mai 2008)

Danke!


----------



## André Uhres (18. Mai 2008)

Hab's jetzt in meinem Code oben angepasst :wink:


----------



## MathiasBauer (18. Mai 2008)

Klasse!!!! Von der Funktionalität geht alles! Leider ruckelt es, wenn man den Button "nach oben" drückt.


----------



## MathiasBauer (18. Mai 2008)

So geht es jetzt bei mir:



```
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.table.*;
public class DynamicRows extends JFrame implements AdjustmentListener {
	private JScrollPane jScrollPane1;
	private JTable jTable1;
	private DefaultTableModel model;
	private int yVisible, yVisibleOld;
	private boolean valueIsAdjusting = false;
	public DynamicRows() {
		super("DynamicRows");
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setSize(400, 300);
		setLocationRelativeTo(null);
		jScrollPane1 = new JScrollPane();
		jTable1 = new JTable();
		jTable1.setModel(new DefaultTableModel(
				new Object[][]{},
				new String[]{
						"Title 1", "Title 2", "Title 3", "Title 4"
				}));
		jScrollPane1.setViewportView(jTable1);
		getContentPane().add(jScrollPane1, BorderLayout.CENTER);
		model = (DefaultTableModel) jTable1.getModel();
		for (int i = 0; i < 20; i++) {
			model.addRow(new Object[]{null, null, null, null});

		}

		jScrollPane1.getVerticalScrollBar().addAdjustmentListener(this);
	}
	public void adjustmentValueChanged(final AdjustmentEvent e) {
		if(e.getValueIsAdjusting()){
			valueIsAdjusting = true;
			return ;
		}
		Adjustable a = e.getAdjustable();
		Rectangle rectBottom = jTable1.getCellRect(model.getRowCount()-1, 0, true);
		int yBottom = rectBottom.y + rectBottom.height;
		Rectangle rectVisible = jTable1.getVisibleRect();
		yVisible = rectVisible.y + rectVisible.height;
		//if we are scrolling upwards:
		if (yVisible != 0 && yVisible < yVisibleOld) {
			//remove all invisible rows if they area empty (from bottom to top):
			boolean remove = true;
			for (int row = jTable1.getRowCount() - 1; row > -1; row--) {
				if (jTable1.getCellRect(row, 0, true).y > yVisible) {//if row is invisible
					for (int column = 0; column < jTable1.getColumnCount(); column++) {
						Object value = jTable1.getValueAt(row, column);
						if (value != null) {//if the row is not empty
							remove = false;//do not remove any more rows
						}
					}
					if (remove) {
						model.removeRow(row);
					}
				}
			}
		} else {
			//here we are scrolling downwards
			//if visible area is at bottom:
			if ((yBottom == yVisible)) {
				if(valueIsAdjusting){
					valueIsAdjusting = false;
					rectVisible.y = rectVisible.y - 2;
					yVisible = yVisible - 2;
					jTable1.scrollRectToVisible(rectVisible);
				}
				else{
					a.removeAdjustmentListener(this);
					//add new row and scroll to visible:
					model.addRow(new Object[]{null, null, null, null});
					rectBottom = jTable1.getCellRect(model.getRowCount() - 1, 0, true);
					rectBottom.height = rectBottom.height - 1;
					jTable1.scrollRectToVisible(rectBottom);
					a.addAdjustmentListener(this);
				}
			}
		}
		yVisibleOld = yVisible;

	}
	public static void main(final String args[]) {
		EventQueue.invokeLater(new 
				Runnable() {
			public void run() {
				new DynamicRows().setVisible(true);
			}
		});
	}
}
```


----------

