Button "schubsen" und weitersliden lassen

Looky

Erfahrenes Mitglied
Moin,

ok, mal eine Frage. Ich möchte (nur um zu gucken obs geht) ein ähnlichesn Feature nachcoden wie das IPhone bei der Kontaktverwaltung hat. D.h je nachdem wie flot ihr den Finger auf dem Touchpad nach oben oder unten gezogen habt, desto schneller oder langsammer slided die Liste der Kontakte.

Im Prinzip will ich nun einfach nur einen Button, den ich ziehe und der Von den Kanten des JFrames abprallt. Und das je nach geschwindigkeit meiner Mausbewegung (bis ich den Button wieder loslasse) entsprechend schnell oder langsam.

Im Grunde müsste das doch mit ein wenig Mathe machbar sein oder seh ich das falsch? Kennt ihr bereits Applikationen, die soetwas nutzen?

Christian
 
Also ich kenne keine die das nutzen, allerdings ist es wirklich recht einfach machbar. Einfach einen MouseListener anmelden, beim onClick Position und Zeit merken und gleiches beim loslassen. Dann die Geschwindigkeit aus Strecke und Zeit berechnen und den Button entsprechend in dieser Geschwindigkeit fliegen lassen.
 
mhm ich bin grad mal etwas dabei, da das ein nettes feature für unsere applikation wäre. Ich stecke nämlich gerade in einem Subproject, wo ich mit eineigen Mitentwicklern die suchergebnissseite einer GoogleSuche so anpassen muss, dass diese auch scrollbar ist.

Angedacht habe ich nun testweise, die Suche statt über unser Webfrontend direkt über ein Applet abzuwickeln, mir ein eigens TableModel zu schreiben und die ergebnisse damit dann zu scrollen.

Aber dieses dämliche TableModel will nicht wie ich will. Das shit Teil flackert wie wild, obwohl doublebuffering an ist.. Naja, Java ist zwar nur ein Mittel zum Zweck für mich, aber das muss irgendwie gehen *grrr*

Meld mich wenn ich's hab.

Chriz
 
Tabellen sind leider nicht so wirklich einfach zu benutzen... das stelle ich auch immer wieder fest.

Schau mal ob du zu oft was aktualisierst und der deswegen zu oft neuzeichnet oder sowas.

Viel Glück auf jeden Fall ;)
 
So leute, ich bin nun soweit durch. Nach langem suchen habe ich festgestellt, dass das flackern an Java 5 liegt. Installiert man Java 6, funktioniert das ganze ziemlich smooth ohne flackern, Also wenn ihr das testen wollt, macht es mit Java 6.

Hier nun also das was ich mir zusammen programmiert habe. (Java ist ein Mittel zum Zweck für mich, nicht vergessen, wenn jemand erkennt das etwas schöner geht, konstruktive Kritik ist gerne gesehen)

Wenn ihr das Beispiel kompiliert werdet ihr eine Tabelle sehen. Da kann man einfach in die Tabelle reinklicken und dann die Maus nach oben schubsen und die Taste wieder loslassen. und schon slided das Teil..

HF

Java:
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * Test if iPhone effect works also for google spreed api, so that developer can use that.
 * 
 * @author Christian
 *
 */
public class Sandbox extends JFrame{

	JTable table = new JTable();
	JScrollPane sp = null;
	DefaultTableModel model = null;
	int cnt = 0;
	int y = -1;
	
	long time1 = 0;
	int ypos = 0;
	Thread t = null;
	
	static int velocity;

	public Sandbox(){
		this.setSize(800, 600);
		this.setLayout(new BorderLayout());
		this.addWindowListener(new WindowAdapter(){@Override
		public void windowClosing(WindowEvent arg0) {
				System.exit(0);
		}});
		
		model = new DefaultTableModel(){
			@Override
		public boolean isCellEditable(int row, int column) {
			return false;
		}};
		
		table.setRowSelectionAllowed(false);
		
	    String[] columnNames =  { 
		        "Testspalte 1", "Testspalte 2", "Testspalte 3", "Testspalte 4" 
		    }; 
		    model.setColumnIdentifiers(columnNames);
		    table.setModel(model);
		
		    fillTable();
		    
		    table.addMouseListener(new MouseAdapter(){@Override
		    public void mouseClicked(MouseEvent arg0) {
		    	if(arg0.getClickCount()==2){
		    		JOptionPane.showMessageDialog(null, "Row click!\n\nRownum: "+table.rowAtPoint( arg0.getPoint())+"\n\nValue of first cell: "+model.getValueAt(table.rowAtPoint( arg0.getPoint()),0),"Information", JOptionPane.INFORMATION_MESSAGE);
		    	}
		    }
		    	@Override
		    	public void mouseReleased(final MouseEvent e) {
		    		int tmp = 0;
		    			tmp = (ypos-e.getY());
		    		if(tmp<0)
		    			tmp = (e.getY()-ypos);
		    		
		    		if(tmp>10){
		    			/**
		    			 * Geschwindigkeit = ((Weg * Konstante (120)) / Zeit)
		    			 */
		    			velocity = (tmp*120)/((int)(System.currentTimeMillis()-time1));

		    		t = new Thread(){
		    			long l = System.currentTimeMillis();;
		    			int direction = -1;//Up or down...
		    			public void run(){
		    				int steps = 10;
		    				if((ypos-e.getY())<0){
		    					direction = 0;//up
		    				}else
		    					direction = 1; //down
		    				
		    				if(velocity>100)//if your finger (or mouse) was to quick, give em more steps to work with
		    					steps = 18;
		    				
		    				while(!Thread.currentThread().isInterrupted()){
		    					try {
		    						if((System.currentTimeMillis()-l)>velocity){
		    							l = System.currentTimeMillis();
		    							Thread.sleep(5);
		    		
		    						}
		    								velocity-=1;
		    								if(steps>0 && velocity%25==0){
		    									steps-=1;
		    								}
		    						
		    						scrollTable(cnt);
		    						if(direction==0){
		    							if(cnt>0)
		    								cnt-=steps;
		    						
		    						}else{
		    							cnt+=steps;
		    						}
		    						if(steps == 0)
		    							return;
		    					} catch (InterruptedException e2) {
		    						Thread.currentThread().interrupt();
		    					};
		    				}
		    			}
		    		};
		    		t.setPriority(Thread.MIN_PRIORITY);
		    		t.start();
		    		}
		    	}
		    @Override
		    public void mousePressed(MouseEvent arg0) {
		    	if(t!=null)
		    	t.interrupt();
		    	y = -1;
		    	ypos = arg0.getY();
		    	time1 = System.currentTimeMillis();
		    }}
		    
		    );
		    table.addMouseMotionListener(new MouseMotionAdapter(){
		    	
		    public void mouseDragged(MouseEvent e) {
		    	if(y==-1){
		    		cnt++;
		    		y = e.getY();
		    	}else{
		    		if(y < e.getY()){
		    			if(cnt>0)
		    				cnt-=5;
		    		}else
		    			cnt+=5;
		    	}
		    	scrollTable(cnt);
		    	
		    }});
		    sp = new JScrollPane(table);
		    sp.setDoubleBuffered(true);
		    table.setDoubleBuffered(true);
		    this.add(sp, BorderLayout.CENTER);
	}
	
	private void fillTable(){
		for(int i=0;i<10000;i++){
			model.addRow(new String[]{"Entry "+i,"Entry "+i, "Entry "+i, "Entry "+i});
		}
	}
	
	private void scrollTable(int value){
		try{
			sp.getVerticalScrollBar().setValue(value);
		}catch(Exception e){
			//Bugfix
		}
	}
	
	public static void main(String[] args){
		new Sandbox().setVisible(true);
	}
	
	
}
 
Zuletzt bearbeitet:
Kompiliert nicht ganz: Sandbox != Sandkasten ;) Und warum ist velocity static?

Aber sonst sehr schick. Für nen einfachen Test auf jeden Fall ausreichend.

Ist das okay für dich, dass im Javadoc der Klasse doch eher private Sachen hier im Forum auftauchen?
 
mhm, warum static.. gute frage...

und mit dem javadoc, du hast recht, hab ich gar nicht dran gedacht ;) Hier, habe noch eine kleinigkeit am Code geändert...

Fällt dir / euch bei der Berechnung irgendwas auf, was verbesserungswürdig ist?

Java:
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * This class is just for testing purpose only! It's not ready to implement that in any working project so.. fuck that ;)
 * 
 * @author Christian
 *
 */
public class Sandbox extends JFrame{

	JTable table = new JTable();
	JScrollPane sp = null;
	DefaultTableModel model = null;
	int cnt = 0;
	int y = -1;
	
	long time1 = 0;
	int ypos = 0;
	Thread t = null;
	
	int velocity;

	public Sandbox(){
		this.setSize(800, 600);
		this.setLayout(new BorderLayout());
		this.addWindowListener(new WindowAdapter(){@Override
		public void windowClosing(WindowEvent arg0) {
				System.exit(0);
		}});
		
		model = new DefaultTableModel(){
			@Override
		public boolean isCellEditable(int row, int column) {
			return false;
		}};
		
		table.setRowSelectionAllowed(false);
		
	    String[] columnNames =  { 
		        "Testspalte 1", "Testspalte 2", "Testspalte 3", "Testspalte 4" 
		    }; 
		    model.setColumnIdentifiers(columnNames);
		    table.setModel(model);
		
		    fillTable();
		    
		    table.addMouseListener(new MouseAdapter(){@Override
		    public void mouseClicked(MouseEvent arg0) {
		    	if(arg0.getClickCount()==2){
		    		JOptionPane.showMessageDialog(null, "Row click!\n\nRownum: "+table.rowAtPoint( arg0.getPoint())+"\n\nValue of first cell: "+model.getValueAt(table.rowAtPoint( arg0.getPoint()),0),"Information", JOptionPane.INFORMATION_MESSAGE);
		    	}
		    }
		    	@Override
		    	public void mouseReleased(final MouseEvent e) {
		    		int tmp = 0;
		    			tmp = (ypos-e.getY());
		    		if(tmp<0)
		    			tmp = (e.getY()-ypos);
		    		
		    		
		    		if((tmp*120)/((int)(System.currentTimeMillis()-time1))>30){
		    			/**
		    			 * Geschwindigkeit = ((Weg * Konstante (120)) / Zeit)
		    			 */
		    			velocity = (tmp*120)/((int)(System.currentTimeMillis()-time1));

		    		t = new Thread(){
		    			long l = System.currentTimeMillis();;
		    			int direction = -1;//Up or down...
		    			public void run(){
		    				int steps = 10;
		    				if((ypos-e.getY())<0){
		    					direction = 0;//up
		    				}else
		    					direction = 1; //down
		    				
		    				if(velocity>100)//if your finger (or mouse) was to quick, give em more steps to work with
		    					steps = 18;
		    				
		    				while(!Thread.currentThread().isInterrupted()){
		    					try {
		    						if((System.currentTimeMillis()-l)>velocity){
		    							l = System.currentTimeMillis();
		    							Thread.sleep(5);
		    		
		    						}
		    								velocity-=1;
		    								if(steps>0 && velocity%25==0){
		    									steps-=1;
		    								}
		    						
		    						scrollTable(cnt);
		    						if(direction==0){
		    							if(cnt>0)
		    								cnt-=steps;
		    						
		    						}else{
		    							cnt+=steps;
		    						}
		    						if(steps == 0)
		    							return;
		    					} catch (InterruptedException e2) {
		    						Thread.currentThread().interrupt();
		    					};
		    				}
		    			}
		    		};
		    		t.setPriority(Thread.MIN_PRIORITY);
		    		t.start();
		    		}
		    	}
		    @Override
		    public void mousePressed(MouseEvent arg0) {
		    	if(t!=null)
		    	t.interrupt();
		    	y = -1;
		    	ypos = arg0.getY();
		    	time1 = System.currentTimeMillis();
		    }}
		    
		    );
		    table.addMouseMotionListener(new MouseMotionAdapter(){
		    	
		    public void mouseDragged(MouseEvent e) {
		    	if(y==-1){
		    		cnt++;
		    		y = e.getY();
		    	}else{
		    		if(y < e.getY()){
		    			if(cnt>0)
		    				cnt-=5;
		    		}else
		    			cnt+=5;
		    	}
		    	scrollTable(cnt);
		    	
		    }});
		    sp = new JScrollPane(table);
		    sp.setDoubleBuffered(true);
		    table.setDoubleBuffered(true);
		    this.add(sp, BorderLayout.CENTER);
	}
	
	private void fillTable(){
		for(int i=0;i<10000;i++){
			model.addRow(new String[]{"Entry "+i,"Entry "+i, "Entry "+i, "Entry "+i});
		}
	}
	
	private void scrollTable(int value){
		try{
			sp.getVerticalScrollBar().setValue(value);
		}catch(Exception e){
			//Bugfix
		}
	}
	
	public static void main(String[] args){
		new Sandbox().setVisible(true);
	}
	
	
}
 
Zuletzt bearbeitet:
Statt dem addWindowListener würde ich nen setDefaultCloseOperation verwenden.

Statt:
Java:
int tmp = 0;
tmp = (ypos-e.getY());
if(tmp<0)
tmp = (e.getY()-ypos);

Ist doch:
Java:
final int diff;
if(ypos <= e.getY())
diff = e.getY() - ypos;
else
diff = ypos - e.getY()
schöner.

Gleiches hier:
Java:
 if((ypos-e.getY())<0){
if((ypos<e.getY())

120 und die weiteren Zahlen würde ich als Konstante anlegen. Dann haben sie nen Namen und man weiß was es ist ;)

Up und Down in einen Direction Enum packen (oder als Konstanten). Konstanten hätten folgenden Vorteil:
Up = -1
Down = 1
Java:
if(direction==0){
f(cnt>0)
 cnt-=steps;
 }else{
 cnt+=steps;
}

Würde zu:
Java:
cnt += (steps * direction);

Ansonsten habe ich mir das jetzt nicht so genau angeschaut als dass ich die Berechnungen verfolgen könnte ;)
 
mhm, warum static.. gute frage...

und mit dem javadoc, du hast recht, hab ich gar nicht dran gedacht ;) Hier, habe noch eine kleinigkeit am Code geändert...

Fällt dir / euch bei der Berechnung irgendwas auf, was verbesserungswürdig ist?

Jop, das mit dem DoubleBuffering ist keine tolle Lösung.


Du änderst Zeile 150, 151

Java:
sp.setDoubleBuffered(true);
table.setDoubleBuffered(true);

in

Java:
sp.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);

ab. Damit hast du erstmal ein angenehm smoothes Scrolling ab >= Java 1.3.

Dann würde ich in Zeile 162 nicht den Umweg über die Scrollbar gehen.

Java:
sp.getViewport().setViewPosition(new Point(0, value));
 
Zuletzt bearbeitet:
Danke für eure Anregungen. Ich habe den Code nun soweit geändert, dass ich statt dem DoubleBuffering deine Methode nutze. Ich sehe nur absolut kein Unterschied. Weder in der genutzten CPU Last, noch im scrollen selber...

Also wo liegt da der unterschied?

Thx
Chriz
 
Zurück