Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Kann mir jemand sagen weshalb der im rot markierte Code nur einmal funktioniert?
Ich habe versucht durch den ComponentAdapter die Grösse des JFrames abzufragen und diese mit dem Bild (hintergrund) anzugleichen. Nur tut es das einmal und danach entsteht irgendwie ein Bug.
Das sind doch normale Reaktionen…. Der Hinweis auf das repaint ist doch schon gegeben worden, daher ist der Mehrwert Deines Posts halt nicht wirklich gegeben.
Und das revalidate macht bei dem gezeigten Code keinen Sinn …
Wenn Du Argumente für diese Aussage hast, dann würde ich die gerne hören. Vielleicht kann ich ja doch einmal etwas von Dir lernen.
Hier halte ich es aber für extrem unwahrscheinlich. Denn man muss einfach nur verstehen, was die einzelnen Methoden machen - dann kann man auch klar sagen, was man braucht und was man nicht braucht.
Repaints this component.
If this component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.
Note: For more information on the paint mechanisms utilitized by AWT and Swing, including information on how to write the most efficient painting code, see Painting in AWT and Swing.
Revalidates the component hierarchy up to the nearest validate root.
This method first invalidates the component hierarchy starting from this component up to the nearest validate root. Afterwards, the component hierarchy is validated starting from the nearest validate root.
This is a convenience method supposed to help application developers avoid looking for validate roots manually. Basically, it's equivalent to first calling the invalidate() method on this component, and then calling the validate() method on the nearest validate root.
Wie als klar erkennbar ist: Ersteres triggert lediglich ein erneutes Malen der Componente (was hier fehlen kann).
Letzteres ist nur sinnvoll / notwendig, wenn an der Hirarchie etwas geändert wurde. Aber das ist ja ganz offensichtlich nicht der Fall.
Wenn man aber von den Abläufen keine Ahnung hat, dann mag man evtl. der Meinung sein: "Ich rufe einfach beides auf". Und das vorsichtshalber an ganz vielen Stellen im Code. Das macht aber natürlich keinen Sinn. Und als Regel macht es auch nur Sinn, wenn man Jemanden nicht mit Details belasten will. Ein Lehrer, der einem Schüler sowas sagt wird der Meinung sein, dass die Hintergründe zu schwer zu verstehen sind oder er hat sie selbst nicht verstanden....
Wie dem auch sei - ich selbst distanziere mich davon, denn aus meiner Sicht ist eine halbwegs professionelle Softwareentwicklung das Ziel für die Leute, die hier Fragen stellen. Und dazu gehört dann immer ein zumindest grobes Verständnis der Abläufe.
HINT: Lesen bildet. Und deine Postings, sind zwar für deine Verhältnisse halt sprachlich "OK" aber mind. redundant (siehe Ausführung von @KonradN weiter oben) oder einfach falsch.
Also lies mal den StackOverflow und bildet dich einfach weiter, statt hier sinnlose Postings einfach abzuschreiben und dann für deine zu verkaufen.
Hier wäre natürlich jetzt ein Beispiel gut, wie man es denn machen würde. Vielleicht auch etwas ohne hundert static Methoden? - Bevor man hier sowas droppt und sich maximal unbeliebt macht, vor allem nachdem man direkt darauf hingewiesen wird...
Es tut mir einfach so leid, dass hier eine einfache Frage eines TO in so einer Schlammschlacht enden muss, nur weil Tobias hier seine Tage hat...
Ja klar kann man die paint() überschreiben.. Aber das hat ja ein ZWECK. Und den wirst du lieber Tobias niemals verstehen mangels Erfahrung.
@Pianoman.20 ; Ich kann mich hier nur für den Troll User entschuldigen. Ich sehe die Schuld bei den "bekannten" Mitgliedern, die genau wissen wer das ist, aber dennoch immer und immer wieder auf die Schnauze fallen, weil man immer und immer wieder eine neue faire Chance geben und das wird mit Füßen getreten.
Ich kann dir anbieten, wenn du Fragen hast, schreib mich an, ich erkläre dir die nächsten Fragen im Discord als Wiedergutmachung.
Hast Du den Beitrag auch gelesen? Wenn man an der Hierarchie etwas ändert (Ups, zu allgemein. Wenn man remove oder removeAll aufruft), dann ruft man revalidate und repaint auf.
Nur da hier an der Hierarchie der AWT / Swing Komponenten nichts verändert wurde, ist das hier eben nicht notwendig.
In dem SO Thread steht also auch nichts anderes, als ich schon geschrieben habe, nur eben ging es bei SO um ein konkretes Problem und ich habe es allgemeiner gehalten.
Das ist nicht zwingend gesagt. Er nutzt die Möglichkeiten der Klasse ImageIcon. Das ist durchaus eine elegante Möglichkeit, wenn man einfach nur ein Bild anpassen will. Das ist also eine nicht unübliche Vorgehensweise.
Und nein, man überschreibt per se nicht die paint Methode. Das wäre nur bei Top Level Containern wie JFrame korrekt. Ansonsten wäre es paintComponent. Da wir nicht wissen, was der TE genau braucht, sollte man da also entweder genau sein oder eben klare Links aufzeigen wie z.B. zu Painting in AWT and Swing (oracle.com)
Solche pauschalen Antworten, die viele Details einfach weg lassen, sind also absolut nicht professionell - aber Du hast ja selbst gesagt: Das willst Du nicht (Hier als auch in dem anderen Thread beim Thema Clean Code ...) Ist ok, so eine Sicht darfst Du gerne haben. Aber ich finde solche Antworten den Fragestellern gegenüber zumindest unfair.
@Pianoman.20 ; Ich kann mich hier nur für den Troll User entschuldigen. Ich sehe die Schuld bei den "bekannten" Mitgliedern, die genau wissen wer das ist, aber dennoch immer und immer wieder auf die Schnauze fallen, weil man immer und immer wieder eine neue faire Chance geben und das wird mit Füßen getreten.
Ich find es schon gut, wenn man im Forum bleibt. Den Troll kannst Du reporten. Dann wird sich irgendwann etwas tun. Die Moderatoren haben leider teilweise nicht so viel Zeit, wie das Forum manchmal erfordert ...
Aber ich denke, dass die fachlichen Erwiderungen doch durchaus vernünftig sind und auch dem TE weiter helfen könnten. Das Problem ist halt nur, dass ich gewisse Aussagen so nicht stehen lassen möchte und daher mich tatsächlich mehr oder weniger gezwungen sehe, da eine Richtigstellung zu schreiben.
Also wenn ich das Fenster mit der Maus vergrössere, vergrössert es das Bild bei ersten Mal mit. Danach funktioniert es nicht mehr, bzw. wenn ich es z.B. verkleinern möchte, schneidet es das Bild nur zu und verkleinert es nicht. Wenn ich es dann wieder vergrössere, macht es mit dem Bild gar nichts mehr und es bleibt nebst dem Bild eine schwarze Fläche (siehe Anhang).
Poste mal deinen ganzen Code in Code Tags (Also bitte über den Knopf </> links oberhalb des Eingabebereiches. Dann teste ich da auch mal lokal und zeige eine Lösung, die den Weg nutzt, den Du nehmen willst.
Ich vermute auch, dass Du Qualitätsverluste durch ständiges Größe verändern bekommst - wobei das erst eine Vermutung ist, aber das setImage (getImage(), ...) sieht etwas danach aus.
Also folgender Code funktionierte bei mir einwandfrei. Ich konnte das Fenster in der Größe anpassen und das Bild wurde dann in der Größe so angepasst, dass es immer richtig angezeigt wurde.
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class GUI {
public GUI() {
//Bilder
ImageIcon hintergrund = new ImageIcon(getClass().getResource("/testlevel.png"));
//Fenster
JFrame frame = new JFrame("Erstes Spiel");
frame.setVisible(true);
frame.setSize(1742,980);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());
//Label
JLabel label = new JLabel(hintergrund);
frame.add(label, BorderLayout.CENTER);
//Bildgrösse ändern
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
super.componentResized(e);
hintergrund.setImage(hintergrund.getImage().getScaledInstance(e.getComponent().getWidth(), e.getComponent().getHeight(), Image.SCALE_SMOOTH));
}
});
}
public static void main(String[] args) {
new GUI();
}
}
Unterschiede zu Deinem Code:
frame Variable ist vom Typ JFrame. java.awt.Frame kennt keine setDefaultCloseOperation.
Ich habe das Bild als Ressource geladen - etwas, das Du auch machen solltest.
Bist Du sicher, dass Dein Code richtig übersetzt wurde? Ggf. hast Du immer einen alten Stand ausgeführt, weil der aktuelle Stand nicht übersetzt werden kann?
Wobei noch anzumerken ist: Du behältst das Seitenverhältnis bei dem Code nicht bei, d.h. du bekommst alles recht verzerrt. Das macht es natürlich nicht ganz so schön.
Ich versichere dir das diesen Code 1 zu 1 so bei mir eingetippt habe. Ich habe nun auch deine Empfehlung umgesetzt das Bild als Ressource zu laden. Ausserdem habe ich noch das Bild von einem jpg in ein png konvertiert. Tortz all dem bleibt das Problem immer noch bestehen. :/
Ich versichere dir das diesen Code 1 zu 1 so bei mir eingetippt habe. Ich habe nun auch deine Empfehlung umgesetzt das Bild als Ressource zu laden. Ausserdem habe ich noch das Bild von einem jpg in ein png konvertiert. Tortz all dem bleibt das Problem immer noch bestehen. :/
Ich glaube das hat aber auch etwas mit der Java Version zu tun. Und aus irgendeinem Grund ist bei meinem Bild die Skalierung falsch, bin mir aber nicht sicher wieso, vermutlich die Einstellung am JLabel.
Öhm, was für ein Setup verwendet Ihr genau? Und Frame ist doch auch bei euch dann java.awt.Frame? Frame (Java SE 17 & JDK 17) (oracle.com)
==> keine setDefaultCloseOperation Methode.
Daher wundere ich mich weiterhin, wie der Code bei euch übersetzen kann. Was übersehe ich bitte?
Und ich verwendet als Entwicklungsumgebung IntelliJ, derzeit mit openjdk 21 als aktives JDK auf meinem System. In dem Maven Projekt setzt ich aber immer noch die Version auf 17.
Ich habe das alles aber jetzt auch mal mit OpenJDK 8 gemacht und es funktioniert immer noch einwandfrei.
Ich setze hier auf einen Mac mit M1 Prozessor. Ich kann es aber auch gerne noch einmal unter Windows probieren.
Nehme ich zurueck, es funktioniert, es ist nur so langsam dass es mir nicht aufgefallen ist dass es funktioniert. Meine Loesung geht schneller, aber wieso dein Code langsam ist, weisz ich nicht.
Ok, das beruhigt mich erst einmal ... war gerade am zweifeln, weil ich dachte, dass der ursprüngliche Code geht ...
Unter Windows funktioniert es nicht. Das Problem ist, dass er ständig neue componentResized Events erzeugt und sich so selbst zumüllt. Unter Windows (und vermutlich auch Linux) muss das setzen der Bildgröße tatsächlich wieder ein solches Event triggern... Das müllt die Queue so voll, dass er nicht mehr zeitig zu repaint kommt ... auch Fenster zu clicken wird nicht bearbeitet ...
Mal ein Code, der dann jetzt auch funktioniert - habe ein paar Ausgaben eingefügt (Debugging für Doofe ) und einfach mal eine mögliche Lösung eingebaut, die dann eben nichts macht, wenn die Größe unverändert ist. Also mehr ein Workaround: Das zusätzliche Event kommt aber dann interessiert es nicht, da wir nichts machen, was wieder ein Event triggern würde....
Was mich jetzt auch irritiert: Das Verhalten ist anders. Auf dem Mac war das Bild immer ganz zu sehen. Jetzt unter Windows bleibt das Ratio zwischen Höhe und Breite gleich und ich bekomme einen Hellen Streifen oben oder unten ...
Unter Windows hatte ich jetzt Java 11 und ein Notepad als Editor.
Unter Windows funktioniert es nicht. Das Problem ist, dass er ständig neue componentResized Events erzeugt und sich so selbst zumüllt. Unter Windows (und vermutlich auch Linux) muss das setzen der Bildgröße tatsächlich wieder ein solches Event triggern... Das müllt die Queue so voll, dass er nicht mehr zeitig zu repaint kommt ... auch Fenster zu clicken wird nicht bearbeitet ...
Was mich jetzt auch irritiert: Das Verhalten ist anders. Auf dem Mac war das Bild immer ganz zu sehen. Jetzt unter Windows bleibt das Ratio zwischen Höhe und Breite gleich und ich bekomme einen Hellen Streifen oben oder unten ...
Ich meine nicht. Das schien mir passend und das Bild wurde nicht verzerrt. Aber das schaue ich mir morgen noch mal genauer an, wenn ich wieder am Firmenrechner bin. (So ich die Zeit dazu finde)
ich habe mir das unter Windows noch etwas angeschaut und das Kernproblem ist, dass es unter Windows schlicht zu viele Events gibt. Dazu einfach einmal ein Frame nehmen und nur die Events ausgeben. e.paramString() reicht schon aus. Also minimal und sonst nichts machen. Und schon sieht man:
Beispiel von meinem System. Es wurden hier also u.a. 9 solcher Events nacheinander erzeugt.
Da der Code nun eine Bildverarbeitung macht und ein Bild erzeugt, wird das natürlich von der Verarbeitung schwer. Es müssen ja intern immer neue Images erzeugt werden (getScaledImage Aufruf), was vermutlich zu einem enormen Speicherdruck führt und dann neben dem Image erzeugen auch den GC triggern wird. Das müsste man noch verifizieren - ist also erst eine reine Vermutung.
Auf dem Mac habe ich das Problem etwas weniger, denn dort bekomme ich diese zusätzlichen Events nicht.
Die Lösung wäre jetzt also aus meiner Sicht, die Last bei der Aktion zu minimieren. Was man da machen kann, wäre ein Check der Größe, die ich schon vorgeschlagen habe. Das ist also eine Option. Aber da immer noch relativ viele Events kommen wenn man das Fenster mit der Maus in der Größe verändert (auch auf dem Mac habe ich bei einem Vorgang mehrere Events - aber halt nur keine doppelten pro Größe), ist eine Idee, dass man zeitverzögert agiert.
Swing hat einen Timer und den nutzen wir dann einfach einmal dafür. Wir suchen uns eine Verzögerung aus - das kann z.B. 100 ms sein.
In dem Event prüfen wir dann nur, ob der Timer bereits läuft. Sollte er noch nicht laufen, dann starten wir ihn.
Und wenn der Timer abgelaufen ist, dann machen wir den Resize des Bildes.
Dann ist das Bild immer mehr verzerrt - daher merken wir uns das Bild direkt nach dem laden und nutzen dieses gemerkte Bild für alle Scalings.
Und der Verdacht, dass wir bei der Größe immer hinterher hinken: Das prüfen wir auch. Dazu machen wir einfach einen Timer, der jede Sekunde die Framegröße ausgibt. Dann können wir sehen, ob die Größe wirklich hinterher hinkt bei den Events. (Edit: Was ich nicht bestätigen konnte. Im Rahmen meiner Tests hatte ich aber auch teilweise diesen Eindruck. Kann ich gerade aber nicht erklären zumal ich den Zustand nicht mehr habe und den genauen Code zu dem Zeitpunkt).
Das ergibt dann folgenden Code:
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class GUI {
public static final int REFRESH_TIMEOUT = 100;
JFrame frame;
JLabel label;
Timer timer;
ImageIcon hintergrund;
Image image;
public GUI() {
//Bilder
hintergrund = new ImageIcon(getClass().getResource("/testlevel.png"));
image = hintergrund.getImage();
//Fenster
frame = new JFrame("Erstes Spiel");
frame.setSize(1742,980);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());
//Label
label = new JLabel(hintergrund);
frame.add(label, BorderLayout.CENTER);
timer = new Timer(REFRESH_TIMEOUT, e -> doResize());
timer.setRepeats(false);
timer.setCoalesce(false);
Timer sizeReporter = new Timer(1000, e -> printSize());
sizeReporter.setRepeats(true);
sizeReporter.start();
//Bildgrösse ändern
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
System.err.println("Event: " + e.paramString() + " Frame Size: " + frame.getWidth() + "x" + frame.getHeight());
if (!timer.isRunning()) {
timer.restart();
}
}
});
frame.setVisible(true);
}
public void printSize() {
System.err.println("Frame Size: " + frame.getWidth() + "x" + frame.getHeight());
}
public void doResize() {
System.err.println("Frame Resize to " + frame.getWidth() + "x" + frame.getHeight());
hintergrund.setImage(image.getScaledInstance(frame.getWidth(), frame.getHeight(), Image.SCALE_SMOOTH));
frame.repaint();
}
public static void main(String[] args) {
new GUI();
}
}
(Habe noch die Frame Größe beim Event mit ausgegeben. Das Frame hat also die Größe, die im Event angegeben wird bei mir. Da läuft also nichts durcheinander ... )
Das einfach einmal als Idee, nach dem man mal eine Nacht drüber geschlafen hat
Edit: Die Prüfung des "hinterher Hinkens" hatte ich vergessen zu erwähnen. Der Code funktioniert bei mir auf Windows einwandfrei.
Es könnte sein, dass die IDE "Altlasten" beibehält. Der Code von #19 liefert unter Ubuntu mit OpenJDK 20 und Kommandozeile wohl dasselbe Verhalten wie unter Windows:
Wobei das so aussieht, dass es da unter Linux auch keine mehrfachen Events für eine Auflösung gibt. Die Zahlen bei COMPONENT_RESIZED scheinen alle unterschiedlich zu sein (wobei das nicht 100% auf dem Bildschirmfoto zu sehen ist). Das ist dann ggf. doch eine Thematik die speziell Windows betreffen könnte...
Das war der Punkt, den ich evtl. schlecht dargestellt hatte: Bei Windows hatte ich deutlich mehr Events ... und ich habe da nur die Events von einer Auflösung heraus kopiert... Also nicht nur, dass ich in kurzer Zeit eine Hand voll Events bekommen habe, weil ich halt mit der Maus das Fenster in der Größe verändert habe, sondern Windows hat sich den Spaß erlaubt, mir gleich noch ein vielfaches an Events zu geben....
Das evtl. nur noch zur Verdeutlichung des gefundenen Problems bei meinem Windows System.
Und natürlich: Danke M.L. fürs testen und berichten!
Aus welchen Posting-Nummern ? Aber im Grund werden in kurzen Zeitabständen "nur" Zusatzinformationen auf Konsole ausgegeben, wie gross das JFrame ist, wenn etwas bewegt wird oder sich seine Grösse verändert.
Schauen wir uns den Code einfach einmal im Detail an:
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class GUI {
public static final int REFRESH_TIMEOUT = 100;
/**
* Hauptfenster
*/
private JFrame frame;
/**
* Label, welches das Bild anzeigt
* ==> Tipp: Sollte dann auch so benannt sein. pictureLabel, backgroundLabel, ...
*/
JLabel label;
/**
* Timer für verzögertes Anpassen des Hintergrunds
* ==> Tipp: Sollte auch einen vernünftigen Namen haben. delayedDrawTimer oder so.
*/
Timer timer;
/**
* Das ImageIcon für den Hintergrund.
*/
ImageIcon hintergrund;
/**
* Das Hintergrundbild in original Größe.
* Wir wollen immer das original Bild verwenden um unnötige Verzerrungen zu vermeiden
* ==> Auch hier fehlt ein vernünftiger Name!
*/
Image image;
/**
* Creates a new instance of GUI
* <remark>
* Creates and shows the main window.
* </remark>
*/
public GUI() {
// Laden des ImageIcon mit dem Bild aus den Ressourcen.
// Damit kann das Bild auch im Jar file sein.
hintergrund = new ImageIcon(getClass().getResource("/testlevel.png"));
// Wir holen und das Bild und speichern es in der Variable für wiederholte Nutzung.
image = hintergrund.getImage();
//Fenster
frame = new JFrame("Erstes Spiel");
frame.setSize(1742,980);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());
//Label
label = new JLabel(hintergrund);
frame.add(label, BorderLayout.CENTER);
// Wir erstellen uns einen Swing Timer. Dieser wird auf dem UI Thread ausgeführt, somit
// gibt es keine Probleme mit mehreren Threads. (Das wäre beim java.util.Timer evtl. der Fall!)
// Der Timer soll, wenn gestartet, nur einmal laufen. Das zweite ist vermutlich nicht notwendig.
// Im Timer habe ich eine Lambda Expression genutzt, die doResize aufruft.
timer = new Timer(REFRESH_TIMEOUT, e -> doResize());
timer.setRepeats(false);
timer.setCoalesce(false);
// Dies ist einfach nur einw Debugging Hilfe. Wir wollen ständig die Größe des Fensters ausgeben.
// Das kannst Du komplett löschen.
Timer sizeReporter = new Timer(1000, e -> printSize());
sizeReporter.setRepeats(true);
sizeReporter.start();
// Hier kommt der ComponentListener.
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
// Eine Ausgabe (err, weil das ungepuffert ist)
// Die sollte weg!
System.err.println("Event: " + e.paramString() + " Frame Size: " + frame.getWidth() + "x" + frame.getHeight());
// Wir prüfen, ob der Timer bereits läuft.
// Wenn es also schon ein Event gab und der Timer noch nicht ausgelöst hat,
// dann wird das Event ignoriert.
if (!timer.isRunning()) {
// Wenn der Timer nicht läuft, dann wird er neu gestartet.
timer.restart();
}
}
});
// Am Ende machen wir das Fenster sichtbar.
// Wichtig: Dies sollte immer am Ende erfolgen!
frame.setVisible(true);
}
/**
* Einfache Ausgabe der Größe des Fensters.
*/
public void printSize() {
System.err.println("Frame Size: " + frame.getWidth() + "x" + frame.getHeight());
}
/**
* Verändern der Bildgröße.
*/
public void doResize() {
// Die Ausgabe sollte herausgenommen werden.
System.err.println("Frame Resize to " + frame.getWidth() + "x" + frame.getHeight());
// Hier wird der Hintergrund gesetzt.
// Was mir gerade auffällt: frame.getWidth() und frame.getHeight() sind nicht der sichtbare Bereich und
// daher vermutlich nicht ganz korrekt. frame.getRootPane().getWidth() bzw. getHeight() dürften besser sein.
// Einfach mal selbst schauen, ob ein Rand vom Bild nicht zu sehen ist. Also unten noch einen Strich
// machen oder so und schauen, ob der zu sehen ist.
hintergrund.setImage(image.getScaledInstance(frame.getWidth(), frame.getHeight(), Image.SCALE_SMOOTH));
// Ups. Das ist ein Überbleibsel meiner Tests. Das darf gehen! Du brauchst kein explizites repaint!
// Ein setImage auf ImageIcon führt selbstverständlich auch selbst ein repaint auf dem ImageIcon aus.
// Dieser Aufruf kann also weg!
frame.repaint();
}
/**
* Main method to start the application.
* @param args Unused application arguments.
*/
public static void main(String[] args) {
new GUI();
}
}
Bitte die Kommentare beachten. Mir sind halt direkt noch ein paar Dinge aufgefallen:
a) Die Namen der Variablen sind teilweise unschön. Da hatte ich so früh am Morgen nicht drauf geachtet.
b) Im doResize wird aus meiner Sicht die falsche Größe verwendet. Statt der Größe vom Frame muss es vermutlich die Größe der RootPane sein. Das solltest Du einmal ausprobieren / schauen.
Zu b)
Sobald Du im BorderLayout noch weitere Dinge nutzt, dann wird die RootPane auch größer sein. Da wäre dann eine eigene Pane notwendig, dessen Größe Du dann nehmen könntest meine ich.