忍受我。我正在制作一个Java控制台,类似于在https://code.google.com/p/dragonconsole/处找到的DragonConsole。一切都按计划进行,但是我想实现DragonConsole中的一项功能。我想增加一下使垂直滚动条延伸到框架底部的能力,就像在DC中一样。



这是我的。



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

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

现在,我浏览了DragonConsole的源代码,并通过复杂的方式告诉我这些东西是如何工作的。据我所知,有一个jTextArea用户可以在其中输入命令,但是我不知道垂直滚动条的功能如何。

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

您还可以看到,DC上的输入与垂直滚动条一起移动。我也该怎么做。



输入区域无处可看...




“ 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
    }




再次感谢您对@amurka的帮助:)

最佳答案

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

在此模式下,只有一个JTextPane,然后将其添加到JScrollPane。这就是滚动条延伸到底部的原因。然后,将KeyListener(keyPressed方法)和CaretListener(caretUpdate函数)添加到JTextPane。最后,它使用在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();
        }
    }
}

09-13 04:48