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

图2

下面是服务器GUI的代码
GUI.java
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):
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();
}
}发布于 2015-01-26 02:18:34
所以,当Crazyjavahacking的回答直截了当地说的时候,我想添加一些东西。但在此之前,您可能还想看看使用BoxLayout的“正式”教程,甚至可能是JavaDoc。请记住,JavaDocs、谷歌和搜索在这样的情况下是你最好的朋友。)
更新:同时,关于运行Swing应用程序:Swing单线程规则
这是我不敢相信我错过的一件重要的事情,主要是因为我在过去的几周里一直在使用Swing接口。下面是一个答案的链接,它解释得比我以往任何时候都要好:事件调度线程。
关于我的补充..。
首先,使用GUI类和ServerController类的方式存在许多问题。首先,声明所有字段的public 是一个糟糕的主意。它不仅令人不悦,而且打破了一个非常基本的原则,即Java和面向对象编程()。我提供了一个链接,指向关于这个主题的一篇短文,这里有很多帖子,互联网上到处都有,所以我不打算在这里讨论。我感觉到的另一个问题是,您在GUI类中扩展了GUI。我知道这里有很多教程和例子,这些都表明了这一点,但是作为将来的参考,这样做并不是一个好主意。此外,我觉得你可能想重新考虑选择你的域名。例如,调用服务器开始按钮serverRunningState并不是最佳的名称选择。在我下面提供的代码中,它将在以后引起混乱。考虑给您的组件命名,比如,在本例中是serverStartButton。这个名称既告诉我组件的功能和它是什么,所以稍后会有更小的可能性变得困惑,或者必须返回到声明中去了解我正在处理的是什么。
我花时间对你的课程做了一次快速的重写,把这两件事记在心里。阅读下面的代码,直到您理解它。我将冒昧地猜测,您的应用程序大多是以这两个类的方式编写的,因此您很有可能不会简单地将它们放到适当的位置并让它们工作。但是花点时间去了解这里发生了什么,为什么,这将帮助你的未来工作更好。
值得注意的是,这些重写在任何意义上都是不彻底的。我主要解决了公共领域的使用问题。其余的将由你来纠正和改进:
GUI类:
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
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);
}
}
}发布于 2015-01-26 01:18:10
这种行为的原因是,一旦向JTextArea添加了某些内容,就必须重新绘制整个JPanel。而且,由于您没有显式设置对齐方式,Swing会将其对齐到中心,从而破坏您的UI。
您需要使用JPanel BoxLayout为中的所有组件显式指定对齐方式。
//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);在添加之后,它应该可以工作。
https://stackoverflow.com/questions/28142195
复制相似问题