I have a QTextEdit control. It has a maximum limit (maximum number of characters it can hold). To implement this I have connected a slot to the textChanged() signal which removes the extra character when the total number of characters exceeds the allowed maximum.
With this I have some problems dealing with the cursor position. Can anyone tell me how to retain the cursor position in QTextEdit?
On your slot:
If num of chars exceeds maximum:
Ask the QTextEdit for the Cursor:
QTextCursor QTextEdit::textCursor() const
Set the return value as your textEdit cursor (cause it returns a copy). From doc:
Returns a copy of the QTextCursor that represents the currently visible cursor. Note that > changes on the returned cursor do not affect QTextEdit's cursor; use setTextCursor() to > update the visible cursor.
void QTextEdit::setTextCursor(const QTextCursor & cursor)
Ask the cursor to delete last char
void QTextCursor::deletePreviousChar()
(Edit)as code:
QTextCursor cursor = ui->textEdit->textCursor();
ui->textEdit->setTextCursor( cursor );
cursor.deletePreviousChar();
If number exceeds the limit or wrong character is typed I'm using:
ui->textEdit->textCursor().deletePreviousChar();
Related
I'm making a sort of an Excel-type application in which I can load a tab-delimited text file and I am able to edit cells... etc
It's useable but I have an issue related to me allowing the user to "freeze" a number of columns/rows. ("Frozen" rows/columns can only be one of the first ones and are then "frozen", i.e. always displayed even when scrolling)
The whole frozen Col/Row is working but I would like the user to be able to scroll slightly past the last Col/Row in order to be able to only ever display full cells.
Right now when reaching the end of the scrollbar I end up with a partial leftmost column and topmost row because it's only displaying up to the last full col/row and not going a wee bit further for all content to be displayed fully.
I've tried doing adding some space to the maximum scrollbar value once everything is loaded in the table but it seems to have no effect :
table->horizontalScrollBar()->setMaximum(table->horizontalScrollBar()->maximum() + t->horizontalScrollBar()->singleStep()*2);
I tried multiple values too.
(Edit) There may be some Qt code that "snaps" the QTableView viewport back to the edge of the last cell automatically...
(Edit2) I connected verticalScrollbar's rangeChanged() signal to a custom slot with the following code:
void MyTableView::onRangeChanged(int min, int max) {
QScrollBar *sender = verticalScrollBar();
int newVMax = max + 20;
sender->blockSignals(true);
sender->setRange(min, newVMax);
sender->blockSignals(false);
}
Sadly there is definitely a snapback mechanic when scrolling to the end of verticalScrollbar...
Gif of snap back issue
(Edit3) The snap back may be related to:
void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode)
{
Q_Q(QHeaderView);
if (scrollMode == QAbstractItemView::ScrollPerItem) {
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();
else
q->setOffsetToSectionPosition(scrollBar->value());
} else {
q->setOffset(scrollBar->value());
}
}
mainly:
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();
I have an editable QComboBox that allows a user to type in a name for a new object and add it to the list. They can also edit names for existing items in the list. The problem is...say I have an item in the list called "AF" and I want to rename it to "ABCDEF". My first problem was if I placed the cursor in between 'A' and 'F' and started typing the cursor would jump to the end after typing 1 letter. So I would get "ABFCDE" unless I manually moved the cursor after each letter typed.
I fixed this by using
// slot connected to textEditChanged(QString) signal from QComboBox
void textChanged(const QString &text)
{
int pos = QComboBox->lineEdit()->custorPosition();
stuff...
QComboBox->setItemText(idx, text);
QComboBox->lineEdit()->setCursorPosition(pos);
}
and that works but unfortunately this caused a new problem.
setCursorPosition will subsequently select (highlight) all text beyond the new cursor location. So in the "AF" to "ABCDEF" example... I place the cursor between 'A' and 'F', type B and the cursor stays after "AB" and before 'F' but 'F' is highlighted. The next key press will replace the 'F' entirely. It will highlight more than 1 character, it highlights every character to the right of the cursor after it is moved.
I tried this to no avail.
QComboBox->lineEdit()->deselect();
I also tried this just as a test and it incorrectly exhibited the same behavior.
QComboBox->lineEdit()->moveCursorBackward(false,2);
The false parameter is supposed to not select the text the cursor moves past but it does anyway.
Anyone have any ideas on what's causing this?
I also encountered this problem. Here's what solved it for me for anyone interested:
First connect the signal but make sure it is queued!
connect(_comboBox, SIGNAL(editTextChanged(const QString&)), this, SLOT(slotTextChanged(const QString&)), Qt::QueuedConnection);
and for the slot:
void ViewListWidget::slotViewNameChanged(const QString& /*name*/) {
int index = _viewComboBox->currentIndex();
int cursorPosition = _viewComboBox->lineEdit()->cursorPosition();
// Since we are using a queued connection, get the current QLineEdit text
// instead of relying on the signal argument, which might be out of sync
QString name = _viewComboBox->lineEdit()->text();
_viewComboBox->blockSignals(true);
_viewComboBox->setItemText(index, name);
_viewComboBox->blockSignals(false);
_viewComboBox->lineEdit()->setCursorPosition(cursorPosition);
}
You should also probably disable auto-complete:
_comboBox->setCompleter(0);
How can I create a QTableView multiline cell?
I'm filling the table using the code bellow.
But Whem GetDescription() returns a long string, the content is terminated with ...
There is some way to automatic break the line?
QStandardItemModel * model = new QStandardItemModel(logos.size(), 2, this);
model->setHorizontalHeaderItem(0, new QStandardItem(QString("")));
model->setHorizontalHeaderItem(1, new QStandardItem(QString("Nome")));
model->setHorizontalHeaderItem(2, new QStandardItem(QString("Descrição")));
int row = 0;
foreach(Item * item, items)
{
QStandardItem* check = new QStandardItem(true);
check->setCheckable(true);
model->setItem(row, 0, check);
QStandardItem *nameItem = new QStandardItem(QString(item->GetName()));
nameItem->setEditable(false);
model->setItem(row, 1, nameItem);
QStandardItem *descriptionItem = new QStandardItem(item->GetDescription());
descriptionItem->setEditable(false);
descriptionItem->setToolTip(logo->GetDescription());
model->setItem(row, 2, descriptionItem);
row++;
}
ui->tableView->setModel(model);
ui->tableView->resizeColumnToContents(0);
ui->tableView->resizeColumnToContents(1);
ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
ui->tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
I think word wrapping is what you're looking for. Make sure that you've enabled wordwrap for the QTableView, then manually resize the rows to fit their contents. That will replace the ellipse with the text.
As you mentioned in your answer, you can set the QHeaderView to resize to contents automatically, but if you do a lot of adding and removing this will slow things down. I prefer to manually resize with a large addition/subtraction, particularly since the user might find it annoying to be unable to resize it themselves.
Here's some example code that enables word wrap, sets the ellipse to appear in the middle (my preference), and then manually resizes the row height to fit the contents at word boundaries:
ui->tableView->setWordWrap(true);
ui->tableView->setTextElideMode(Qt::ElideMiddle);
ui->tableView->resizeRowsToContents();
I only add to my code:
ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
As far as I know, the only way to implement multiline text drawing in cells is implementing own delegate.
You can derive from QItemDelegate.
You'll have to
implement own sizeHint function, based on QFontMetrics
and override drawDisplay function to actually display text. You can use QPainter::drawText to display multiline text. So, you don't have to care about drawing focus and selection rectangles and own painting function will be simple.
tableView->resizeRowsToContents();
I have a Qt "Text Edit" widget in my Gui and this widget is used to log something.
I add every line(s) this way:
QString str;
str = ...
widget.textEdit_console->append(str);
by this way the Text Edit height will increase more and more after each new line.
I want it act like a terminal in this case, I mean after some number (that I set) of lines entered, for each new line the first line of Text Edit being deleted to prevent it being too big!
should I use a counter with every new line entered and delete the first ones after counter reached it's top or there is better way that do this automatically after
widget.textEdit_console->append(str);
called ?
thank cmannett85 for your advise but for some reason I prefer 'Text Edit',
I solved my problem this way:
void mainWindow::appendLog(const QString &str)
{
LogLines++;
if (LogLines > maxLogLines)
{
QTextCursor tc = widget.textEdit_console->textCursor();
tc.movePosition(QTextCursor::Start);
tc.select(QTextCursor::LineUnderCursor);
tc.removeSelectedText(); // this remove whole first line but not that '\n'
tc.deleteChar(); // this way the first line will completely being removed
LogLines--;
}
widget.textEdit_console->append(str);
}
I still don't know is there any better more optimized way while using 'Text Edit'
One simple way is to turn the vertical scroll-bar off:
textEdit_console->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
This code move cursor to the first line and then select it until end of line, next it will delete the line:
widget.textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);
widget.textEdit->moveCursor(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
widget.textEdit->textCursor().deleteChar();
widget.textEdit->textCursor().deleteChar();
Given a QTextBlock retrieved from QPlainTextEdit, I want to change background of the text in that block. I know how to do this with the help of textCursor() but in this case textCursor could be somewhere else. I am traversing through the file text line by line and would like to change background of the current line irrespective of the cursor position. Please let me know if it can be done.
What's the problem with moving the cursor to the line you want to mark?
You can save an old cursor position if you need.
int oldPos = edit->textCursor().position();
QTextCursor cursor = edit->textCursor();
int oldPos = cursor.position();
int linePos = // get the line position
cursor.setPosition(linePos);
cursor.select(QTextCursor::LineUnderCursor);
cursor.setCharFormat(format);
cursor.setPosition(oldPos);
edit->setTextCursor(cursor);