ArlexBee-871RBO
20th May 2010, 07:27
Greetings. Instead of using QStyle, I have sub-classed QLineEdit and reimplemented the paintEvent function (don't ask why) for custom look. It looks almost finished, but I have a problem with the cursor. The position of the cursor is not being rendered correctly, and I've tried different things without success. If I directly draw the cursor position then it gets better, but it still starts to show problems when the line is filled with more text. It gets much worse with QTextLayout, and I don't find the documentation very helpful.
Here is what I've got so far. Much of it I got from Qt after studying the source code. I've intentionally given the LineEdit a fixed size to make sure the alignment is as it should be.
#include <QtGui>
#include <QtCore>
class Edit : public QLineEdit{
public:
Edit(const QString &t, QWidget *pParent = 0) : QLineEdit(t, pParent){
font = QFont("Sans");
font.setPixelSize(12);
setFixedSize(640, 220);
setTextMargins(4, 0, 4, 0);
}
protected:
void paintEvent(QPaintEvent *pEvent){
QPainter painter(this);
QRect r = rect();
//frame
int x2 = r.width() - 1, y2 = r.height() - 1;
painter.fillRect(r, QBrush(QColor(79, 79, 104, 255)));
painter.setPen(QPen(QColor(64, 64, 64, 255), 1));
painter.drawLine(0, 0, x2, 0);
painter.drawLine(0, 0, 0, y2);
painter.setPen(QPen(QColor(92, 92, 92, 255), 1));
painter.drawLine(x2, y2, 1, y2);
painter.drawLine(x2, y2, x2, 1);
painter.setPen(QPen(QColor(19, 19, 19, 255), 1));
painter.drawRect(QRect(1, 1, r.width() - 3, r.height() - 3));
//set clipping
int lm, tm, rm, bm;
getTextMargins(&lm, &tm, &rm, &bm);
r.setX(r.x() + lm);
r.setY(r.y() + tm);
r.setRight(r.right() - rm);
r.setBottom(r.bottom() - bm);
painter.setClipRect(r);
painter.setPen(QPen(QColor(196, 196, 196, 255), 1));
QFontMetrics fm(font);
QTextLayout tl(text(), font, this);
tl.beginLayout();
QTextLine line = tl.createLine();
if( !line.isValid() ){ return; }
tl.endLayout();
QRect lineRect(r.x(), r.y() + (r.height() - qRound(line.height()) + 1) / 2,
r.width() - 1, qRound(line.height()));
//painter.drawRect(lineRect);
int ccc = cursorPosition();
int cix = qRound(line.cursorToX(&ccc));
int minLB = qMax(0, -fm.minLeftBearing());
int minRB = qMax(0, -fm.minRightBearing());
int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB;
int hscroll;
if( (minLB + widthUsed) <= lineRect.width() ){
hscroll = 0;
hscroll -= minLB;
}else if( cix - hscroll >= lineRect.width() ){
hscroll = cix - lineRect.width() + 1;
}else if( cix - hscroll < 0 && hscroll < widthUsed ){
hscroll = cix;
}else if( widthUsed - hscroll < lineRect.width() ){
hscroll = widthUsed - lineRect.width() + 1;
}
QPoint topLeft = lineRect.topLeft() -
QPoint(hscroll, line.ascent() - fm.ascent());
QVector<QTextLayout::FormatRange> selections;
QTextLayout::FormatRange o;
if( hasSelectedText() ){
o.start = selectionStart();
o.length = selectedText().length();
o.format.setBackground(QColor(88, 101, 134, 255));
o.format.setForeground(QColor(196, 196, 196, 255));
selections.append(o);
}
tl.draw(&painter, topLeft, selections);
painter.setPen(QPen(QColor(200, 0, 0, 255), 2));
//painter.drawLine(cix, lineRect.y(), cix, lineRect.y() + lineRect.height());
tl.drawCursor(&painter, topLeft, cix, 2);
}
private:
QFont font;
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QWidget *w = new QWidget;
w->setPalette(QPalette(QColor(77, 77, 77, 255)));
QHBoxLayout *l = new QHBoxLayout(w);
Edit *e1 = new Edit(QString("test1"));
QLineEdit *e2 = new QLineEdit(QString("test2"));
e2->setFixedSize(640, 220);
l->addWidget(e1);
l->addWidget(e2);
w->show();
return a.exec();
}
Any idea why QTextLayout doesn't render the cursor properly?
Here is what I've got so far. Much of it I got from Qt after studying the source code. I've intentionally given the LineEdit a fixed size to make sure the alignment is as it should be.
#include <QtGui>
#include <QtCore>
class Edit : public QLineEdit{
public:
Edit(const QString &t, QWidget *pParent = 0) : QLineEdit(t, pParent){
font = QFont("Sans");
font.setPixelSize(12);
setFixedSize(640, 220);
setTextMargins(4, 0, 4, 0);
}
protected:
void paintEvent(QPaintEvent *pEvent){
QPainter painter(this);
QRect r = rect();
//frame
int x2 = r.width() - 1, y2 = r.height() - 1;
painter.fillRect(r, QBrush(QColor(79, 79, 104, 255)));
painter.setPen(QPen(QColor(64, 64, 64, 255), 1));
painter.drawLine(0, 0, x2, 0);
painter.drawLine(0, 0, 0, y2);
painter.setPen(QPen(QColor(92, 92, 92, 255), 1));
painter.drawLine(x2, y2, 1, y2);
painter.drawLine(x2, y2, x2, 1);
painter.setPen(QPen(QColor(19, 19, 19, 255), 1));
painter.drawRect(QRect(1, 1, r.width() - 3, r.height() - 3));
//set clipping
int lm, tm, rm, bm;
getTextMargins(&lm, &tm, &rm, &bm);
r.setX(r.x() + lm);
r.setY(r.y() + tm);
r.setRight(r.right() - rm);
r.setBottom(r.bottom() - bm);
painter.setClipRect(r);
painter.setPen(QPen(QColor(196, 196, 196, 255), 1));
QFontMetrics fm(font);
QTextLayout tl(text(), font, this);
tl.beginLayout();
QTextLine line = tl.createLine();
if( !line.isValid() ){ return; }
tl.endLayout();
QRect lineRect(r.x(), r.y() + (r.height() - qRound(line.height()) + 1) / 2,
r.width() - 1, qRound(line.height()));
//painter.drawRect(lineRect);
int ccc = cursorPosition();
int cix = qRound(line.cursorToX(&ccc));
int minLB = qMax(0, -fm.minLeftBearing());
int minRB = qMax(0, -fm.minRightBearing());
int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB;
int hscroll;
if( (minLB + widthUsed) <= lineRect.width() ){
hscroll = 0;
hscroll -= minLB;
}else if( cix - hscroll >= lineRect.width() ){
hscroll = cix - lineRect.width() + 1;
}else if( cix - hscroll < 0 && hscroll < widthUsed ){
hscroll = cix;
}else if( widthUsed - hscroll < lineRect.width() ){
hscroll = widthUsed - lineRect.width() + 1;
}
QPoint topLeft = lineRect.topLeft() -
QPoint(hscroll, line.ascent() - fm.ascent());
QVector<QTextLayout::FormatRange> selections;
QTextLayout::FormatRange o;
if( hasSelectedText() ){
o.start = selectionStart();
o.length = selectedText().length();
o.format.setBackground(QColor(88, 101, 134, 255));
o.format.setForeground(QColor(196, 196, 196, 255));
selections.append(o);
}
tl.draw(&painter, topLeft, selections);
painter.setPen(QPen(QColor(200, 0, 0, 255), 2));
//painter.drawLine(cix, lineRect.y(), cix, lineRect.y() + lineRect.height());
tl.drawCursor(&painter, topLeft, cix, 2);
}
private:
QFont font;
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QWidget *w = new QWidget;
w->setPalette(QPalette(QColor(77, 77, 77, 255)));
QHBoxLayout *l = new QHBoxLayout(w);
Edit *e1 = new Edit(QString("test1"));
QLineEdit *e2 = new QLineEdit(QString("test2"));
e2->setFixedSize(640, 220);
l->addWidget(e1);
l->addWidget(e2);
w->show();
return a.exec();
}
Any idea why QTextLayout doesn't render the cursor properly?