Focusprobleme

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Wie schon viele andere hab ich jetzt auch Probleme mit dem setzen des Focus.

hier mal ein bisschen Code:

Das Spielfeld:
Code:
public GamePanel(Gui gui, Grid g, ImagedTurningCharacter imgchar, ServerInterface si) { 
        setLayout(null);
        grid=g;
        serverinterface=si;
        imagedcharacter=imgchar;
        
        pingstart_sysmillis=System.currentTimeMillis();
        latenz=0;
        
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
        GraphicsDevice device = ge.getDefaultScreenDevice(); 
        GraphicsConfiguration gc = device.getDefaultConfiguration();
        backgroundimage = gc.createCompatibleVolatileImage(1000, 800);
        worldimage = gc.createCompatibleVolatileImage(window_width, window_height);
        wassersegment=Statics.getImage("C:/home/workspace/BloodSeaClient/images/200x200.gif");
        
        addMouseWheelListener(getMouseWheelListener());
        addMouseMotionListener(getMouseMotionListener());
        addMouseListener(getMapListener());

        tempwindows=new Vector<TemporaryWindow>();
        
        menupanel=new MenuePanel(this, 800,20);
        add(menupanel);
        menupanel.setBounds(0, 0, 800, 20);

        systempanel=new SystemPanel(this);
        systempanel.s1.setValue(systempanel.s1.getMinimum());
        
    	//Dass hier ist fast schon ein Scherz...
    	//ohne dieses Panel werden keine geaddeten
    	//Panels angezeigt... zum anzeigten tuff
        //sichtbar / unsichtbar machen schon gehts
    	//----------------------------------------
    	tuffpan=new JPanel();
    	Statics.setSize(tuffpan, 1, 1);
    	tuffpan.setBounds(1,1,1,1);
    	add(tuffpan);
    	tuffpan.setVisible(false);
        
        zoom();
        
        th = new Thread(this); 
        th.start();     
    	
	    if(imagedcharacter.getDockedAt()!=null){
	    	showIslePanel();//
	    }
        
        setVisible(true); 
        
	    requestFocus();
    }

Hier das Sorgenkind:
Code:
    private MouseWheelListener getMouseWheelListener(){
    	MouseWheelListener mw=new MouseWheelListener(){
			public void mouseWheelMoved(MouseWheelEvent arg0) {
	            int count = arg0.getWheelRotation(); 
	            if(count < 0){
	            	if(systempanel.s1.getValue()<=95){
	            		systempanel.s1.setValue(systempanel.s1.getValue()+5);
	            	}else{
	            		systempanel.s1.setValue(100);
	            	}
	            }else{
	            	if(systempanel.s1.getValue()>=30){
	            		systempanel.s1.setValue(systempanel.s1.getValue()-5);
	            	}else{
	            		systempanel.s1.setValue(25);
	            	}
	            }
			}
    	};
    	return mw;
    }

Mein Problem ist das der MouseWheelListener erst greift wenn ich auf irgend einen Button, Slider, etc geklickt hab.
Da der Slider aber nur meine "mein Laptop hat gar kein MouseWheel"-Lösung ist würd ich gern für alle anderen Spieler das ganze benutzerfreundlich machen.

Hier nun die Frage: wie wird wann wo warum der Focus hinversteckt? Ich mein Java wird den ja nicht spontan unter den Tisch fallen lassen?

P.S.: Ja, ich weiss, das mit dem TuffPanel ist ne blöde Idee, aber als Workarround gehts. Ist zwar nur ein kleineres Randproblem, aber wenn da jemand wüsst warum das so ist immer her mmit dem Wissen .-)

thx schonmal
 
G

Gast

Gast
Noch lieber als ne fertige Lösung wär mir allerdings wenn mir jemand das mit dem Focus erklären könnt, so für ganz ganz Dumme bitte.
 

André Uhres

Top Contributor
Erstens muss die Gui immer auf dem "Event Dispatch Thread" (EDT) gestartet werden:
Code:
   public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {//dies schickt den Code auf den EDT!

            public void run() {
                new Gui(new GamePanel()).setVisible(true);
            }
        });
    }
Den Focus kann nur kriegen, wer sichtbar und focusable ist (notfalls setFocusable(true) setzen).
Da der obige Code den JFrame (Gui) auf dem EDT sichtbar macht, muss der Focus danach gesetzt werden,
und zwar auch auf dem EDT. Das macht man üblicherweise mit SwingUtilities.invokeLater:
Code:
       SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                bt2.requestFocusInWindow();
            }
        });

Noch ein Spezialfall:
Um ein JWindow zu benutzen, muss der owning Frame sichtbar sein,
damit eine Komponente im JWindow den Focus kriegen kann.
 
G

Guest

Gast
André Uhres hat gesagt.:
Code:
   public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {//dies schickt den Code auf den EDT!

            public void run() {
                new Gui(new GamePanel()).setVisible(true);
            }
        });
    }

Das new Gui() versteh ich grad nicht. beziehst du dich damit auf das Gui aus meinem Codebeispiel oben oder hast du da was anderes im Sinn?

Dazu mein Gui extends JFrame
Code:
public Gui() {
    super("Gui");
    setCursor(new Cursor(Cursor.HAND_CURSOR));
    getContentPane().add(new GamePanel(this, grid, imagedcharacter,serverinterface));
    setVisible(true);
}

In meinem Fall müsste ich also :
Code:
public Gui() {
    super("Gui");
    setCursor(new Cursor(Cursor.HAND_CURSOR));
GamePanel gp;
    SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                gp=new GamePanel(bla));
            }
        });

    getContentPane().add(gp);
    setVisible(true);
}

Weil meiner Gui das Gamepanel direkt mitgeben kann ich da leider nicht so einfach, da wird bevor das Spielfeld startet noch ne Serververbindungn aufgebaut, mit Login, neuen Char erstellen, char laden etc. Soll ein Multiplayergame werden...
 

André Uhres

Top Contributor
Gui soll dein JFrame darstellen.
Es scheint gute Praxis zu sein, setVisible nicht im Konstruktor aufzurufen,
sondern so, wie es mein Beispiel zeigt:
Code:
   public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {//dies schickt den Code auf den EDT!

            public void run() {
                new Gui().setVisible(true);
            }
        });
    }

Der Konstruktor der Gui kann selbstverständlich auch ohne Parameter sein (das war nur ein Beispiel).
Das GamePanel musst du aber nicht später hinzufügen (invokeLater), nur der requestFocusInWindow
muss verzögert werden, damit dann alles sichtbar ist:
Code:
       SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                bt2.requestFocusInWindow();
            }
        });
 
G

Guest

Gast
Also ich hab in meiner Gui ne Methode gehabt :
Code:
public void showGamePanel(String charname){
    gp = new GamePanel(this, grid, imagedcharacter,serverinterface);
    getContentPane().add("gamepanel", gp);
    ((CardLayout)getContentPane().getLayout()).show(getContentPane(), "gamepanel");
}

die hab ich ersetzt durch:
Code:
public void showGamePanel(String charname){    	
    SwingUtilities.invokeLater(new Runnable() { 
        public void run() { 
            gp=new GamePanel(grid, imagedcharacter,serverinterface); 
        } 
    });
    getContentPane().add("gamepanel", gp);
    ((CardLayout)getContentPane().getLayout()).show(getContentPane(), "gamepanel");
}

Aber das scheint wohl falsch zu sein, ich bekomm zwar keine Fehlermeldung aber auch kein Spielfeld mehr.
Da muss ich mal drüber nachdenken. Danke schonmal :)
 
G

Guest

Gast
hm ok, so leicht dann doch nicht.

ich starte jetzt die Gui und das GamePanel mit einem Invoke, und setze danach erst mit dem Code den du geschrieben den Focus. Geht trotzdem nicht. Dabei bin ich aber drüber gestolpert das es geht wenn ich in meinem GamePanel die Zeilen
Code:
        th = new Thread(this); 
        th.start();
auskommentiere. Dann zeichnet er aber auch das GamePanel nicht mehr neu. Ich glaub ich hab mich grad ganz schön verfranzt :?
 

André Uhres

Top Contributor
Was macht denn die run Methode?
Wenn du dort den Focus nicht veränderst, dann dürfte sie ja eigentlich nichts ausmachen.
 
G

Guest

Gast
Nene, mein Prob geht tiefer. Ich sitz seit nem halben Jahr 6/7 Abenden an meinem Game, da baut man schonmal Mist. Da bin ich gestern beim drüber nachdenken mal draufgestoßen als ich versucht hab das mit dem InvokeLater umzusetzen.
Wie gesagt ich hab ein Spielfeld (so in der Art wie das aus dem SpieleTutoriel von ähh quaxli glaub ich), und das liegt im ContentPane meines JFrame.

Frage 1:
- Nun hab ich all meine BedienElemente (alles erbt von JPanel) direkt auf mein GamePanel geaddet, und ich glaub das war saublöde von mir, seh ich das richtig? Weil das ja alle äh 10 ms neuzeichnen mag.

Frage 2:
-Wäre es nicht sinnvoller oder sogar einzig richtig gewesen die auf die ContentPane von dem JFrame zu adden und die Zorientation zu managen?

Frage 3:
-Egal wo ich die JPanels draufputte, die werden ja nur einmal gezeichnet und bleiben dann unverändert, wäre es doch sinnvoll die über den InvokeLater einzubauen, oder?

Mann, Mann, da hab ich die halbe Nacht dran gesessen und nix Produktiv gemacht :/ Ich hab nämlich auch ab und an Probleme mit der FrameRate, grad wenn Fenster (die JPanels) mit ins Spiel kommen. Das könnt zwei Fliegen mit einer Klappe schlagen das Problemchen.
 
G

Gast

Gast
Achso, die runMethode malt auf ein VolatileImage und ruft dann repaint auf. Die PaintComponent ist überschrieben und malt dann das VolatileImage auf das Spielfeld. Wie bei Quaxli :)
 

André Uhres

Top Contributor
Ich würde zu der Klasse, die die paintComponent überschreibt, keine Kindkomponenten hinzufügen. Vielleicht löst das ja schon dein Problem..
 
G

Gast

Gast
ich hab gestern versucht das ganze umzubauen, und starte deswegen gleich nen neuen Tread. Sollte ich das Focusproblem dann noch haben schreib ich hier weiter.

Und danke schonmal für die Mühe :)
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben