【问题标题】:Scroll Bar not appearing along with JTextArea滚动条没有与 JTextArea 一起出现
【发布时间】:2018-07-23 10:16:54
【问题描述】:

好的,所以我最近制作了一个 java 控制台应用程序,它会暴力破解您的密码,所以现在我正在开发一个类似的应用程序,但使用的是 gui。 所以我有所有代码及其运行,但由于某种原因,我添加到 textArea 的滚动条没有出现,当我运行程序时,我既没有得到滚动条,也没有得到文本区域。 请告诉我哪里出错并帮助我解决这个问题。

package swinggui;

import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

public class BruteForce {
    static JFrame frameObject;
    static JPanel panelObject;

JLabel lblPassword;
JTextField txtPassword;
JTextArea txtStatus;
JScrollPane scrollbar;

JButton btn;

BruteForce() {
    panelObject = new JPanel();
    frameObject.getContentPane().add(panelObject);
    panelObject.setLayout(null);

    txtStatus = new JTextArea("Status: ");
    txtStatus.setBounds(10,95,260,160);
    panelObject.add(txtStatus);

    lblPassword = new JLabel("Password: ");
    txtPassword = new JTextField();

    Font dialog = new Font("Dialog", Font.PLAIN, 14);

    lblPassword.setBounds(10,10,100,30);
    lblPassword.setFont(dialog);
    panelObject.add(lblPassword);

    txtPassword.setBounds(80,10,190,30);
    panelObject.add(txtPassword);

    scrollbar = new JScrollPane(txtStatus);
    panelObject.add(scrollbar);

    btn = new JButton("Test Password Strength");
    btn.setBounds(10,50,260,30);
    panelObject.add(btn);

    btn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            int password = Integer.parseInt(txtPassword.getText());

            int guess_password = 0;
            while(guess_password != password) {
                txtStatus.append("\n [+] Password Attempt: " + guess_password);
                guess_password = guess_password + 1;
            }
            if(guess_password == password) {
                txtStatus.append("\n \n [-] Password Found: " + guess_password);
            }
        }
    }); 
}
public static void main(String[] args) throws Exception {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    frameObject = new JFrame("Brute Force Tool");
    frameObject.setVisible(true);
    frameObject.setSize(300,300);
    frameObject.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    BruteForce gui = new BruteForce();
}

}

请告诉我哪里出错并更正我的代码。 任何帮助将不胜感激,并提前致谢。

【问题讨论】:

  • 请发布您的代码
  • @RoyalSlayer YT 首先不要使用null 布局使用布局管理器。第二件事您不需要将文本区域添加到面板中,将文本区域添加到 ScrollPane 然后将 setboundsScrollPane 而不是文本区域。

标签: java swing jscrollpane jtextarea


【解决方案1】:

首先一个重要提示:不要使用空布局。请学习所有标准 layout manager 并使用它们来填充您的 UI。您也可以使用一些第三方布局管理器,例如 MigLayout 或 FormLayout(使用 Google 查找它们)。这些经理通常比标准更好。

为什么它比空布局更好?因为 Java-UI 是跨平台的,并且某些组件在不同的操作系统上可能需要不同的大小。当用户使用某些操作系统功能(如字体缩放)时,也会发生同样的情况。布局管理器还定义了调整大小的行为(当用户更改窗口大小时应该发生什么)。

这是您的代码的更正版本(无需更改布局管理器)。

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;

public class BruteForce {
    static JFrame frameObject;

    JPanel panelObject;

    JLabel lblPassword;

    JTextField txtPassword;

    JTextArea txtStatus;

    JScrollPane scrollbar;

    JButton btn;

    BruteForce() {
        panelObject = new JPanel();
        frameObject.getContentPane().add(panelObject);
        panelObject.setLayout(null);

        txtStatus = new JTextArea("Status: ");
        // set bounds not required here. it's required for scrollbar
        // txtStatus.setBounds(10,95,260,160);
        panelObject.add(txtStatus);

        lblPassword = new JLabel("Password: ");
        txtPassword = new JTextField();

        Font dialog = new Font("Dialog", Font.PLAIN, 14);

        lblPassword.setBounds(10, 10, 100, 30);
        lblPassword.setFont(dialog);
        panelObject.add(lblPassword);

        txtPassword.setBounds(80, 10, 190, 30);
        panelObject.add(txtPassword);

        scrollbar = new JScrollPane(txtStatus);
        // set the scroll bar bounds
        scrollbar.setBounds(10, 95, 260, 160);
        panelObject.add(scrollbar);

        btn = new JButton("Test Password Strength");
        btn.setBounds(10, 50, 260, 30);
        panelObject.add(btn);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int password = Integer.parseInt(txtPassword.getText());

                int guess_password = 0;
                while (guess_password != password) {
                    txtStatus.append("\n [+] Password Attempt: " + guess_password);
                    guess_password = guess_password + 1;
                }
                if (guess_password == password) {
                    txtStatus.append("\n \n [-] Password Found: " + guess_password);
                }
            }
        });
    }

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        frameObject = new JFrame("Brute Force Tool");
        BruteForce gui = new BruteForce();
        frameObject.add(gui.panelObject); // don't forget to place your panel in the window
        frameObject.setSize(300, 300);
        frameObject.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frameObject.setLocationRelativeTo(null); // center location for window
        frameObject.setVisible(true);
    }

}

【讨论】:

    【解决方案2】:

    您确实意识到,如果您提供一个整数密码值(例如 55673),并且如果您在循环中一次一个地遍历每个值,那么您不需要应用程序来确定密码编号尝试获取该密码的次数(55673 次迭代)。我们只是把它作为一个例子。 :/

    在我看来,您的特定项目存在一些需要注意的问题:

    为了更简单的编码,设置 BruteForce 类使其扩展 JFramepublic class BruteForce extends javax.swing.JFrame {。您不需要静态 JFrame 变量 (frameObject),它会稍微清理一下。

    ma​​in() 方法中取出所有与 JFrame 相关的代码。请改为在 initialization 方法中设置 JFrame。在我看来,我认为你的 ma​​in() 方法会更好,如果你有:

    public static void main(String[] args) throws Exception {
       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    
       /* Create and display the form */
       java.awt.EventQueue.invokeLater(new Runnable() {
           @Override
           public void run() {
               new BruteForce().setVisible(true);
           }
       });
    }
    

    您的初始化方法可能如下所示:

    private void initializeComponents() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Brute Force Tool");
        setResizable(false);
        setAlwaysOnTop(true);
    
    
        // Size the Form
        // Slightly different from original size since
        // form has been made non-resizable. Makes the
        // form more uniformed.
        setPreferredSize(new Dimension(285, 325));
        setSize(getPreferredSize());
    
        // Center Form to screen. Should always be after sizing
        setLocationRelativeTo(null); 
    
        panelObject = new JPanel();
        panelObject.setLayout(null);
    
        // Password Box Label
        Font dialog = new Font("Dialog", Font.PLAIN, 14);
        lblPassword = new JLabel("Password: ");
        lblPassword.setBounds(10, 10, 100, 30);
        lblPassword.setFont(dialog);
        panelObject.add(lblPassword);
    
        // Password Entry Text Field
        txtPassword = new JTextField();
        txtPassword.setBounds(80, 10, 190, 30);
        panelObject.add(txtPassword);
    
        // Text Area with Scroll Pane to display 
        // Brute Force process.
        txtStatus = new JTextArea("Status: ");
        scrollbar = new JScrollPane(txtStatus);
        scrollbar.setBounds(10, 125, 260, 160);
        panelObject.add(scrollbar);
    
        // Button to start Brute Force Process
        btn = new JButton("Test Password Strength");
        btn.setBounds(10, 50, 260, 30);
        panelObject.add(btn);
    
        // Display Progress CheckBox
        chkUpdateStatus = new JCheckBox("Display Progress");
        chkUpdateStatus.setBounds(10, 85, 150, 30);
        panelObject.add(chkUpdateStatus);
    
        // Scroll Progress CheckBox
        chkScrollUpdate = new JCheckBox("Scroll Progress");
        chkScrollUpdate.setBounds(160, 85, 150, 30);
        panelObject.add(chkScrollUpdate);
    
        // Add filled JPanel to JFrame
        panelObject.setBounds(this.getBounds());
        getContentPane().add(panelObject);
    
    
        // Add Button Action Listener
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!workThreadIsRunning) { 
                    // Clear the TextArea
                    txtStatus.setText(null);
                    new Thread(workThread).start(); 
                }
                if (btn.getText().equals("Cancel Test")) {
                    shutDownThread = true;
                }
            }
        });
    }
    

    这意味着您的类构造函数 (BruteForce()) 仅包含:

    public BruteForce() {
        initializeComponents();
    }
    

    如果您不打算使用 JFrame#pack() 以便 JFrame 根据其所有内容自动调整大小,等于或大于其首选大小,则 setSize() 自行调整 JFrame 大小的方法对您没有多大帮助。在这种情况下,您还需要使用 setPreferredSize() 方法。

    创建表单时,您希望将 JTextArea 添加到 JScrollPane,而不是 JPanel。然后它将是您添加到 JPanel 中的 JScrollPane。

    JTextArea 的 setBounds() 不是必需的,因为它将填充整个 JScrollPane 容器。对于您使用的 null 布局,它将是需要提供 setBounds() 的 JScrollPane。

    由于您使用的是 Null 布局并且您的应用程序窗口是 确实足够小,并且您已经为所有组件设置了边界,您还应该确保无法调整 JFrame 窗口的大小(setResizable(false);),因为如果是这样,表单看起来会很荒谬。我相信您已经被告知了为什么 Null 布局不一定是一个好的选择。但如果这对你来说还不够,那么谷歌这个:Why is null layout in Swing frowned upon?。然而,它确实在世界上占有一席之地,尤其是在使用多种布局时。

    附带说明:

    可以理解,在处理这样的事情时,通常很高兴在执行过程中看到该过程的进度。可悲的现实是,在尝试这样做时,速度会严重受到阻碍。

    要通过在 JTextArea 上附加一行指示已处理的暴力尝试(迭代)来有效更新 JTextArea,您需要使用新线程来执行该更新。这当然意味着处理(尝试)是在单独的线程中执行的,而不是在事件调度线程(EDT)中完成,在所有处理完成之前不会更新 JTextArea(这就是您在代码中所做的) )。通过将处理代码放置在其自己的线程中立即更新 JTextArea 确实是唯一可行的选择,但将更新写入 JTextArea 确实需要时间......事实上相当长的时间。

    例如,如果您运行下面提供的可运行代码(您的代码已修改)并提供密码 222222,在我的系统上大约需要 2147 毫秒(大约 2 秒)完成任务。如果您要在循环中注释掉 textStatus.append(...),您会发现只需要大约 6 毫秒(大约 0.006 秒)即可完成任务。这是处理时间的一个非常显着的差异,如果您正在执行类似 Brute Force 之类的操作,您希望获得每一个速度。如果您希望 JTextArea 自动滚动以便在视口中显示每个更新,那么速度会受到更多的阻碍。

    进度显示应该是可选的,可以使用我在下面的示例可运行代码中实现的复选框,并且由于蛮力处理是在其自己的线程而不是 EDT 中完成的,因此对复选框的任何更改都会立即生效影响。该按钮还具有更多的切换效果,因此可以取消蛮力处理。

    这是完整的代码:

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    
    
    public class BruteForce extends javax.swing.JFrame {
    
        JPanel panelObject;
        JLabel lblPassword;
        JTextField txtPassword;
        JTextArea txtStatus;
        JScrollPane scrollbar;
        JButton btn;
        JCheckBox chkUpdateStatus;
        JCheckBox chkScrollUpdate;
        Runnable workThread;
        boolean workThreadIsRunning = false;
        volatile boolean shutDownThread = false;
    
        public BruteForce() {
            initializeComponents();
    
            workThread = new Runnable() {
                @Override
                public void run() {
                    long startTime = System.currentTimeMillis();
                    workThreadIsRunning = true;
                    int password = Integer.parseInt(txtPassword.getText());
                    btn.setText("Cancel Test");
                    int guess_password = 0;
                    while (guess_password != password & !shutDownThread) {
                        if (chkUpdateStatus.isSelected()) {
                            txtStatus.append("\n [+] Password Attempt: " + String.valueOf(guess_password + 1));
                            if (chkScrollUpdate.isSelected()) {
                                // Update The JTextArea to show immediate processing.
                                // (Slows down processing considerably)
                                txtStatus.setCaretPosition(txtStatus.getText().length() - 1);
                            }
                        }
                        guess_password++;
                    }
                    long duration = System.currentTimeMillis() - startTime;
                    if (guess_password == password) {
                        txtStatus.append("\n \n [-] Password Found: " + guess_password);
                        txtStatus.append("\n [-] It took " + duration + " milliseconds\n     "
                                       + "(just over " + String.valueOf(duration / 1000) + " seconds) "
                                       + "to\n     accomplish.");
                        txtStatus.setCaretPosition(txtStatus.getText().length() - 1);
                    }
                    workThreadIsRunning = false;
                    btn.setText("Test Password Strength");
                    shutDownThread = false;
                }
            };
        }
    
        private void initializeComponents() {
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            setTitle("Brute Force Tool");
            setResizable(false);
            setAlwaysOnTop(true);
    
    
            // Size the Form
            // Slightly different from original size since
            // form has been made non-resizable. Makes the
            // form more uniformed.
            setPreferredSize(new Dimension(285, 325));
            setSize(getPreferredSize());
    
            // Center Form to screen. Should always be after sizing
            setLocationRelativeTo(null); 
    
            panelObject = new JPanel();
            panelObject.setLayout(null);
    
            // Password Box Label
            Font dialog = new Font("Dialog", Font.PLAIN, 14);
            lblPassword = new JLabel("Password: ");
            lblPassword.setBounds(10, 10, 100, 30);
            lblPassword.setFont(dialog);
            panelObject.add(lblPassword);
    
            // Password Entry Text Field
            txtPassword = new JTextField();
            txtPassword.setBounds(80, 10, 190, 30);
            panelObject.add(txtPassword);
    
            // Text Area with Scroll Pane to display 
            // Brute Force process.
            txtStatus = new JTextArea("Status: ");
            scrollbar = new JScrollPane(txtStatus);
            scrollbar.setBounds(10, 125, 260, 160);
            panelObject.add(scrollbar);
    
            // Button to start Brute Force Process
            btn = new JButton("Test Password Strength");
            btn.setBounds(10, 50, 260, 30);
            panelObject.add(btn);
    
            // Display Progress CheckBox
            chkUpdateStatus = new JCheckBox("Display Progress");
            chkUpdateStatus.setBounds(10, 85, 150, 30);
            panelObject.add(chkUpdateStatus);
    
            // Scroll Progress CheckBox
            chkScrollUpdate = new JCheckBox("Scroll Progress");
            chkScrollUpdate.setBounds(160, 85, 150, 30);
            panelObject.add(chkScrollUpdate);
    
            // Add filled JPanel to JFrame
            panelObject.setBounds(this.getBounds());
            getContentPane().add(panelObject);
    
    
            // Add Button Action Listener
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!workThreadIsRunning) { 
                        // Clear the TextArea
                        txtStatus.setText(null);
                        new Thread(workThread).start(); 
                    }
                    if (btn.getText().equals("Cancel Test")) {
                        shutDownThread = true;
                    }
                }
            });
        }
    
        public static void main(String[] args) throws Exception {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    
            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new BruteForce().setVisible(true);
                }
            });
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-03-05
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      • 2011-10-02
      • 1970-01-01
      相关资源
      最近更新 更多