首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java - BoxLayout

Java - BoxLayout
EN

Stack Overflow用户
提问于 2015-01-25 22:14:46
回答 2查看 550关注 0票数 0

我正在使用BoxLayout来定位我的Server的GUI元素。我的JLabels发生了一件奇怪的事情。我想知道为什么当我将一个字符串附加到我的JTextArea中时,JLabels会从它们原来的位置移动。第一个数字是位于正确位置的JLabels。第二个图像是JLabels倾斜的

图1

图2

下面是服务器GUI的代码

GUI.java

代码语言:javascript
运行
复制
package serverGUI;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class GUI extends JFrame{

    public JTextArea serverInfo;
    public JButton serverRunningState;
    public JLabel serverConnectionStatus = new JLabel(GUIConfig.DEFAULT_SERVER_STATUS);
    public JLabel serverInfoLabel = new JLabel(GUIConfig.DEFAULT_SERVER_EVENT_LABEL);

    public GUI(){
        super("Yahtzee Game Server");

        //set the server online/off-line status to default color
        serverConnectionStatus.setForeground(GUIConfig.DEFAULT_SERVER_STATUS_COLOR);

        //create the server events text area. It will hold all info
        //about server events including client connections/disconnections
        serverInfo = new JTextArea();
        serverInfo.setEditable(false);
        serverInfo.setPreferredSize(new Dimension(350, 450));

        //create the connect/disconnect button. Will be connect when server 
        //is not connected and disconnect when server is connected
        serverRunningState = new JButton();
        serverRunningState.setText("Run Server");

        //Create JPanel with box layout
        JPanel guiPanel = new JPanel();
        guiPanel.setLayout(new BoxLayout(guiPanel, BoxLayout.PAGE_AXIS));

        //add components to panel
        guiPanel.add(serverInfoLabel);
        guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
        guiPanel.add(serverInfo);
        guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
        guiPanel.add(serverConnectionStatus);

        //create a bit of space around components so they get away from edges
        guiPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

        //add panel to frame
        add(guiPanel, BorderLayout.CENTER);

        //create new panel for buttons
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));

        //add connection button
        serverRunningState.setAlignmentX(Component.CENTER_ALIGNMENT);
        buttonPanel.add(serverRunningState);
        buttonPanel.add(Box.createRigidArea(new Dimension(0,5)));
        //add panel to frame
        add(buttonPanel, BorderLayout.SOUTH);

        //set size, do not allow resize and show
        setSize(GUIConfig.DEFAULT_FRAME_WIDTH, GUIConfig.DEFUALT_FRAME_HEIGHT);
        setResizable(false);
        setVisible(true);

        //set it to terminate frame on exit
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public static void main(String args[]) {
        GUI g = new GUI();
    }
}

ActionListener Code (ServerController.java):

代码语言:javascript
运行
复制
package serverController;

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

import serverGUI.GUI;
import serverModel.AppServer;
import serverModel.Config;

public class ServerController {

    public AppServer server;
    public GUI serverGUI;

    public ServerController() {
        super();

        //create the view and add an action listener to know when run server
        //button is pressed
        serverGUI = new GUI();

        //add action listener on run server button
        serverGUI.serverRunningState.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e) {
                        //start server and disable run server button. change its text to server running
                        server = new AppServer(Config.DEFAULT_PORT);

                        if(server.isRunning() == true){
                            serverGUI.serverRunningState.setEnabled(false);
                            serverGUI.serverRunningState.setText("Server Running");
                            serverGUI.serverInfo.append("Server started!\nWaiting for new clients...\n\n");
                            serverGUI.serverInfo.setLineWrap(true);

                            //change JLabel to "Server Online" from "Server Off-line"
                            serverGUI.serverConnectionStatus.setText("Server Online");
                            serverGUI.serverConnectionStatus.setForeground(Color.GREEN);
                        }
                    }
                });
    }

    public void updateServerEventLog() {}

    private void checkServerStatus(AppServer s) {

    }

    public static void main(String args[]) {
        ServerController sController = new ServerController();
    }

}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-26 02:18:34

所以,当Crazyjavahacking的回答直截了当地说的时候,我想添加一些东西。但在此之前,您可能还想看看使用BoxLayout的“正式”教程,甚至可能是JavaDoc。请记住,JavaDocs、谷歌和搜索在这样的情况下是你最好的朋友。)

更新:同时,关于运行Swing应用程序:Swing单线程规则

这是我不敢相信我错过的一件重要的事情,主要是因为我在过去的几周里一直在使用Swing接口。下面是一个答案的链接,它解释得比我以往任何时候都要好:事件调度线程

关于我的补充..。

首先,使用GUI类和ServerController类的方式存在许多问题。首先,声明所有字段的public 是一个糟糕的主意。它不仅令人不悦,而且打破了一个非常基本的原则,即Java和面向对象编程()。我提供了一个链接,指向关于这个主题的一篇短文,这里有很多帖子,互联网上到处都有,所以我不打算在这里讨论。我感觉到的另一个问题是,您在GUI类中扩展了GUI。我知道这里有很多教程和例子,这些都表明了这一点,但是作为将来的参考,这样做并不是一个好主意。此外,我觉得你可能想重新考虑选择你的域名。例如,调用服务器开始按钮serverRunningState并不是最佳的名称选择。在我下面提供的代码中,它将在以后引起混乱。考虑给您的组件命名,比如,在本例中是serverStartButton。这个名称既告诉我组件的功能和它是什么,所以稍后会有更小的可能性变得困惑,或者必须返回到声明中去了解我正在处理的是什么。

我花时间对你的课程做了一次快速的重写,把这两件事记在心里。阅读下面的代码,直到您理解它。我将冒昧地猜测,您的应用程序大多是以这两个类的方式编写的,因此您很有可能不会简单地将它们放到适当的位置并让它们工作。但是花点时间去了解这里发生了什么,为什么,这将帮助你的未来工作更好。

值得注意的是,这些重写在任何意义上都是不彻底的。我主要解决了公共领域的使用问题。其余的将由你来纠正和改进:

GUI类:

代码语言:javascript
运行
复制
import javax.swing.*;
import java.awt.*;

public class GUI implements Runnable{

public GUI(){
    private JFrame frame = new JFrame("Yahtzee Game Server");

    //set the server online/off-line status to default color
    private JLabel serverConnectionStatus = new JLabel(GUIConfig.DEFAULT_SERVER_STATUS);
    serverConnectionStatus.setForeground(GUIConfig.DEFAULT_SERVER_STATUS_COLOR);

    //create the server events text area. It will hold all info
    //about server events including client connections/disconnections
    private JTextArea serverInfo = new JTextArea();
    serverInfo.setEditable(false);
    serverInfo.setPreferredSize(new Dimension(350, 450));

    //create the connect/disconnect button. Will be connect when server
    //is not connected and disconnect when server is connected
    private JButton serverRunningState = new JButton();
    serverRunningState.setText("Run Server");

    //Create JPanel with box layout
    private JPanel guiPanel = new JPanel();
    guiPanel.setLayout(new BoxLayout(guiPanel, BoxLayout.PAGE_AXIS));

    //add components to panel
    private JLabel serverInfoLabel = new JLabel(GUIConfig.DEFAULT_SERVER_EVENT_LABEL);
    guiPanel.add(serverInfoLabel);
    guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
    serverInfo.setAlignmentX(Component.LEFT_ALIGNMENT); // Fixed the actual problem
    guiPanel.add(serverInfo);
    guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
    serverConnectionStatus.setAlignmentX(Component.LEFT_ALIGNMENT); // Fixed the actual problem
    guiPanel.add(serverConnectionStatus);

    //create a bit of space around components so they get away from edges
    guiPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

    //add panel to frame
    frame.add(guiPanel, BorderLayout.CENTER);

    //create new panel for buttons
    JPanel buttonPanel = new JPanel();
    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));

    //add connection button
    serverRunningState.setAlignmentX(Component.CENTER_ALIGNMENT);
    buttonPanel.add(serverRunningState);
    buttonPanel.add(Box.createRigidArea(new Dimension(0,5)));
    //add panel to frame
    frame.add(buttonPanel, BorderLayout.SOUTH);

    // Add ActionListener 
    serverRunningState.addActionListener(new ServerController(
        serverRunningState, serverInfo, serverInfoLabel, serverConnectionStatus
    ));

    //set size, do not allow resize and show
    frame.setSize(GUIConfig.DEFAULT_FRAME_WIDTH, GUIConfig.DEFUALT_FRAME_HEIGHT);
    frame.setResizable(false);
    frame.setVisible(true);

    //set it to terminate frame on exit
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}

@Override
public void run() {
    // It seems to me folks like to include the code that sets the size,
    // close option, frame visibility, etc, here. But I don't believe it
    // necessary. However, any Swing gui you create needs to implement
    // Runnable and be instantiated in the manner shown in main().
    // See: https://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/
}
public static void main(String args[]) {
    //SwingUtilities.invokeLater() is another method aside from EventQueue.invokeLater()
    SwingUtilities.invokeLater(new GUI());
}
}

ActionListener

代码语言:javascript
运行
复制
import javax.swing.*;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ServerController implements ActionListener {
private JTextArea serverInfo;
private JLabel serverRunningState;
private JLabel serverConnectionStatus;
private JButton serverStartButton;

public ServerController(JButton serverStartButton,
                        JTextArea serverInfo,
                        JLabel serverRunningState,
                        JLabel serverConnectionStatus) {
    this.serverInfo = serverInfo;
    this.serverRunningState = serverRunningState;
    this.serverConnectionStatus = serverConnectionStatus;
    this.serverStartButton = serverStartButton;
}

@Override
public void actionPerformed(ActionEvent e) {
    server = new AppServer(Config.DEFAULT_PORT);

    if (server.isRunning()) { /* If this method is a boolean, putting
                                 (server.isRunning() == true) is pointless.
                                 It will either return true or not. */
        serverStartButton.setEnabled(false);
        serverStartButton.setText("Server Running");
        serverInfo.append(
            "Server started!\nWaiting for new clients...\n\n");
        serverInfo.setLineWrap(true);

        //change JLabel to "Server Online" from "Server Off-line"
        serverConnectionStatus.setText("Server Online");
        serverConnectionStatus.setForeground(Color.GREEN);
    }
}
}
票数 1
EN

Stack Overflow用户

发布于 2015-01-26 01:18:10

这种行为的原因是,一旦向JTextArea添加了某些内容,就必须重新绘制整个JPanel。而且,由于您没有显式设置对齐方式,Swing会将其对齐到中心,从而破坏您的UI。

您需要使用JPanel BoxLayout中的所有组件显式指定对齐方式。

代码语言:javascript
运行
复制
    //add components to panel
    serverInfoLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
    guiPanel.add(serverInfoLabel);
    guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
    serverInfo.setAlignmentX(Component.LEFT_ALIGNMENT);
    guiPanel.add(serverInfo);
    guiPanel.add(Box.createRigidArea(new Dimension(0,5)));
    serverConnectionStatus.setAlignmentX(Component.LEFT_ALIGNMENT);
    guiPanel.add(serverConnectionStatus);

在添加之后,它应该可以工作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28142195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档