Java终端 - 开发

时间:2014-05-08 23:22:49

标签: java scrollbar console-application

忍受我。我正在创建一个java控制台,类似于此处{Dragon}的DragonConsole https://code.google.com/p/dragonconsole/。一切都按计划进行,但我想实现DragonConsole内部的功能。我想补充我的能力,让垂直滚动条延伸到框架的底部,就像它在DC中一样。

DragonConsole example

这是我的。

My console

正如您所看到的,垂直滚动条没有延伸到底部,而IMO,它看起来不专业。但我仍然是一个业余爱好者:D

以下是我的程序的组织方式:输出是一个jScrollPane,输入是一个简单的jTextField。用户输入输入,并显示结果输出。

现在,我已经查看了DragonConsole的来源,以及让我知道这些东西如何运作的复杂方法。据我所知,有一个jTextArea,用户输入命令,但我不知道垂直滚动条的功能如何。

请问我可以帮我模仿DragonConsole的滚动条吗?

同样如您所见,DC上的输入与垂直滚动条一起移动。我怎么能这样做。

enter image description here

输入区域无处可见......


“cls”命令调用此函数:

public void clear() {
        console.setText("");
        print(""); // printing will automatically print the '> ' at the beginning
        startIndex = console.getText().length();
    }

打印功能:

public void print(String s) { // prints output to the console
        console.append(System.lineSeparator() + prompt + s);
    }

产生错误:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: bad position: 110
    at javax.swing.text.JTextComponent.setCaretPosition(JTextComponent.java:1678)   at javax.swing.text.JTextComponent.setCaretPosition(JTextComponent.java:1678)
    at Main.Terminal.caretUpdate(Terminal.java:198)
    at javax.swing.text.JTextComponent.fireCaretUpdate(JTextComponent.java:407)
    at javax.swing.text.JTextComponent$MutableCaretEvent.fire(JTextComponent.java:4417)
    at javax.swing.text.JTextComponent$MutableCaretEvent.stateChanged(JTextComponent.java:4439)
    at javax.swing.text.DefaultCaret.fireStateChanged(DefaultCaret.java:798)
    at javax.swing.text.DefaultCaret.changeCaretPosition(DefaultCaret.java:1273)
    at javax.swing.text.DefaultCaret.handleSetDot(DefaultCaret.java:1169)
    at javax.swing.text.DefaultCaret.setDot(DefaultCaret.java:1150)
    at javax.swing.text.DefaultCaret$Handler.removeUpdate(DefaultCaret.java:1796)
    at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:260)
    at javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:623)
    at javax.swing.text.AbstractDocument.remove(AbstractDocument.java:591)
    at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:667)
    at javax.swing.text.JTextComponent.setText(JTextComponent.java:1718)
    at Main.Terminal.doCommand(Terminal.java:218)
    at Main.Terminal.keyPressed(Terminal.java:168)
    at java.awt.Component.processKeyEvent(Component.java:6463)
    at javax.swing.JComponent.processKeyEvent(JComponent.java:2829)
    at java.awt.Component.processEvent(Component.java:6282)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4861)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1895)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:762)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1027)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:899)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:727)
    at java.awt.Component.dispatchEventImpl(Component.java:4731)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:729)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:688)
    at java.awt.EventQueue$3.run(EventQueue.java:686)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:702)
    at java.awt.EventQueue$4.run(EventQueue.java:700)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:699)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

这似乎指向了一个问题:

@Override
    public void caretUpdate(CaretEvent e) {
        // Ensure that the caret position can only be a valid location
        if (e.getDot() < startIndex) {
            console.setCaretPosition(startIndex);
            Toolkit.getDefaultToolkit().beep();
        }
    }

修复错误的代码

public void clear() {
        startIndex = 0; // set it to zero to prevent error from happening
        console.setText(""); // this will erase anything on screen, but start the input seqence on the next line
    }

enter image description here

再次感谢你的帮助@amurka:)

1 个答案:

答案 0 :(得分:2)

查看DragonConsole源代码,它支持两种模式:内联和非内联。滚动条延伸到底部的第一张图片是内嵌模式下的DragonConsole。

在此模式下,它只是一个JTextPane,然后会添加到JScrollPane。这就是滚动条延伸到底部的原因。然后,它会向KeyListener添加CaretListener(keyPressed方法)和JTextPane(caretUpdate函数)。最后,它使用DocumentFilter类中实现的自定义InputController来获取您看到的控制台行为。

总结如下:

  • 创建JTextPane。查看DragonConsole.java中的initializeConsole()
  • CaretListenerKeyListener添加到该文本窗格。查看DragonConsole.java中的caretUpdate()keyPressed()
  • 设置自定义DocumentFilter。查看InputController.java(实际上,在inializeConsole方法中设置文档样式。)

你这样做的方式几乎与DragonConsole在内联模式下的方式相同。在这种情况下,输出区域使用JTextPane,输入区域使用JTextArea,对于滚动条看起来应该相同。

修改:这是内联控制台的一个非常简单的示例。

public class Console extends JPanel implements KeyListener, CaretListener {

    private static final String PROMPT = ">>";

    private JScrollPane scrollPane;
    private JTextArea consoleTextPane;

    private int startIndex;

    public Console() {
        super();

        // Create a text area
        consoleTextPane = new JTextArea();
        consoleTextPane.setText(PROMPT);
        consoleTextPane.setBorder(null);
        // Wraps the text if it goes longer than a line, but NOT on word boundary
        // like a normal console
        consoleTextPane.setLineWrap(true);
        consoleTextPane.setWrapStyleWord(false);

        // Set the initial caret position
        startIndex = consoleTextPane.getText().length();
        consoleTextPane.setCaretPosition(startIndex);

        // Add the caret and key listeners
        consoleTextPane.addCaretListener(this);
        consoleTextPane.addKeyListener(this);

        // Scrollbar, always show the vertical one
        scrollPane = new JScrollPane(consoleTextPane);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setBorder(null);

        JPanel panelCenter = new JPanel(new BorderLayout());
        panelCenter.setPreferredSize(new Dimension(400, 200));
        panelCenter.add(scrollPane, BorderLayout.CENTER);

        add(panelCenter, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Console");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(new Console());
        frame.pack();
        frame.setVisible(true);
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // All processing in keyPressed
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // All processing in keyPressed
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch(e.getKeyCode()) {
            case KeyEvent.VK_ENTER:
                // ENTER key was pressed
                // Get the "Command"
                String command = consoleTextPane.getText().substring(startIndex);

                if (!command.isEmpty()) {
                    // TODO: do something with the command
                    consoleTextPane.append(System.lineSeparator() 
                            + "Command Entered: " + command);
                }

                // Update the start index and append a new prompt
                consoleTextPane.append(System.lineSeparator() + PROMPT);
                startIndex = consoleTextPane.getText().length();

                // Consume the ENTER key event so further processing is not
                // performed
                e.consume();
                break;
            case KeyEvent.VK_BACK_SPACE:
                // Make sure this is a valid delete
                if (consoleTextPane.getCaretPosition() <= startIndex) {
                    e.consume();
                    Toolkit.getDefaultToolkit().beep();
                }

                break;
            // TODO: add key presses here as desired
            default:
                //System.out.println("Unhandled: " + e.getKeyCode());
                break;
        }
    }

    @Override
    public void caretUpdate(CaretEvent e) {
        // Ensure that the caret position can only be a valid location
        if (e.getDot() < startIndex) {
            consoleTextPane.setCaretPosition(startIndex);
            Toolkit.getDefaultToolkit().beep();
        }
    }
}