2014-02-13 23 views
0

對於我的應用程序,我設計了一個腳本編輯器。目前,我有一個JPanel,其中包含另一個JPanel,其中包含行號(位於左側)和一個JTextArea,用於允許用戶鍵入他們的代碼(位於右側)。使JScrollPane控制多個組件

目前,我已在JTextArea上實施JScrollPane以允許用戶滾動瀏覽其代碼。

對於包含行號的JPanel,每當用戶按下回車鍵時它們都會遞增。

但是,問題是我想要相同的JScrollPane(在JTextArea上實現的JScrollPane)來控制行號JPanel的滾動;即當用戶在JTextArea上滾動時,行號JPanel也應該滾動。但由於行號保存在JPanel中,因此我無法將該組件添加到JTextArea。

用於容納所述的JTextArea和行號的JPanel JPanel類的構造函數:

private ScriptEditor() { 

    setBackground(Color.WHITE); 

    lineNumPanel = new LineNumberPanel(); 

    scriptArea = new JTextArea(); 
    scriptArea.setLineWrap(true); 
    scriptArea.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15)); 
    scriptArea.setMargin(new Insets(3, 10, 0, 10)); 

    JScrollPane scrollPane = new JScrollPane(scriptArea); 
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
    scrollPane.setPreferredSize(new Dimension(width, height)); 

    scriptArea.addKeyListener(this); 

    add(lineNumPanel); 
    add(scrollPane); 
} 

爲行號的JPanel這增加了在其自身內的JLabel來表示行號的構造:

public LineNumberPanel() { 

    setPreferredSize(new Dimension(width, height)); 

    box = Box.createVerticalBox(); 
    add(box); 

    //setup the label 
    label = new JLabel(String.valueOf(lineCount)); 
    label.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15)); 

    //setup the label alignment 
    label.setVerticalAlignment(JLabel.TOP); 
    label.setHorizontalAlignment(JLabel.CENTER); 
    label.setVerticalTextPosition(JLabel.TOP); 
    setAlignmentY(TOP_ALIGNMENT); 

    box.add(label); 
} 
+0

看看使用[文本組件行號(HTTP:// tips4java。來自Rob Camick博客的wordpress.com/2009/05/23/text-component-line-number/)。這是一個可用作包含文本區域的滾動窗格的行標題的組件。 –

回答

2

創建一個包含行號面板和文本區域的外部面板。所以你最終這種安排

然後把這個新的面板到滾動窗格中:

enter image description here

哪個代碼是一樣的東西:

private ScriptEditor() { 

    setBackground(Color.WHITE); 

    JPanel outerPanel = new JPanel(); 

    lineNumPanel = new LineNumberPanel(); 

    scriptArea = new JTextArea(); 
    scriptArea.setLineWrap(true); 
    scriptArea.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15)); 
    scriptArea.setMargin(new Insets(3, 10, 0, 10)); 

    outerPanel.add(lineNumPanel, BorderLayout.WEST) 
    outerPanel.add(scriptArea, BorderLayout.CENTER) 

    JScrollPane scrollPane = new JScrollPane(outerPanel); 
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
    scrollPane.setPreferredSize(new Dimension(width, height)); 

    scriptArea.addKeyListener(this); 

    add(lineNumPanel); 
    add(scrollPane); 
} 
0

我建議將這兩個組件放到面板中,然後將該面板放入滾動窗格中。

3

您應該使用JScrollPane#setRowHeaderView設置該組件將出現在滾動窗格的左側。

這樣做的好處是行標題不會滾動到左邊作爲視圖滾動到右邊...

示例故意使用換行...

Line Numbering

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.Insets; 
import java.awt.Point; 
import java.awt.Rectangle; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.DocumentEvent; 
import javax.swing.event.DocumentListener; 
import javax.swing.text.Element; 
import javax.swing.text.Utilities; 

public class ScrollColumnHeader { 

    public static void main(String[] args) { 
     new ScrollColumnHeader(); 
    } 

    public ScrollColumnHeader() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JTextArea ta = new JTextArea(20, 40); 
       ta.setWrapStyleWord(true); 
       ta.setLineWrap(true); 
       JScrollPane sp = new JScrollPane(ta); 
       sp.setRowHeaderView(new LineNumberPane(ta)); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(sp); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class LineNumberPane extends JPanel { 

     private JTextArea ta; 

     public LineNumberPane(JTextArea ta) { 
      this.ta = ta; 
      ta.getDocument().addDocumentListener(new DocumentListener() { 

       @Override 
       public void insertUpdate(DocumentEvent e) { 
        revalidate(); 
        repaint(); 
       } 

       @Override 
       public void removeUpdate(DocumentEvent e) { 
        revalidate(); 
        repaint(); 
       } 

       @Override 
       public void changedUpdate(DocumentEvent e) { 
        revalidate(); 
        repaint(); 
       } 
      }); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      FontMetrics fm = getFontMetrics(getFont()); 
      int lineCount = ta.getLineCount(); 
      Insets insets = getInsets(); 
      int min = fm.stringWidth("000"); 
      int width = Math.max(min, fm.stringWidth(Integer.toString(lineCount))) + insets.left + insets.right; 
      int height = fm.getHeight() * lineCount; 
      return new Dimension(width, height); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      FontMetrics fm = ta.getFontMetrics(ta.getFont()); 
      Insets insets = getInsets(); 

      Rectangle clip = g.getClipBounds(); 
      int rowStartOffset = ta.viewToModel(new Point(0, clip.y)); 
      int endOffset = ta.viewToModel(new Point(0, clip.y + clip.height)); 

      Element root = ta.getDocument().getDefaultRootElement(); 
      while (rowStartOffset <= endOffset) { 
       try { 
        int index = root.getElementIndex(rowStartOffset); 
        Element line = root.getElement(index); 

        String lineNumber = ""; 
        if (line.getStartOffset() == rowStartOffset) { 
         lineNumber = String.valueOf(index + 1); 
        } 

        int stringWidth = fm.stringWidth(lineNumber); 
        int x = insets.left; 
        Rectangle r = ta.modelToView(rowStartOffset); 
        int y = r.y + r.height; 
        g.drawString(lineNumber, x, y - fm.getDescent()); 

        // Move to the next row 
        rowStartOffset = Utilities.getRowEnd(ta, rowStartOffset) + 1; 
       } catch (Exception e) { 
        break; 
       } 
      } 
     } 

    } 

} 

正如我剛剛發現,@camickr有一個更加有用的例子,Text Component Line Number