Как выделить часть JLabel? - PullRequest
       13

Как выделить часть JLabel?

7 голосов
/ 20 августа 2010

Прежде чем кто-либо предложит HTML, я объясню позже, почему это не вариант здесь.У меня есть таблица, которая содержит столбец с текстовыми ячейками в нем.Мне нужно иметь возможность выделить часть текста в каждой ячейке.Так, например, если в ячейке содержится «cat foo dog» ... я мог бы выделить foo.

Мой текущий метод заключается в использовании пользовательского TableCellRenderer, который помещает html в компонент JLabel, который отображается ивремя было хорошоЗатем я заметил, что, когда текст в ячейке становится слишком длинным, чтобы поместиться в ширину столбца, он просто обрезает текст без нормального «...», что обычно происходит в этом случае.Таким образом, пользователи не знали, что было больше текста, который они не видели.Другая проблема заключалась в том, что если исходный текст сам содержал HTML, что в моем случае иногда происходит, ячейка отображалась бы неправильно.Я знаю, что могу просто избежать html, но у меня все еще будет существующая проблема.

Если я использую компонент, отличный от jlabel, тогда ячейки моего стола выглядят странно.У кого-нибудь есть предложения?Спасибо

Ответы [ 3 ]

7 голосов
/ 21 августа 2010

Ну, вот решение.

Короче говоря, вы можете создать подкласс JLabel, чтобы нарисовать выделение вручную. Переопределите метод paintComponent, чтобы сделать фактическое рисование, и используйте FontMetrics, чтобы вычислить, где должна быть нарисована выделенная область.

Вот этот ответ в мучительных деталях:

По сути, вы можете создать подкласс JLabel, который может выделять вещи. Я бы сделал это так; Вы можете сделать это несколько иначе:

Добавить метод, который сообщает метке, какую часть выделить. Это может быть что-то вроде этого, если вам нужен только один выделенный регион:

public void highlightRegion(int start, int end) {
     // Set some field to tell you where the highlight starts and ends...
}

Если вам нужно несколько регионов, просто используйте ArrayList вместо простого поля. Вероятно, был бы также полезен метод для подсветки.

Теперь вам нужно переопределить paintComponent метод JLabel. Здесь вам нужно сделать несколько отдельных шагов, которые вы можете организовать различными способами или чем-то еще. Для простоты я все изложу в методе рисования.

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

Сначала вам нужно выяснить физические размеры выделения, что вы можете сделать, используя класс FontMetrics. Создайте класс FontMetrics для Font, который вы используете.

  FontMetrics metrics = new FontMetrics(getFont());

Теперь вы можете получить всю информацию, необходимую для создания прямоугольника, который будет основным моментом. Вам понадобится начальная позиция, высота и ширина. Чтобы получить это, вам понадобятся две подстроки текста JLabel следующим образом:

  String start = getText().substring(0, startOfHighlight);
  String text = getText().substring(startOfHighlight, endOfHighlight);
  //You may also need to account for some offsets here:
  int startX = metrics.stringWidth(start);
  int startY = 0; //You probably have some vertical offset to add here.
  int length = metrics.stringWidth(text);
  int height = metrics.getHeight();

Теперь вы можете нарисовать выделенную область перед нанесением остальной метки:

  g.fillRect(startX, startY, length, height);
  super.paintComponent(g);
}

Конечно, если вы хотите, чтобы выделение занимало несколько строк, это потребует дополнительной работы.

Если вам интересно, я уже писал что-то подобное раньше. По какой-то причине я решил написать свой собственный компонент типа текстовой области из JPanel, и именно так я и работал с подсветкой. Изобретать колесо может быть глупо в реальном проекте, но оно учит вас случайным вещам, которые могут оказаться полезными ...

2 голосов
/ 27 октября 2011

Невозможно удержаться, чтобы бросить механизм рендеринга SwingX в кольцо: его способ решить это требование - это сделать Highlighter.Что на самом деле уже сделано (хотя пока официально не поддерживается), но скрыто в проекте SwingLabs-Demos с именем X / MatchingTextHighlighter (вам понадобится оба) и недавно исправлено для работы с иконками, RToL-ComponentOrientation, выравнивание, эллипсы ..

2 голосов
/ 27 октября 2010

Это отличный ответ и, вероятно, лучшее решение. Но альтернативой, которая может показаться кому-то более простой, является использование JTextfield вместо JLabel для рендеринга, тогда вы можете использовать возможности выделения JTextfields, т. Е.

void highlightWhitespaceText(JTextField text)
    {
        text.setHighlighter(AbstractTableCellRenderer.defaultHighlighter);
        try
        {
            Matcher m = AbstractTableCellRenderer.whitespaceStartPattern.matcher(text.getText());
            if (m.matches())
            {
                text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
            }
            m = AbstractTableCellRenderer.whitespaceEndPattern.matcher(text.getText());
            if (m.matches())
            {
                text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
            }
        }
        catch (BadLocationException ble)
        {
            //
        }
    }

Вы можете изменить свойства JTextfield, чтобы он выглядел как jLabel в других отношениях.

...