Russian Qt Forum
Ноябрь 22, 2024, 21:58 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QLineEdit - фрагмент текста жирным шрифтом.  (Прочитано 22376 раз)
niXman
Гость
« : Февраль 06, 2009, 10:59 »

Доброго времени суток!
Есть необходимость часть текста/слова выделить другим шрифтом/цветом.
« Последнее редактирование: Февраль 06, 2009, 11:13 от niXman » Записан
spirit
Гость
« Ответ #1 : Февраль 06, 2009, 11:19 »

никак. QTextLayout и прочая хрень запривачена в QLineEditPrivate. я делал такой эдитор, но весь код пришлось перетянуть из оригинального QLineEdit.
Записан
niXman
Гость
« Ответ #2 : Февраль 06, 2009, 11:20 »

А с QLabel такое можно проделать?
Записан
spirit
Гость
« Ответ #3 : Февраль 06, 2009, 11:27 »

по идее да. не пробовал если честно Улыбающийся
Записан
BRE
Гость
« Ответ #4 : Февраль 06, 2009, 11:38 »

А с QLabel такое можно проделать?
QLabel поддерживает html-tags:

Код
C++ (Qt)
label->setText( tr( "Text <b>Bold text</b> <font color=red>Red text</font>" ) );
Записан
niXman
Гость
« Ответ #5 : Февраль 06, 2009, 11:51 »

СПАСИБО!!!
Записан
SABROG
Гость
« Ответ #6 : Февраль 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 контент?
Записан
niXman
Гость
« Ответ #7 : Февраль 07, 2009, 14:24 »

Рано обрадовался... В замешательстве
Все же придется делать аналоги QLineEdit и QListWidget с необходимым функционалом.
Записан
ритт
Гость
« Ответ #8 : Февраль 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
« Последнее редактирование: Февраль 08, 2009, 05:10 от Константин » Записан
niXman
Гость
« Ответ #9 : Февраль 10, 2009, 02:04 »

Мысль понятна.
Буду пробовать.
Записан
ритт
Гость
« Ответ #10 : Февраль 13, 2009, 08:09 »

ха! нашёл способ использовать произвольное оформление текста в лайнэдите вообще без наследования Улыбающийся
код будет позже.
Записан
ритт
Гость
« Ответ #11 : Февраль 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);
 
« Последнее редактирование: Февраль 13, 2009, 12:55 от Константин » Записан
igor_bogomolov
Гость
« Ответ #12 : Февраль 13, 2009, 10:36 »

А если в lineEdit нужно свойство setReadOnly(true). Как сделать чтобы форматирование сохранилось?
Записан
ритт
Гость
« Ответ #13 : Февраль 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 и сбрасывать/задавать форматирование заново.
« Последнее редактирование: Февраль 13, 2009, 12:28 от Константин » Записан
Андрей80
Гость
« Ответ #14 : Февраль 23, 2009, 15:13 »

C:\Qt\4.3.3\examples\richtext\syntaxhighlighter\release
Ваш случай по моему
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.334 секунд. Запросов: 21.