Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: niXman от Февраль 06, 2009, 10:59



Название: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: niXman от Февраль 06, 2009, 10:59
Доброго времени суток!
Есть необходимость часть текста/слова выделить другим шрифтом/цветом.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: spirit от Февраль 06, 2009, 11:19
никак. QTextLayout и прочая хрень запривачена в QLineEditPrivate. я делал такой эдитор, но весь код пришлось перетянуть из оригинального QLineEdit.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: niXman от Февраль 06, 2009, 11:20
А с QLabel такое можно проделать?


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: spirit от Февраль 06, 2009, 11:27
по идее да. не пробовал если честно :)


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: BRE от Февраль 06, 2009, 11:38
А с QLabel такое можно проделать?
QLabel поддерживает html-tags:

Код
C++ (Qt)
label->setText( tr( "Text <b>Bold text</b> <font color=red>Red text</font>" ) );


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: niXman от Февраль 06, 2009, 11:51
СПАСИБО!!!


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: SABROG от Февраль 07, 2009, 12:38
никак. QTextLayout и прочая хрень запривачена в QLineEditPrivate. я делал такой эдитор, но весь код пришлось перетянуть из оригинального QLineEdit.

Все это правильно. Но если уже приперло, то можно и похакать, все тайное станет явным:

Код
C++ (Qt)
#include <QtGui/QTextLayout>
#include <QtGui/private/qlineedit_p.h>
#include <QtGui/QLineEdit>
...
class myEdit : public QLineEdit
{
       Q_OBJECT
public:
       myEdit(QWidget *parent) : QLineEdit(parent)
       {
       }
       ~myEdit(){}
       using QObject::d_ptr;
};
...
       myEdit *edit = new myEdit(this);
       edit->setText("test");
       edit->show();
       QLineEditPrivate *pedit = (QLineEditPrivate *)edit->d_ptr;
       QTextLayout &lay = pedit->textLayout;
       qDebug() << lay.text();
 

Вкратце расскажу, что происходит. Подключаем приватный хедер, наследумся от QLineEdit, чтобы получить доступ к приватному члену данных d_ptr и вытащить его наружу. Судя по исходникам QLineEdit в нем содержится указатель на QLineEditPrivate. Затем для теста используем обычный метод QLineEdit::setText и получаем подтверждение того, что всё работает в консоли вызывая метод QTextLayout::text(). Вопрос в том как QTextLayout нам поможет отрисовывать rich text контент?


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: niXman от Февраль 07, 2009, 14:24
Рано обрадовался... :-\
Все же придется делать аналоги QLineEdit и QListWidget с необходимым функционалом.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: ритт от Февраль 08, 2009, 05:04
необходимо хачить чтобы сработало `Q_D(QLineEdit)` => чтобы обновилось значение d->vscroll/d->hscroll => чтобы правильно срабатывали QLineEditPrivate::cursorRect(...) и т.п. /* если не забуду, отпишусь в ТТ по поводу d->vscroll/d->hscroll, т.к. из-за этой хрени фактически становится невозможным нормально наследоваться от QLineEdit */

Код
C++ (Qt)
// hardcoded in qlineedit.cpp
#define verticalMargin 1
#define horizontalMargin 2
 
/*!\reimp
*/

void MyLineEdit::paintEvent(QPaintEvent *)
{
   Q_D(QLineEdit);
   QPainter p(this);
 
   QRect r = rect();
   QPalette pal = palette();
 
   QStyleOptionFrameV2 panel;
   initStyleOption(&panel);
   style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
   r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
#if QT_VERSION >= 0x040500
   int left, top, right, bottom;
   getTextMargins(&left, &top, &right, &bottom);
   r.adjust(left, top, -right, -bottom);
#endif
   p.setClipRect(r);
 
   QFontMetrics fm = fontMetrics();
   Qt::Alignment va = QStyle::visualAlignment(layoutDirection(), QFlag(d->alignment));
   switch (va & Qt::AlignVertical_Mask) {
    case Qt::AlignBottom:
        d->vscroll = r.y() + r.height() - fm.height() - verticalMargin;
        break;
    case Qt::AlignTop:
        d->vscroll = r.y() + verticalMargin;
        break;
    default:
        //center
        d->vscroll = r.y() + (r.height() - fm.height() + 1) / 2;
        break;
   }
   QRect lineRect(r.x() + horizontalMargin, d->vscroll, r.width() - 2*horizontalMargin, fm.height());
   QTextLine line = d->textLayout.lineAt(0);
 
   int cursor = d->cursor;
   if (d->preeditCursor != -1)
       cursor += d->preeditCursor;
   // locate cursor position
   int cix = qRound(line.cursorToX(cursor));
 
   // horizontal scrolling. d->hscroll is the left indent from the beginning
   // of the text line to the left edge of lineRect. we update this value
   // depending on the delta from the last paint event; in effect this means
   // the below code handles all scrolling based on the textline (widthUsed,
   // minLB, minRB), the line edit rect (lineRect) and the cursor position
   // (cix).
   int minLB = qMax(0, -fm.minLeftBearing());
   int minRB = qMax(0, -fm.minRightBearing());
   int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB;
   if ((minLB + widthUsed) <=  lineRect.width()) {
       // text fits in lineRect; use hscroll for alignment
       switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
       case Qt::AlignRight:
           d->hscroll = widthUsed - lineRect.width() + 1;
           break;
       case Qt::AlignHCenter:
           d->hscroll = (widthUsed - lineRect.width()) / 2;
           break;
       default:
           // Left
           d->hscroll = 0;
           break;
       }
       d->hscroll -= minLB;
   } else if (cix - d->hscroll >= lineRect.width()) {
       // text doesn't fit, cursor is to the right of lineRect (scroll right)
       d->hscroll = cix - lineRect.width() + 1;
   } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) {
       // text doesn't fit, cursor is to the left of lineRect (scroll left)
       d->hscroll = cix;
   } else if (widthUsed - d->hscroll < lineRect.width()) {
       // text doesn't fit, text document is to the left of lineRect; align
       // right
       d->hscroll = widthUsed - lineRect.width() + 1;
   }
   // the y offset is there to keep the baseline constant in case we have script changes in the text.
   QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->ascent - fm.ascent());
 
   // draw text, selections and cursors
#ifndef QT_NO_STYLE_STYLESHEET
   if (QStyleSheetStyle* cssStyle = qobject_cast<QStyleSheetStyle*>(style())) {
       cssStyle->focusPalette(this, &panel, &pal);
   }
#endif
   p.setPen(pal.text().color());
 
   QVector<QTextLayout::FormatRange> selections;
#ifdef QT_KEYPAD_NAVIGATION
   if (!QApplication::keypadNavigationEnabled() || hasEditFocus())
#endif
   if (d->selstart < d->selend || (d->cursorVisible && d->maskData && !d->readOnly)) {
       QTextLayout::FormatRange o;
       if (d->selstart < d->selend) {
           o.start = d->selstart;
           o.length = d->selend - d->selstart;
           o.format.setBackground(pal.brush(QPalette::Highlight));
           o.format.setForeground(pal.brush(QPalette::HighlightedText));
       } else {
           // mask selection
           o.start = d->cursor;
           o.length = 1;
           o.format.setBackground(pal.brush(QPalette::Text));
           o.format.setForeground(pal.brush(QPalette::Window));
       }
       selections.append(o);
   }
 
/*+*/    if (/* условия для выделения блока текста жирным */) {
/*+*/        QTextLayout::FormatRange o;
/*+*/        o.start = 3; // начало блока (первый символ)
/*+*/        o.length = 4; // длина блока в символах
/*+*/        o.format.setFontWeight(QFont::Bold);
/*+*/        selections.append(o);
/*+*/    }
 
   // Asian users see an IM selection text as cursor on candidate
   // selection phase of input method, so the ordinary cursor should be
   // invisible if we have a preedit string.
   d->textLayout.draw(&p, topLeft, selections, r);
   if (d->cursorVisible && !d->readOnly && !d->hideCursor)
       d->textLayout.drawCursor(&p, topLeft, cursor, style()->pixelMetric(QStyle::PM_TextCursorWidth));
}
 
см. код, помеченный /*+*/
т.о. возможно использовать любое оформление, предусмотренное классом QTextCharFormat


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: niXman от Февраль 10, 2009, 02:04
Мысль понятна.
Буду пробовать.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: ритт от Февраль 13, 2009, 08:09
ха! нашёл способ использовать произвольное оформление текста в лайнэдите вообще без наследования :)
код будет позже.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: ритт от Февраль 13, 2009, 09:14
niXman, я даже не знаю чем ты со мной за это расплачиваться будешь  ;)

Код
C++ (Qt)
static void setLineEditTextFormat(QLineEdit* lineEdit, const QList<QTextLayout::FormatRange>& formats)
{
if(!lineEdit)
return;
 
QList<QInputMethodEvent::Attribute> attributes;
foreach(const QTextLayout::FormatRange& fr, formats)
{
// [b]обязательно[/b] нужно отнять от требуемой стартовой позиции текущую позицию курсора.
// можно обойтись без этого, если в начало и конец списка вставить специально подготовленные
// атрибуты, но меня и такой вариант устраивает
QInputMethodEvent::AttributeType type = QInputMethodEvent::TextFormat;
int start = fr.start - lineEdit->cursorPosition();
int length = fr.length;
QVariant value = fr.format;
attributes.append(QInputMethodEvent::Attribute(type, start, length, value));
}
QInputMethodEvent event(QString(), attributes);
QCoreApplication::sendEvent(lineEdit, &event);
}
 
static void clearLineEditTextFormat(QLineEdit* lineEdit)
{
setLineEditTextFormat(lineEdit, QList<QTextLayout::FormatRange>());
}
 
// наглядный пример:
QLineEdit* lineEdit = new QLineEdit;
lineEdit->setText(tr("Task Tracker - Entry"));
 
QList<QTextLayout::FormatRange> formats;
 
QTextCharFormat f;
 
f.setFontWeight(QFont::Bold);
QTextLayout::FormatRange fr_task;
fr_task.start = 0;
fr_task.length = 4;
fr_task.format = f;
 
f.setFontItalic(true);
f.setBackground(Qt::darkYellow);
f.setForeground(Qt::white);
QTextLayout::FormatRange fr_tracker;
fr_tracker.start = 5;
fr_tracker.length = 7;
fr_tracker.format = f;
 
f = QTextCharFormat();
f.setForeground(Qt::gray);
QTextLayout::FormatRange fr_entry;
fr_entry.start = 15;
fr_entry.length = 5;
fr_entry.format = f;
 
formats.append(fr_task);
formats.append(fr_tracker);
formats.append(fr_entry);
 
customizeLineEditText(lineEdit, formats);
 


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: igor_bogomolov от Февраль 13, 2009, 10:36
А если в lineEdit нужно свойство setReadOnly(true). Как сделать чтобы форматирование сохранилось?


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: ритт от Февраль 13, 2009, 12:21
с ридонли лайнэдит отключает доставку событий QInputMethodEvent. если даже вызвать inputMethodEvent напрямую, любое событие QInputMethodEvent будет проигнорировано.

единственный вариант - унаследоваться от лайнэдита и перегрузить inputMethodEvent следующим образом:
Код
C++ (Qt)
void MyLineEdit::inputMethodEvent(QInputMethodEvent *e)
{
   bool wasReadOnly = isReadOnly();
   if(wasReadOnly)
       setReadOnly(false);
 
   QLineEdit::inputMethodEvent(QInputMethodEvent *e);
 
   setReadOnly(wasReadOnly);
}
 

также следует добавить, что доставка отключается и для
echoMode() != QLineEdit::Normal && echoMode() != QLineEdit::PasswordEchoOnEdit
если изменить echoMode после такого "раскрашивания" текста, получится не то, чего пользователь ожидает :)

да, ещё не забываем, такое форматирование является перманентным и позиции FormatRange-а не изменяются при изменении текста - нужно отлавливать textchanged и сбрасывать/задавать форматирование заново.


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: Андрей80 от Февраль 23, 2009, 15:13
C:\Qt\4.3.3\examples\richtext\syntaxhighlighter\release
Ваш случай по моему


Название: Re: QLineEdit - фрагмент текста жирным шрифтом.
Отправлено: spirit от Февраль 23, 2009, 15:45
C:\Qt\4.3.3\examples\richtext\syntaxhighlighter\release
Ваш случай по моему

хайлайтер используется вместе с QTextEdit
Цитировать
The QSyntaxHighlighter class is a base class for implementing QTextEdit syntax highlighters. A syntax highligher automatically highlights parts of the text in a QTextEdit, or more generally in a QTextDocument. Syntax highlighters are often used when the user is entering text in a specific format (for example source code) and help the user to read the text and identify syntax errors.
а в топике идет речь о QLineEdit.