QPlainTextEdit - pushing into undo stack manually - c++

I'm building a code editor with QPlainTextEdit. As default, when I type a bunch of words in one line and then press undo, the whole line gets deleted. I'd like to push to undo stack manually on every character, so that when I click undo, previous character is removed. Then I could implement capturing only non-letters, etc... so it would undo one logical token at a time. How do I do it?
I hope you guys can help me. Thanks in advance.

I've got this working by overriding the keyPressEvent():
void CodeEditor::keyPressEvent(QKeyEvent *event)
{
QTextCursor cursor = textCursor();
cursor.beginEditBlock();
QPlainTextEdit::keyPressEvent(event);
cursor.endEditBlock();
setTextCursor(cursor);
}

Related

wxWidgets: make tooltips less annoying,

I have added tooltips to my checkbox elements, but they are too annoying. They appear immediately after hovering the mouse cursor over the element and do not disappear after the cursor has left the checkbox.
I could start a timer, but I don't know how I can check if the cursor is within the desired element or has left it.
And the second question is, is there any event like wxEVT_LEAVE_WINDOW, but for the checkbox to remove the tooltip when the cursor goes out of bounds.
Thanks, #New Pagodi
I am still dont get normal behaivor of tips, but your trich works. I can get tip window from wxCheckBox element just calling GetChildren().
wxRichToolTip* tip = new wxRichToolTip(wxT("INFO"), msg);
tip->SetTimeout(0, 500);
tip->ShowFor(it->second.first);
wxWindowList tipWindow = it->second.first->GetChildren();
auto a = tipWindow.GetLast()->GetData();
a->Bind(wxEVT_MOTION, &DeviceListDialog::onLeaveCheckbox, this);

Performantly appending (rich) text into QTextEdit or QTextBrowser in Qt

QTextEdit can be appended text to simply using append(). However, if the document is rich text, every time you append to the document, it is apparently reparsed. This seems like a bit of a trap in Qt.
If you're using the edit box as a log window and appending text in fast successions as a result of external signals, the appending can easily hang your app with no intermediate appends shown until each of the appends have completed.
How do I append rich text to a QTextEdit without it slowing down the entire UI?
If you want each append to actually show quickly & separately (instead of waiting until they've all been appended before they are shown), you need to access the internal QTextDocument:
void fastAppend(QString message,QTextEdit *editWidget)
{
const bool atBottom = editWidget->verticalScrollBar()->value() == editWidget->verticalScrollBar()->maximum();
QTextDocument* doc = editWidget->document();
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.beginEditBlock();
cursor.insertBlock();
cursor.insertHtml(message);
cursor.endEditBlock();
//scroll scrollarea to bottom if it was at bottom when we started
//(we don't want to force scrolling to bottom if user is looking at a
//higher position)
if (atBottom) {
scrollLogToBottom(editWidget);
}
}
void scrollLogToBottom(QTextEdit *editWidget)
{
QScrollBar* bar = editWidget->verticalScrollBar();
bar->setValue(bar->maximum());
}
The scrolling to bottom is optional, but in logging use it's a reasonable default for UI behaviour.
Also, if your app is doing lots of other processing at the same time, appending this at the end of fastAppend, will prioritize actually getting the message displayed asap:
//show the message in output right away by triggering event loop
QCoreApplication::processEvents();
This actually seems a kind of trap in Qt. I would know why there isn't a fastAppend method directly in QTextEdit? Or are there caveats to this solution?
(My company actually paid KDAB for this advice, but this seems so silly that I thought this should be more common knowledge.)

Qt sending keyPressEvent

I want to append chars to QLineEdit by sending KeyEvent.
I'm using code like this:
ui.myEdit->setFocus();
for(size_t i = 0; i < 10; ++i) {
QKeyEvent keyPressed(QKeyEvent::KeyPress, 'a', Qt::NoModifier);
QWidget::keyPressEvent(&keyPressed); // or
//QApplication::sendEvent(QApplication::focusWidget(), &keyPressed);
}
Why there is no change in myEdit?
You can change the change the text of QLineEdit simply by :
ui->myEdit->setText(ui->myEdit->text().append("a"));
But if you really want to change it by sending QKeyEvent you can try this :
QKeyEvent * eve1 = new QKeyEvent (QEvent::KeyPress,Qt::Key_A,Qt::NoModifier,"a");
QKeyEvent * eve2 = new QKeyEvent (QEvent::KeyRelease,Qt::Key_A,Qt::NoModifier,"a");
qApp->postEvent((QObject*)ui->myEdit,(QEvent *)eve1);
qApp->postEvent((QObject*)ui->myEdit,(QEvent *)eve2);
Your approach is not wise.
Setting the focus yourself may annoy more than one user which loose focus from one UI element for the other.
By calling keyPressEvent directly you are skipping many layers of processing from the framework. Only misbehavior await down this path.
To reply to
I want to append chars to QLineEdit
You can obtain the line edit text, modify at your will and set it back.
QString currentText = ui.myEdit->text();
QString toappend = "aaaaaaaaaa";
QString nextText = currentText + toappend;
ui.myEdit->setText(nextText);
or one line
ui.myEdit->setText(ui.myEdit->text()+mystring);
Synthesizing a key press event to append characters to a line edit is asking for endless trouble. You'd need to retain the state of the control to ensure that you are in fact appending characters. If the cursor is not at the end, you'll be inserting or prepending characters. If any modifiers are active, you may cause the widget to act as if, say, a clipboard shortcut was activated. Say if you "append" an X while Ctrl/⌘ is held down, you'll cause any selected text to disappear from the line edit.
In other words: if you want to append something to a textedit, simply append it, don't synthesize keystrokes.
lineEdit->setText(lineEdit->text() + "appended");
That's it. To do it properly via appending keystrokes requires about a page of code, and even then it can't but rely on Qt's implementation details.

QLineEdit not able to Undo after calling SetText() in Qt

In my application I am having many QLineEdit widgets. The user can edit them.
I have observed that if I add text to a QLineEdit through GUI & then if that QLineEdit has the cursor then if I press ctrl+z then it undoes the text so that there is no text in it.
Now if I set the text by code by SetText("some text"), then undo does not work by ctrl+z method. Even if I undo by code still it does not clear the text. What is the problem? Am I missing something?
Thank You.
undo probably thinks that the value you set by SetText should be treated as default start value, that doesn't need undoing. Normal behavior as it seems for me.
Here is SetText() definition:
This property holds the line edit's text.
Setting this property clears the selection, clears the undo/redo history, moves the cursor to the end of the line and resets the modified property to false. The text is not validated when inserted with setText().
The text is truncated to maxLength() length.
By default, this property contains an empty string.
Calling setText() resets the modified flag to false.
Perhaps if you set setModified ( bool ) to true, will fix this for you
Edit:
Found workaround : insert(QString text) works with undo() just fine

CEdit control MFC, placing cursor to end of string after SetWindowText

I am using VC9, I've a CEdit control whose contents are reset to default test (say - "fill-in") at the click of a button and then I call SetFocus for the CEdit control. The problem is that the cursor blinks at the start of the default text, and i want it to blink an the end of the default string.
How can this be done?
You can use CEdit::SetSel to accomplish that.
Example:
CEdit* e = (CEdit*)GetDlgItem(IDC_EDIT1);
e->SetWindowText("hello world");
e->SetFocus();
e->SetSel(0,-1); // select all text and move cursor at the end
e->SetSel(-1); // remove selection
You can use CEdit::SetSel to accomplish that:
CEdit* e = (CEdit*)GetDlgItem(IDC_EDIT1);
e->SetWindowText("hello world");
// e->SetSel(0,-1); // you don't need this line
e->SetFocus();
e->SetSel(-1);
It will place the cursor in the end of the string.
I had a strange finding but still relevant to it.
This solution did not work for me initially. Even after calling SetSel(-1) my cursor was moving to the top of the edit box.
Then I did some code reshuffle and it started working.
The learning was that if I update any other control after updating the edit control, the cursor will move to the top of the edit box. But if edit box is the last control updated, the cursor remains in the end of the edit box.
Like I had a code something like
Add text to edit & call SetSel(-1)
update static control
And the cursor would not stay in the end. But when I changed it to
update static control
Add text to edit & call SetSel(-1)
My cursor was displayed in the end of the edit box.
I had it on my mind since the day I had this finding to update the knowledge base here. Hope it helps some random soul whose cursor jumps to top of edit box even after calling the API.