使用JTextField调整文本大小

3

我有一个JTextField textField和一个任意的String string

我想让文本框显示字符串的末尾,但截断不能适合的部分,并用"..."代替它。例如,如果字符串是"Hello How Are You Doing",那么文本框可能看起来像

...re You Doing

给定textfieldstring,我该怎么做?
更新:我想这样做的原因是因为它是一个文件选择器,所以我想优先显示文件的结尾。例如,如果用户选择在/Users/Name/Documents/Folder1/Folder2/Folder3/file.txt保存,则我希望显示结尾,而不能适合的其余部分应该被替换为“...”。
这是完成的地方:
JFileChooser chooser = new JFileChooser();
int response = chooser.showSaveDialog(this);
if(response == JFileChooser.APPROVE_OPTION) {
    File file = chooser.getSelectedFile();
    String string = file.getAbsolutePath();

    fileTextField.setText(/* here's where the code would go */);
}

1
显示字符串的结尾,但截断无法容纳的部分。为什么要相反地对待通常的字符串末尾修剪方式?这似乎非常不直观。 - Andrew Thompson
JTextField 具有自动滚动功能,但是像 JLabel 这样的控件会更好吗? - MadProgrammer
@trashgod,它不需要切断以保留一个单词。 - CodeGuy
1
@CodeGuy,您关心固定的“String”长度还是可用空间? - MadProgrammer
使用SwingConstants和ComponentOrientations没有任何hacky的方法,不要截断可见文本,这很疯狂。 - mKorbel
显示剩余7条评论
3个回答

5
我建议采用以下两种方法作为替代方案,或者在文件名后面加上工具提示(路径)。

..这是一个文件选择器,所以我希望优先显示文件的结尾。

FileListName

import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.io.File;

class FileListName {

    final class FileListCellRenderer extends DefaultListCellRenderer {

        private FileSystemView fsv = FileSystemView.getFileSystemView();

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            JLabel l = (JLabel) c;
            File f = (File) value;
            l.setText(f.getName());
            l.setIcon(fsv.getSystemIcon(f));
            l.setToolTipText(f.getAbsolutePath());

            return l;
        }
    }

    public FileListName() {
        JFileChooser jfc = new JFileChooser();
        jfc.showOpenDialog(null);
        if (jfc.getSelectedFile() != null) {
            File[] f = {jfc.getSelectedFile()};
            JList list = new JList(f);
            list.setVisibleRowCount(1);
            list.setCellRenderer(new FileListCellRenderer());
            JOptionPane.showMessageDialog(null, list);
        }
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                try {
                    // Provides better icons from the FSV.
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                new FileListName();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }
}

@MadProgrammer 由于图标只需要几个按键就能添加,我忍不住加上了它。 :) - Andrew Thompson

3
你将会面临的问题是,String#length 和像素宽度不匹配。你需要考虑当前字体、组件宽度、图标、图标间距、插入、屏幕 DPI 等等 :P
public class TrimPath {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());

                File path = new File("C:\\Users\\Default\\AppData\\Local\\Microsoft\\Windows\\GameExplorer");
                TrimmedLabel label = new TrimmedLabel(path.getPath());
                label.setIcon(FileSystemView.getFileSystemView().getSystemIcon(path));

                frame.add(label);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TrimmedLabel extends JLabel {

        private String masterText;

        public TrimmedLabel(String text) {
            super(text);
        }

        @Override
        public void setText(String text) {
            if (masterText == null ? text != null : !masterText.equals(text)) {
                masterText = text;
                super.setText(text);
            }
        }

        @Override
        public String getText() {

            String text = getMasterText();

            if (text != null && text.length() > 0) {
                int width = getWidth();
                Icon icon = getIcon();
                if (icon != null) {
                    width -= (icon.getIconWidth() + getIconTextGap());
                }
                FontMetrics fm = getFontMetrics(getFont());
                if (width > 0 && fm != null) {
                    int strWidth = fm.stringWidth(text);
                    if (strWidth > width) {
                        StringBuilder sb = new StringBuilder(text);
                        String prefix = "...";
                        while (fm.stringWidth(prefix + sb.toString()) > width) {
                            sb.delete(0, 1);
                        }
                        text = prefix + sb.toString();
                    }
                }
            }
            return text;
        }

        public String getMasterText() {
            return masterText;
        }
    }
}

1
条件 if (width > 0 && fm != null) 应该还包括对 text 的非空检测: if (width > 0 && fm != null && text != null),否则下一行可能会出现 NPE。 - Guillaume Polet
@GuillaumePolet 公平的观点,我已经添加了对null和空字符串的检查,谢谢 - MadProgrammer

0

可以通过设置自己的文档来完成

(这是快速且不太精确的,所以要多次测试)

final int CHAR_DISPLAY_MAX = 10;
final int REPLACE_NUMBER = 3;
final JTextField tf = new JTextField(7);
Document doc = new PlainDocument(){
  public void insertString(int offs, String str, AttributeSet a) throws BadLocationException{
    if (this.getLength() + str.length() > CHAR_DISPLAY_MAX)
    {
      String oldText = tf.getText();
      String newText = oldText+str;
      tf.setText("..."+newText.substring(newText.length() - (CHAR_DISPLAY_MAX-REPLACE_NUMBER)));
      return;
    }
    super.insertString(offs, str, a);
  }
};
tf.setDocument(doc);

“发抖”不,那绝对不是你想要做的事情。该文档是一个“模型”,因此不应该(也不能)了解视图状态或更改它... - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接