JFrame-Anwendungsfenster verschieben

OSchriever

Bekanntes Mitglied
Hi Freunde,
ich möchte gerne eine Funktion in mein Programm einbauen, mit der ich die Fensterposition entweder nach links, rechts, oben oder unten verschieben kann. Jetzt kann ich über setLocation() die Position angeben, ich möchte aber über Schaltflächen jeweils die Position des Fensters um 10 Pixel in die gewünschte Richtung (über ActionListener) verändern.

Hat jemand eine Idee?

LG
 
Ich verstehe gerade Dein Problem nicht. Du hast doch setLocation selbst schon genannt. Und du kannst die aktuelle Position per getLocation bekommen.

Und Schaltflächen kannst Du per Buttons machen oder einfach per MouseListener wenn Dir das lieber ist.

Was fehlt dir also für ein Verschieben des Fensters?
 
Meine Frage dazu wäre: Wie kann ich denn dann die Position der Fensterhöhe mit dem Button "höher" um 10 Pixel nach oben bewegen?
Bei setLocation muss ich ja beide Werte angeben...
 
Du holst per getLocation die aktuelle Position (kommt als Point) und veränderst dann die y Koordinate und setzt das dann mit setLocation.

Ganz kleines, dummes Beispiel, das ein Fenster auf der x-Achse verschiebt:

Code:
import javax.swing.*;
import java.awt.*;

public class FrameMove {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(300, 150);
        frame.setVisible(true);

        while (true) {
            try {
                Thread.sleep(100);
                Point current = frame.getLocation();
                current.x = current.x + 100;
                if (current.x > 800) current.x = 0;
                frame.setLocation(current);
            } catch (Exception ex) {
            }

        }
    }
}
 
Im ActionListener des Buttons:
Java:
Point aktPos = myFrame.getLocation();
aktPos.x = aktPos.x + 10;
myFrame.setLocation(aktPos);
sollte das erledigen.

Beste Grüße,
Stuck1A
 
Das hat nicht geklappt. Ich hänge hier mal, zum einfacheren Verständnis, meinen Code an. 🙂
Ich habe den ActionListener hier jetzt absichtlich noch leer gelassen.
Vielen Dank
Java:
import java.awt.BorderLayout;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Fenster extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = -5413214781097583793L;
    private JButton links, rechts, hoch, herunter;

    class SchaltflaechenListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

        }
    }

    public Fenster(String text) {
        super(text);

        links = new JButton("Links");
        rechts = new JButton("Rechts");
        hoch = new JButton("Hoch");
        herunter = new JButton("Herunter");

        links.addActionListener(new SchaltflaechenListener());
        rechts.addActionListener(new SchaltflaechenListener());
        hoch.addActionListener(new SchaltflaechenListener());
        herunter.addActionListener(new SchaltflaechenListener());

        setLayout(new BorderLayout(25, 25));
        setBounds(600, 500, 200, 200);

        add(links, BorderLayout.WEST);
        add(rechts, BorderLayout.EAST);
        add(hoch, BorderLayout.NORTH);
        add(herunter, BorderLayout.SOUTH);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setVisible(true);

    }

}
 
Was hast Du denn an Code konkret versucht und was ging dann nicht?

Die Lösung wurde ja schon aufgezeigt und die ist auch 1:1 bei Dir verwendbar. Da SchaltflaechenListener eine innere Klasse ist, kannst Du auf die Element der äußeren Klasse zugreifen und ein Code a. la.
Code:
                Point p = getLocation();
                p.y += 10;
                setLocation(p);
In dem actionPerformed würde funktionieren.

Da du aber 4 Mal den gleichen ActionListener hast (Was ich ungünstig finde), musst Du natürlich prüfen, welcher Knopf gedrückt wurde. Dazu gibt es in dem EventObject ein getSource(), also kannst Du z.B. prüfen: if (e.getSource() == herunter). Wobei hier ggf. ein switch Befehl gut wäre um vor dem Switch getLocation aufzurufen, im switch den Point zu verändern und nach dem Switch dann setLocation aufzurufen.

Aber evtl. wäre es einfacherdie ganze Klasse SchaltflaechenListener raus zu schmeissen und dafür einfach mit Lambdas zu arbeiten:
Java:
        links.addActionListener(e -> {
                Point p = getLocation();
                p.x -= 10;
                setLocation(p);
        });
 
Das Problem scheint mir zu sein, dass das Ergebnis vom System abhängig ist. Bei mir liefert z. B. getLocation() das gleiche Ergebnis wie getLocationOnScreen(). Der zurückgegebene Punkt entspricht aber nicht der linken oberen Ecke des Fensters, sondern des Content-Panes und zwar absolut auf die linke obere Bildschirmecke bezogen. Dagegen sind die Koordinaten von setLocation() relativ zur linken oberen Ecke des Desktops (die Toolbar wird nicht berücksichtigt).

Kurz: setLocation(0,0) platziert das Fenster unterhalb der Toolbar ganz links, getLocation() liefert jedoch (1, 52).

Um das stabil zu haben, würde ich einfach den Punkt, der für setBounds() bzw. setLocation() verwendet wurde, wiederverwenden, statt via getLocation() neu abzufragen.
 
Das Problem scheint mir zu sein, dass das Ergebnis vom System abhängig ist. Bei mir liefert z. B. getLocation() das gleiche Ergebnis wie getLocationOnScreen(). Der zurückgegebene Punkt entspricht aber nicht der linken oberen Ecke des Fensters, sondern des Content-Panes und zwar absolut auf die linke obere Bildschirmecke bezogen. Dagegen sind die Koordinaten von setLocation() relativ zur linken oberen Ecke des Desktops (die Toolbar wird nicht berücksichtigt).

Kurz: setLocation(0,0) platziert das Fenster unterhalb der Toolbar ganz links, getLocation() liefert jedoch (1, 52).

Um das stabil zu haben, würde ich einfach den Punkt, der für setBounds() bzw. setLocation() verwendet wurde, wiederverwenden, statt via getLocation() neu abzufragen.

Dem kann ich jetzt irgendwie nicht ganz folgen. Auf welchem System hast Du dies gemacht?

Ich habe jetzt einfach einmal den Code vom TE etwas umgeschrieben:

Java:
import java.awt.BorderLayout;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Point;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Fenster extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = -5413214781097583793L;
    private JButton links, rechts, hoch, herunter;

    class SchaltflaechenListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

        }
    }

    public Fenster(String text) {
        super(text);

        links = new JButton("Set(0,0)");
        rechts = new JButton("Set(200,100)");
        hoch = new JButton("Get Location");
        herunter = new JButton("Herunter");

        links.addActionListener(e -> {
        Point p = new Point(0,0);
        setLocation(p);
    });
        rechts.addActionListener(e -> {
        Point p = new Point(200,100);
        setLocation(p);
    });
        hoch.addActionListener(e -> {
        Point p = getLocation();
        setTitle("Position: " + p.x + ", " + p.y);
    });
        herunter.addActionListener(new SchaltflaechenListener());

        setLayout(new BorderLayout(25, 25));
        setBounds(600, 500, 200, 200);

        add(links, BorderLayout.WEST);
        add(rechts, BorderLayout.EAST);
        add(hoch, BorderLayout.NORTH);
        add(herunter, BorderLayout.SOUTH);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setVisible(true);
    }

    public static void main (String[] args) {
    new Fenster("Test");
    }

}

Das Fenster musste ich etwas vergrößern, um die Koordinaten richtig zu sehen, aber das ist ja Nebensache.
setLocation(new Point(0,0)) setzt das Fenster korrekt auf 0,0 bei mir (Also oben links in die Ecke). So da eine Taskleiste von Windows ist, wird das Fenster verdeckt.
Das Fenster kann auch teilweise verdeckt werden. Dann hat man halt -89,0 oder so. Selbst das ließ sich auch aktiv testen.
==> Also wenn ich die Koordinate auf x,y gesetzt habe mit setLocation, dann habe ich diese koordinate auch mit getLocation zurück bekommen.

Auf einem Mac und diversen Fenster Managern unter Linux habe ich es jetzt aber nicht testen können. Ich möchte nicht ausschließen, dass ein Fenstermanager z.B. ein Fenster an eine andere Position setzt, wenn es teilweise verdeckt würde oder so. Aber wenn man das Fenster irgendwo hin setzt, wo es nicht so verschoben wird, dann sollte auch gelten: wenn mit setLocation ein Wert gesetzt wird, dann sollte der Wert auch bei getLocation wieder zurück gegeben werden.

Oder habe ich da jetzt etwas missverstanden?

Ach ja: Meine Systeme, auf denen ich getestet habe, waren ein Windows 10 und ein Linux mit KDE Plasma.

Edit: Auf Linux konnte ich noch eine Kontrollleiste so einrichten, dass Fenster hier nicht erlaubt waren. Bei Setzen von (0,0) war dann das Resultat (0,36). Aber das lag halt meiner Meinung nach daran, dass die Applikation 0,0 setzt und dann der Fenstermanager erneut umsetzt. Ein Setzen von 200,100 brachte das Fenster auch nach 200,100. Ebenso war unter Linux kein -89, 100 oder so möglich. Das Ergebnis war dann 0,100.
 
Zuletzt bearbeitet von einem Moderator:
Testanwendung ist eine modifizierte Version des Codes von @OSchriever :
Java:
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.Window;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class Fenster extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = -5413214781097583793L;
    private JButton links, rechts, hoch, herunter;

    static class FensterBewegung implements ActionListener {
        private final JFrame frame;
        private final int xDelta;
        private final int yDelta;

        public FensterBewegung(JFrame frame, int xd, int yd) {
            this.frame = frame;
            this.xDelta = xd;
            this.yDelta = yd;
        }

        @Override
        public void actionPerformed(ActionEvent e) {           
            Point p = frame.getLocation();
            System.out.printf("JFrame vor Verschiebung: %s\n", p);
            Point pp = frame.getContentPane().getLocationOnScreen();
            System.out.printf("ContentPane on Screen: %s\n", pp);
            p.x += xDelta;
            p.y += yDelta;
            frame.setLocation(p);
            System.out.printf("Verschiebung um (%d, %d) => Ziel %s \n", 
                              xDelta, yDelta, p);
            SwingUtilities.invokeLater(() -> {
                    System.out.printf("JFrame nach Verschiebung: %s\n\n", 
                                      frame.getLocation());
            });
        }
    }

    public Fenster(String text) {
        super(text);

        links = new JButton("Links");
        rechts = new JButton("Rechts");
        hoch = new JButton("Hoch");
        herunter = new JButton("Herunter");

        links.addActionListener(new FensterBewegung(this, -10, 0));
        rechts.addActionListener(new FensterBewegung(this, 10, 0));
        hoch.addActionListener(new FensterBewegung(this, 0, -10));
        herunter.addActionListener(new FensterBewegung(this, 0, 10));

        setLayout(new BorderLayout(25, 25));
        setBounds(0, 0, 200, 200);
        System.out.printf("setBounds(0, 0, 200, 200)\n");

        add(links, BorderLayout.WEST);
        add(rechts, BorderLayout.EAST);
        add(hoch, BorderLayout.NORTH);
        add(herunter, BorderLayout.SOUTH);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setVisible(true);
        System.out.printf("setVisible(true)\n");
    }

    public static void main(String[] args) {
        new Fenster("Test");
    }

}

Testablauf:
1. Fenster starten (java -cp . Fenster)
2. 4x "Hoch" klicken
3. 2x "Rechts" klicken

Ergebnis:

Unter Java 1.8 entsteht das in #9 beschriebene Verhalten:
Code:
setBounds(0, 0, 200, 200)
setVisible(true)
JFrame vor Verschiebung: java.awt.Point[x=1,y=52]
ContentPane on Screen: java.awt.Point[x=1,y=52]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=1,y=42] 
JFrame nach Verschiebung: java.awt.Point[x=1,y=42]

JFrame vor Verschiebung: java.awt.Point[x=8,y=70]
ContentPane on Screen: java.awt.Point[x=8,y=70]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=8,y=60] 
JFrame nach Verschiebung: java.awt.Point[x=8,y=60]

JFrame vor Verschiebung: java.awt.Point[x=9,y=88]
ContentPane on Screen: java.awt.Point[x=9,y=88]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=9,y=78] 
JFrame nach Verschiebung: java.awt.Point[x=9,y=78]

JFrame vor Verschiebung: java.awt.Point[x=10,y=106]
ContentPane on Screen: java.awt.Point[x=10,y=106]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=10,y=96] 
JFrame nach Verschiebung: java.awt.Point[x=10,y=96]

JFrame vor Verschiebung: java.awt.Point[x=11,y=124]
ContentPane on Screen: java.awt.Point[x=11,y=124]
Verschiebung um (10, 0) => Ziel java.awt.Point[x=21,y=124] 
JFrame nach Verschiebung: java.awt.Point[x=21,y=124]

JFrame vor Verschiebung: java.awt.Point[x=22,y=152]
ContentPane on Screen: java.awt.Point[x=22,y=152]
Verschiebung um (10, 0) => Ziel java.awt.Point[x=32,y=152] 
JFrame nach Verschiebung: java.awt.Point[x=32,y=152]

Unter Java 12 sieht das "besser" aus, allerdings immer noch äußerst seltsam:
Code:
setBounds(0, 0, 200, 200)
setVisible(true)
JFrame vor Verschiebung: java.awt.Point[x=0,y=24]
ContentPane on Screen: java.awt.Point[x=1,y=52]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=0,y=14] 
JFrame nach Verschiebung: java.awt.Point[x=0,y=14]

JFrame vor Verschiebung: java.awt.Point[x=7,y=24]
ContentPane on Screen: java.awt.Point[x=8,y=52]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=7,y=14] 
JFrame nach Verschiebung: java.awt.Point[x=7,y=14]

JFrame vor Verschiebung: java.awt.Point[x=7,y=14]
ContentPane on Screen: java.awt.Point[x=8,y=52]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=7,y=4] 
JFrame nach Verschiebung: java.awt.Point[x=7,y=4]

JFrame vor Verschiebung: java.awt.Point[x=7,y=4]
ContentPane on Screen: java.awt.Point[x=8,y=52]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=7,y=-6] 
JFrame nach Verschiebung: java.awt.Point[x=7,y=-6]

JFrame vor Verschiebung: java.awt.Point[x=7,y=-6]
ContentPane on Screen: java.awt.Point[x=8,y=52]
Verschiebung um (10, 0) => Ziel java.awt.Point[x=17,y=-6] 
JFrame nach Verschiebung: java.awt.Point[x=17,y=-6]

JFrame vor Verschiebung: java.awt.Point[x=17,y=24]
ContentPane on Screen: java.awt.Point[x=18,y=52]
Verschiebung um (10, 0) => Ziel java.awt.Point[x=27,y=24] 
JFrame nach Verschiebung: java.awt.Point[x=27,y=24]
 
Was für ein Verhalten genau meinst Du? Bei deiner Java 1.8 ist die Location der ContentPane gleich der des JFrame - ist das die Problematik, die Du meinst? Das ist etwas, das ich bei mir nicht nachvollziehen kann:

Einfach mal die Ausgabe - habe sogar das Fenster - wie man erkennen kann - nach oben aus dem Sichtbaren Bereich heraus geführt:
setBounds(0, 0, 200, 200)
setVisible(true)
JFrame vor Verschiebung: java.awt.Point[x=0,y=0]
ContentPane on Screen: java.awt.Point[x=8,y=31]
Verschiebung um (10, 0) => Ziel java.awt.Point[x=10,y=0]
JFrame nach Verschiebung: java.awt.Point[x=10,y=0]

JFrame vor Verschiebung: java.awt.Point[x=10,y=0]
ContentPane on Screen: java.awt.Point[x=18,y=31]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=10,y=-10]
JFrame nach Verschiebung: java.awt.Point[x=10,y=-10]

JFrame vor Verschiebung: java.awt.Point[x=10,y=-10]
ContentPane on Screen: java.awt.Point[x=18,y=21]
Verschiebung um (0, -10) => Ziel java.awt.Point[x=10,y=-20]
JFrame nach Verschiebung: java.awt.Point[x=10,y=-20]

Also immer +8 / +31 für das ContentPane.

Ergebnisse sind von meinem Windows 10 System, mit OpenZulu JDK:
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (Zulu 8.38.0.13-CA-win64) (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM (Zulu 8.38.0.13-CA-win64) (build 25.212-b04, mixed mode)

Werde es auch gerne noch einmal auf meinem Linux System testen. Da habe ich aber bisher alles mit JDK 11 (Ebenfalls OpenZulu) gemacht, aber ich kann es auch einmal mit dem 1.8er probieren....)

Wobei ich nicht ausschließen möchte, dass ich derzeit einfach zu blind bin, um das Problem zu erkennen. Oder eben bei mir tritt es nicht auf. Daher danke schon einmal für deine Geduld mit mir!
 
Bei deiner Java 1.8 ist die Location der ContentPane gleich der des JFrame - ist das die Problematik, die Du meinst?
Ja, das ist das, was ich unter #9 beschrieben habe (EDIT: setLocation bezieht sich aber nicht auf das ContentPane). Aber unter JDK12 tritt auch etwas interessantes auf:
  1. das was Du auch beobachtest: die y gehen ins negative, obwohl (zumindest bei mir) das Fenster sich nicht weiter nach oben verschiebt.
  2. wenn ich danach nach rechts klicke, kommt zunächst einmal die rechnerisch richtige Koordinate raus (es ändert sich nur der x-Wert)
  3. wenn ich nun nochmal nach rechts klicke, erhalte ich plötzlich wieder die positive y-Koordinate (s. die letzten beiden Blöcke im JDK12-Spoiler bei #11).
Strange, oder? 🙂
 
Zuletzt bearbeitet:
Das ist wirklich komisch. Also bei mir ging das Fenster entweder aus dem Sichtbaren Bereich heraus (Sprich: Es war teilweise nicht sichtbar) oder eben die Position war eine andere (bei Linux, nachdem ich eine Leiste positioniert habe, die kein Fenster verdecken darf. Da wurde das Fenster dann halt nur unter die Leiste gesetzt und die Position war stimmig.)

Was für ein JDK auf welchem Betriebssystem hast Du im Einsatz?
 
Das ist mein berühmter Kurbel-Rechner, den ich für so Spielereien wie das Forum verwende 🙂
Code:
Ubuntu 12.04.5
3.13.0-117-generic #164~precise1-Ubuntu SMP Mon Apr 10 16:17:54 UTC 2017 i686 athlon i386 GNU/Linux
mit
Code:
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) Server VM (build 25.111-b14, mixed mode)
und
Code:
openjdk version "12-BellSoft" 2019-03-19
OpenJDK Runtime Environment Liberica (build 12-BellSoft+33)
OpenJDK Server VM Liberica (build 12-BellSoft+33, mixed mode)
 
Hallo Freunde, ich möchte hier einmal den Quelltext posten, so wie ich das "Problem" gelöst habe.
Funktioniert 🙂 Vielen Dank euch nochmal für die Unterstützung.

Java:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Fenster extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = -5413214781097583793L;
    private JButton links, rechts, hoch, herunter;

    class SchaltflaechenListener implements ActionListener {
        //der Listener, der auf die Schaltflächen reagiert
        @Override
        public void actionPerformed(ActionEvent e) {
           
            Point p = getLocation();
            Dimension d = Toolkit.getDefaultToolkit().getScreenSize();

            if (e.getActionCommand().equals("Links") && p.x > 0) {

                p.x -= 10;
                setLocation(p);
            }
            if (e.getActionCommand().equals("Rechts") && p.x < (d.getSize().width - getSize().width)) {

                p.x += 10;
                setLocation(p);
            }
            if (e.getActionCommand().equals("Hoch") && p.y > 0) {

                p.y -= 10;
                setLocation(p);
            }
            if (e.getActionCommand().equals("Herunter") && p.y < (d.getSize().height - getSize().height)) {

                p.y += 10;
                setLocation(p);
            }
        }
    }

    public Fenster(String text) {
        super(text);

        links = new JButton("Links");
        rechts = new JButton("Rechts");
        hoch = new JButton("Hoch");
        herunter = new JButton("Herunter");

        links.addActionListener(new SchaltflaechenListener());
        rechts.addActionListener(new SchaltflaechenListener());
        hoch.addActionListener(new SchaltflaechenListener());
        herunter.addActionListener(new SchaltflaechenListener());

        setLayout(new BorderLayout(25, 25));
        setBounds(600, 500, 200, 200);

        add(links, BorderLayout.WEST);
        add(rechts, BorderLayout.EAST);
        add(hoch, BorderLayout.NORTH);
        add(herunter, BorderLayout.SOUTH);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setVisible(true);

    }

}
 
Ich habe mir eben den Code angeschaut. Wenn links, unten oder rechts weniger als 10 Pixel Abstand vorhanden ist, dann wird das Fenster nicht bis zum Bildschirmrand verschoben. Siehe Screenshot. Woran könnte das liegen? Wie könnte man dieses Problem lösen?
 
Evtl. ist es besser, einen eigenen Thread zu öffnen. Und wir bräuchten den genauen Code. Dann könnte man ggf. weiterhelfen.
 

Zurück
Oben