[英]Troubles with Java Swing
我有以下代碼:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main
{
public static void main(String[] args)
{
Window window = new Window("This is a title", 450, 350);
JButton buttonExit = new Button("Exit", 75, 25);
window.addElement(buttonExit);
window.build();
}
}
class Window // extend the current class
{
public Window window;
public JFrame frame;
public JPanel panel;
public String title;
// instantiate object with the constructor
public Window(String title, int width, int height)
{
this.frame = new JFrame(title);
this.frame.setPreferredSize(new Dimension(width, height));
this.frame.setLocationRelativeTo(null); // centers the main window relative to the center of the screen dimension
this.panel = new JPanel();
this.panel.setPreferredSize(new Dimension(width, height));
//this.panel.setLayout(new FlowLayout());
this.frame.add(panel);
}
public void build()
{
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.pack(); // removes all unnecessary pixel space from the form
this.frame.setVisible(true);
this.frame.setSize(frame.getPreferredSize());
}
public void addElement(JButton element)
{
this.panel.add(element);
}
}
class Button extends JButton // extend the current class
{
public Button(String text, int width, int height)
{
JButton button = new JButton();
button.setPreferredSize(new Dimension(width, height));
button.setText(text);
button.setVisible(true);
new ButtonHandler(button);
}
}
class ButtonHandler implements ActionListener
{
public ButtonHandler(JButton button)
{
button.addActionListener(this);
}
public void actionPerformed(ActionEvent actionEvent) {
System.exit(0);
}
}
我有兩個問題:
附帶說明一下,我知道我沒有在這里指定 LayoutManager,但是我之前已經實現了它,但它並沒有解決我的問題(我嘗試了 FlowLayoutManager 和 GridBagLayout [這將是我想要的,因為它靈活性])。
有人可以告訴我,我在這里做錯了什么嗎? 我之前只使用過 C# 和 WPF/WinForms...
您的自定義Button
class 在構造函數中是一個JButton
但也有一個JButton
(命名為button
)。 這里的問題是您將ButtonHandler
class 安裝到構造函數的button
,而不是自定義Button
本身(在構造函數內部稱為this
)。
When you set the [preferred] size of the JFrame
property named frame
(in the custom class named Window
), you are not setting the frame's contents' [preferred] size, but the size of the whole JFrame
, which includes the bar located at框架的頂部(具有框架的標題)。 這使得框架內容的空間小於首選大小,因為首選大小設置為整個框架。 我知道,您還設置了名為panel
的JPanel
的首選大小,它被添加到框架中,但是當您pack
框架時,優先考慮框架的首選大小而不是框架內容的首選大小,所以這可能就是您看到按鈕被壓縮的原因。
讓我用一些代碼來說明我的意思:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestFramePrefSz {
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final JFrame frame = new JFrame("Testing JFrame preferred size");
final JPanel contents = new JPanel();
contents.setPreferredSize(new Dimension(200, 200));
frame.setPreferredSize(new Dimension(200, 200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println(contents.getSize());
});
}
}
如您所見,打印的尺寸 object(這是面板的實際尺寸)約為 184x161 而不是請求的 200x200,因為框架的首選尺寸也設置為 200x200(包括框架的標題等)。 .)。
解決方案是僅設置內容的首選大小,而不是框架(至少在這種特定情況下)。
所以你應該:
this.frame.setSize(frame.getPreferredSize());
在build
方法中。this.frame.setPreferredSize(new Dimension(width, height));
在名為Window
的自定義 class 的構造函數中。 行this.frame.setLocationRelativeTo(null);
在名為Window
的自定義 class 的構造函數內部,在該位置無效。 想象一下,當你調用這個方法時,它必須確定框架的位置來設置它。 所以它需要首先知道屏幕的大小,然后是框架本身的大小。 但是,在您調用此方法時,框架的大小是多少? 大約是 0x0。 不是您可能期望的首選尺寸。 這使得框架位置的計算使得框架不會以屏幕為中心。 這是因為首選尺寸是框架的一個屬性,與尺寸不同。 因此,您要么必須在調用之前setSize
,要么最好設置框架內容的首選大小(即this.panel
),然后在框架上調用pack
並最后調用方法this.frame.setLocationRelativeTo(null)
. 然后您可以自由地將框架設置為可見,以查看它在屏幕中的位置(即應該居中)。
所以解決方案是遵循如下模式:
pack
(請記住,此調用將根據框架內容或框架本身的首選大小更改框架的大小)。setLocationRelativeTo(null)
。setVisible(true)
。如果您查看您的代碼,您正在執行以下操作:
setLocationRelativeTo(null)
(但框架的大小尚未設置)。panel
)。addElement
向panel
添加更多內容。pack
(記住框架的首選大小已設置到這一點,因此它將覆蓋任何其他首選大小,例如內容的首選大小)。setVisible(true)
。setSize
,並使用它的首選大小。 因此,您正在覆蓋框架從第 6 步開始的大小。不知道你用的是什么教程。 我推薦 Oracle 教程,使用 JFC/Swing 創建 GUI 。 您可以跳過 Netbeans 部分,但我建議您閱讀這些部分的 rest。
我創建了以下 GUI。
退出按鈕工作,處理 GUI。 右上角的 X 也處理 GUI。
這是可運行的示例代碼。 解釋遵循代碼。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JButtonExample implements Runnable{
public static void main(String[] args) {
SwingUtilities.invokeLater(new JButtonExample());
}
private JFrame frame;
@Override
public void run() {
frame = new JFrame("This is a title");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
exitProcedure();
}
});
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(300, 200));
panel.setBorder(BorderFactory.createEmptyBorder(
75, 100, 75, 100));
JButton button = new JButton("Exit");
button.addActionListener(new ExitListener(this));
panel.add(button, BorderLayout.CENTER);
return panel;
}
public void exitProcedure() {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
public class ExitListener implements ActionListener {
private JButtonExample example;
public ExitListener(JButtonExample example) {
this.example = example;
}
@Override
public void actionPerformed(ActionEvent event) {
example.exitProcedure();
}
}
}
我從main
方法調用SwingUtilities
invokeLater
方法。 此方法確保在Event Dispatch Thread上創建並執行 Swing 組件。
我將JFrame
代碼與JPanel
代碼分開。 這樣我就可以一次專注於 GUI 的一部分。
必須按特定順序調用JFrame
方法。 這是我用於大多數 Swing 應用程序的順序。
WindowListener
( WindowAdapter
) 讓我的代碼控制 JFrame 的關閉。 這將允許退出按鈕actionListener
關閉JFrame
。 WindowListener
不是一個簡單的概念。
JFrame
defaultCloseOperation
通常設置為 EXIT_ON_CLOSE。 為了使WindowListener
工作,我必須將defaultCloseOperation
設置為 DO_NOTHING_ON_CLOSE。
我讓JFrame
使用pack
方法確定自己的大小。
我設置了JPanel
的首選大小。
我為JPanel
創建了一個空邊框,因此JButton
將擴展以填充JPanel
的 rest。 這就是放置在 BorderLayout 中心的組件所發生的情況。
我創建了一個ExitListener
class。 因為它是一個內部 class,所以我不必創建構造函數或傳遞JButtonExample
實例。 我創建了一個構造函數,以便您可以看到它是如何完成的,以及actionListener
方法如何執行JButtonExample
class 的exitProcedure
方法。
我希望這個 JButton 示例對您有所幫助。 WindowListener 對於一個簡單的示例來說有點高級,但您可以看到它是如何完成的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.