簡體   English   中英

Java Swing 的故障

[英]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);
    }
}

我有兩個問題:

  1. 按鈕已壓縮,不會顯示其文本
  2. 我無法讓事件處理程序工作並且似乎不明白為什么

附帶說明一下,我知道我沒有在這里指定 LayoutManager,但是我之前已經實現了它,但它並沒有解決我的問題(我嘗試了 FlowLayoutManager 和 GridBagLayout [這將是我想要的,因為它靈活性])。

有人可以告訴我,我在這里做錯了什么嗎? 我之前只使用過 C# 和 WPF/WinForms...

問題一:

您的自定義Button class 在構造函數中是一個JButton但也有一個JButton (命名為button )。 這里的問題是您將ButtonHandler class 安裝到構造函數的button ,而不是自定義Button本身(在構造函數內部稱為this )。

問題 2:

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框架的頂部(具有框架的標題)。 這使得框架內容的空間小於首選大小,因為首選大小設置為整個框架。 我知道,您還設置了名為panelJPanel的首選大小,它被添加到框架中,但是當您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(包括框架的標題等)。 .)。

解決方案是僅設置內容的首選大小,而不是框架(至少在這種特定情況下)。

所以你應該:

  1. 刪除行this.frame.setSize(frame.getPreferredSize()); build方法中。
  2. 刪除行this.frame.setPreferredSize(new Dimension(width, height)); 在名為Window的自定義 class 的構造函數中。

問題 3:

this.frame.setLocationRelativeTo(null); 在名為Window的自定義 class 的構造函數內部,在該位置無效。 想象一下,當你調用這個方法時,它必須確定框架的位置來設置它。 所以它需要首先知道屏幕的大小,然后是框架本身的大小。 但是,在您調用此方法時,框架的大小是多少? 大約是 0x0。 不是您可能期望的首選尺寸。 這使得框架位置的計算使得框架不會以屏幕為中心。 這是因為首選尺寸是框架的一個屬性,與尺寸不同。 因此,您要么必須在調用之前setSize ,要么最好設置框架內容的首選大小(即this.panel ),然后在框架上調用pack並最后調用方法this.frame.setLocationRelativeTo(null) . 然后您可以自由地將框架設置為可見,以查看它在屏幕中的位置(即應該居中)。

所以解決方案是遵循如下模式:

  1. 創建框架,將框架的內容添加到其中並設置內容的首選大小。
  2. 在框架上調用pack (請記住,此調用將根據框架內容或框架本身的首選大小更改框架的大小)。
  3. 在框架上調用setLocationRelativeTo(null)
  4. 在框架上調用setVisible(true)

如果您查看您的代碼,您正在執行以下操作:

  1. 創建框架。
  2. 設置框架的首選大小。
  3. 在框架上調用setLocationRelativeTo(null) (但框架的大小尚未設置)。
  4. 將框架的內容添加到它(即panel )。
  5. 調用addElementpanel添加更多內容。
  6. 在框架上調用pack (記住框架的首選大小已設置到這一點,因此它將覆蓋任何其他首選大小,例如內容的首選大小)。
  7. 在框架上調用setVisible(true)
  8. 在框架上調用setSize ,並使用它的首選大小。 因此,您正在覆蓋框架從第 6 步開始的大小。

不知道你用的是什么教程。 我推薦 Oracle 教程,使用 JFC/Swing 創建 GUI 您可以跳過 Netbeans 部分,但我建議您閱讀這些部分的 rest。

我創建了以下 GUI。

JButton 示例 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();
        }

    }

}
  1. 我從main方法調用SwingUtilities invokeLater方法。 此方法確保在Event Dispatch Thread上創建並執行 Swing 組件。

  2. 我將JFrame代碼與JPanel代碼分開。 這樣我就可以一次專注於 GUI 的一部分。

  3. 必須按特定順序調用JFrame方法。 這是我用於大多數 Swing 應用程序的順序。

  4. WindowListener ( WindowAdapter ) 讓我的代碼控制 JFrame 的關閉。 這將允許退出按鈕actionListener關閉JFrame WindowListener不是一個簡單的概念。

  5. JFrame defaultCloseOperation通常設置為 EXIT_ON_CLOSE。 為了使WindowListener工作,我必須將defaultCloseOperation設置為 DO_NOTHING_ON_CLOSE。

  6. 我讓JFrame使用pack方法確定自己的大小。

  7. 我設置了JPanel的首選大小。

  8. 我為JPanel創建了一個空邊框,因此JButton將擴展以填充JPanel的 rest。 這就是放置在 BorderLayout 中心的組件所發生的情況。

  9. 我創建了一個ExitListener class。 因為它是一個內部 class,所以我不必創建構造函數或傳遞JButtonExample實例。 我創建了一個構造函數,以便您可以看到它是如何完成的,以及actionListener方法如何執行JButtonExample class 的exitProcedure方法。

我希望這個 JButton 示例對您有所幫助。 WindowListener 對於一個簡單的示例來說有點高級,但您可以看到它是如何完成的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM