How to remove focus from QLineEdit - c++

I am developing a cpp/Qt tool.When I click on a QLineEdit field, its frame turns to a different color and the cursor starts blinking.When I type on Return in the field, I want its cursor to stop blinking and its frame color to default back to normal.I can intercept the Return Pressed, but when I then start the clearFocus() command, the keyboard input does not come anymore to the QLineEdit field (which is the behaviour I am expecting), but its frame doesn't go back to the default color and the cursor continues blinking. How to really remove focus from the field (i.e.: No cursor blinking anymore and frame back to default color) ?
=== EDIT ===
Here is the code:
void myQLineEditClass::keyPressEvent(QKeyEvent *e)
{
if(e->text().length()>0)
{
int asciiVal = e->text().at(0).toAscii();
if (asciiVal==3||asciiVal==13)
{
MGlobal::displayInfo(MQtUtil::toMString(QString().sprintf("Focus cleared"))); // -> this is properly displayed
clearFocus();
}
}
QLineEdit::keyPressEvent(e);
}
Thanks.

Related

Closing Popup and setting button label

I'm writing a C++ wxWidgets calculator application. I want to compress trigonometric function buttons into a single one to save on space, using what's basically a split button. If you left click on it, the current option is used. If you right click, a popup menu is opened, which contains all the buttons; when you click on one of them, it is used and the big button changes.
I've been suggested to use wxComboBox and other stuff for this job, but I preferred using wxPopupTransientWindow because this way I can display the buttons in a grid, making everything - in my opinion - neater.
Problem is, when I choose an option from the menu, the main button's ID changes (because when I reopen the menu the previously clicked button is light up as its ID and the big button's ID match), but the label does not. Furthermore, the popup is supposed to close itself when you left click on one of the buttons, but it does not.
This is the code for the custom button in the popup which is supposed to do all that stuff:
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxWindow* mBtn = this->GetParent()->GetParent();
mBtn->SetLabel(this->GetLabel());
mBtn->SetId(this->GetId());
this->GetParent()->Close(true);
}
}
This is the code for the custom button in the main frame which opens up the popup (temporary setup just to test if the whole thing is working):
void ikeButton::rightClick(wxMouseEvent& evt) // CREA PANNELLO ESTENSIONE
{
if (flags & EXPANDABLE)
{
std::vector<expandMenuInfo> buttons;
buttons.push_back(expandMenuInfo(L"sin", 3001));
buttons.push_back(expandMenuInfo(L"cos", 3002));
buttons.push_back(expandMenuInfo(L"tan", 3003));
buttons.push_back(expandMenuInfo(L"arcsin", 3004));
buttons.push_back(expandMenuInfo(L"arccos", 3005));
buttons.push_back(expandMenuInfo(L"arctan", 3006));
wxPoint p = this->GetScreenPosition();
size_t sz = this->GetSize().GetHeight() / 1.15;
expandMenu* menu = new expandMenu(this, buttons, sz, wxPoint(
p.x, p.y + this->GetSize().GetHeight() + 2));
menu->SetPosition(wxPoint(
menu->GetPosition().x - ((menu->GetSize().GetWidth() - this->GetSize().GetWidth()) / 2),
menu->GetPosition().y));
menu->Popup();
}
}
Let me know if I need to show more code.
This is probably a terrible way of doing this, but this is basically the first "serious" application I'm creating using the wxWidgets framework. Any help is appreciated.
when I choose an option from the menu, the main button's ID changes
(because when I reopen the menu the previously clicked button is light
up as its ID and the big button's ID match), but the label does not.
If you're creating the popup menu like in your previous post, you had a popup window with a panel as its child and the buttons were then children of the panel layed out with a sizer.
If that's still the case, this->GetParent() and should be the panel, this->GetParent()->GetParent() should be the popup. So this->GetParent()->GetParent()->GetParent() should be the trig function button (assuming you created the popup with the trig function button as the parent).
So I think the line wxWindow* mBtn = this->GetParent()->GetParent(); should be changed to wxWindow* mBtn = this->GetParent()->GetParent()->GetParent();.
Or slightly shorter wxWindow* mBtn = this->GetGrandParent()->GetParent();;
the popup is supposed to close itself when you left click on one of
the buttons, but it does not.
It looks like wxPopupTransientWindow has a special Dismiss method that is supposed to be used to close it.
So I think the line this->GetParent()->Close(true); should be changed to this->GetGrandParent()->Dismiss(); (Assuming as above that the buttons in the popup are children pf a panel).
Alternately, if you want a solution that will work regardless of the parentage of the controls in the popup window, you could have a utility function to find the popup ancestor which would look something like this:
wxPopupTransientWindow* FindPopup(wxWindow* w)
{
wxPopupTransientWindow* popup = NULL;
while ( w != NULL )
{
popup = wxDynamicCast(w, wxPopupTransientWindow);
if ( popup )
{
break;
}
w = w->GetParent();
}
return popup;
}
This uses the wxDynamicCast function which is slightly different from the c++ dynamic_cast expression. wxDynamicCast uses wxWidgets' RTTI system to check if the given pointer can be converted to the given type.
Then the mouseReleased method could use this utility function something like this:
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxPopupTransientWindow* popup = FindPopup(this);
if (popup ) {
wxWindow* mBtn = popup->GetParent();
mBtn->SetLabel(this->GetLabel());
mBtn->SetId(this->GetId());
mBtn->Refresh();
popup->Dismiss();
}
}
}
I'm not sure why you're setting trig function button to have a new id, but I assume you have a reason.
To make the SetLabel method work in your custom button class, I think the easist thing is to call the SetLabel() method in the button's constructor. This will store the string passed to the constructor in the button's internal label member.
Based on other questions, I think the ikeButton constructor looks something like this:
ikeButton::ikeButton(wxFrame* parent, wxWindowID id, wxString text,...
{
...
this->text = text;
To store the label, you would need to change the line this->text = text; to
SetLabel(text);
And when you draw the button, I think the method you use looks like this:
void ikeButton::render(wxDC& dc)
{
...
dc.DrawText(text, ...);
}
You would need to change, the line dc.DrawText(text, ...); to
dc.DrawText(GetLabel(), ...);
Likewise, any other references to the button's text member should be changed to GetLabel() instead.
Finally, when you set the label in the expandButton::mouseReleased method, it might be a good idea to call button's Refresh() method to force the button to redraw itself. I added that my suggestion for the mouseReleased method above.

How to emit QTextTexid::textChanged signal only in certain cases selectively?

Can you trigger the textChanged signal only for certain cases? for example triggering it for inserted text, inserted space characters but not backspace?
I am running checks for typed characters inside a QTextEdit every time the text changes and based on the results highlighting text inside a read-only QTextEdit in the background used as an always-on placeholder text for the user to look at while typing. If the user makes a mistake the character gets highlighted red and reset to it's initial background color after the mistake is fixed. The problem arises when the backspace key is pressed, as it is registered as a mistake and as a result the previous character also gets highlighted red.
void Widget::onTextChanged()
{
QChar c;
QString txt_contents = txtedit_->toPlainText();
if(txt_contents.isEmpty()){
c = '\0';
//reset text display
txtdisplay_->clear();
txtdisplay_->append(*label_text_);
}
else
c = txtedit_->toPlainText().back();
if(!texteditq_->isEmpty()){
if(c == texteditq_->head()){
//refresh text display
correct_++;
txtdisplay_->clear();
txtdisplay_->append(*label_text_);
//remove character that was used for the successful check from the
//queue
texteditq_->dequeue();
}else{
//set backgroud color to red for errors
fmt_->setBackground(Qt::red);
if(!txtedit_->toPlainText().isEmpty()){
//move cursor to the end of the editor, where the error is and save
//the position the error occurs at
c_edit_->movePosition(QTextCursor::End);
quint32 error_pos = c_edit_->position();
//move the cursor in the display for the background text and
//use the KeepAnchor move mode to highlight the misspelled char
c_display_->setPosition(error_pos-1,QTextCursor::MoveAnchor);
c_display_->setPosition(error_pos,QTextCursor::KeepAnchor);
//apply formating to that character
c_display_->setCharFormat(*fmt_);
}
}
}
}
As per OP's request, I am posting a solution that is a class called CustomTextEdit which is subclassing QTextEdit. It is hooking to keyPressEvent() and checking the key that was pressed. If it was other than Backspace then the custom signal keyPressed() will get emitted.
class CustomTextEdit : public QTextEdit {
Q_OBJECT
public:
explicit CustomTextEdit(QWidget *parent = nullptr) : QTextEdit(parent) {}
signals:
void keyPressed();
protected:
void keyPressEvent(QKeyEvent *e) override {
if (e->key() != Qt::Key_Backspace) {
emit keyPressed();
}
QTextEdit::keyPressEvent(e);
}
};

Qt, offset when restore geometry

With Qt 5.11, I have this code to save end restore geometry of a QDialog subclass :
class HlgRunoffEditorDialog:public QDialog
{
some code
}
void HlgRunoffEditorDialog::show()
{
if (isVisible())
return;
ReosSettings settings;
restoreGeometry(settings.value(QStringLiteral("RunoffEditorDialog/geometry")).toByteArray());
ui->splitter->restoreState(settings.value(QStringLiteral("RunoffEditorDialog/splitter/geometry")).toByteArray());
QDialog::show();
}
void HlgRunoffEditorDialog::closeEvent(QCloseEvent *event)
{
updateSettings();
QDialog::closeEvent(event);
}
void HlgRunoffEditorDialog::updateSettings()
{
ReosSettings settings;
settings.setValue(QStringLiteral("RunoffEditorDialog/geometry"),saveGeometry());
settings.setValue(QStringLiteral("RunoffEditorDialog/splitter/geometry"),ui->splitter->saveState());
}
The problem is when the show() method is called, the windows has an offset with the position before the close event. A picture is more explicit than text :
The red line is the position before the close event.
It seems like the new position is set the top left point of the widget excluding the windows frame before close event is set on the the top left point of the widget including the windows frame after show() method id called.
Any idea ?
Edit 1
This offset above is on Windows. When I run on Linux KDE, it seems like the offset is in the other direction ....
Edit 2 :
This offset appear anly when the QDialog is close with the cross on the top right. When the QDialog is closed with the close button (connect to the close() slot), the offset is not here ...
For correct resoring visibility states of widgets (as windows) you must follow this call order:
// 1) show the widget
widget->show();
// 2) set status bar visibility (if exists)
//widget->statusBar->setVisible(booleanValueFromSettings);
// 3) set margins (if use it)
//widget->setContentsMargins(a, b, c, d);
// 4) geometry
widget->restoreGeometry(byteArrayFromSettings);
// 5) state (can be use it and for you splitter)
widget->restoreState(byteArrayFromSettings);
I remember a project where I had to calculate a bit, something like this:
QRect ng = w->normalGeometry();
QRect frame = w->frameGeometry();
ng.adjust(-frame.x(), -frame.y(), -frame.x(), -frame.y());
and saving the latter values

Clear ExtraSelections Qt on slot disconnect

I am implementing a focus mode in QT QTextEdit in which I am highlighting single line where cursor is present. So far I can enable focus mode but when I disable focus mode, i want the state restored back to what it was.
The function that calls connect and disconnect is:
void MainWindow::onFocus_Mode_triggered()
{
QTextEdit *texed = qobject_cast<QTextEdit*>(ui->tabWidget->currentWidget());
if(ui->actionFocus_Mode->isChecked()){
connect(texed, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
}
else {
disconnect(texed, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); //First disconnect and then call method to clear ExtraSelections
BacktoNormal(); //Help needed in implementing this
}
}
Now when the menu item actionFocus_Mode is checked, the line where the cursor is currently present is highlighted in yellow by the function given below.
void MainWindow::highlightCurrentLine() {
QTextEdit *texed = qobject_cast<QTextEdit*>(ui->tabWidget->currentWidget());
QList<QTextEdit::ExtraSelection> extraSelections;
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(Qt::yellow).lighter(160);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = texed->textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
texed->setExtraSelections(extraSelections);
}
So I am able to highlight it in yellow but if(!ui->actionFocus_Mode->isChecked()), i.e, if menu item (focus mode) is unchecked then I wish to revert back to normal mode. How would I implement BacktoNormal() function.
What I think right now is that I should set lineColor to transparent or something to get it back to normal (if it is possible at all).
I am unable to find anything related to this. Any help would be useful as I am completely stuck at this point.
In your BackNormal try to set just nothing as extra selections.
QTextEdit *texed = qobject_cast<QTextEdit*>(ui->textEdit);
QList<QTextEdit::ExtraSelection> extraSelections;
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(Qt::yellow).lighter(160);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = texed->textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
extraSelections.clear();//nothing
texed->setExtraSelections(extraSelections);
When did I try this on my computer(with another code), this selections was successfully removed.
Smaller version:
QTextEdit *texed = qobject_cast<QTextEdit*>(ui->textEdit);
QList<QTextEdit::ExtraSelection> extraSelections;//empty list
texed->setExtraSelections(extraSelections);

How do I get the value of the slider's position in Qt Eclipse?

I have about 5 push buttons and one slider. Every time I click the push button, the function for the particular push button gets called.
However, I also want the slider to do the same. So, instead of pressing the push button, you can drag the slider to the 5 different positions and it will do the same. However, I dont really know how I can connect 5 different positions of the sliders to each push button. Any help would be appreciated.
Thanks
I don't even know what to say... it's kinda easy:
slider->setRange(0, 4);
connect(slider, SIGNAL(valueChanged(int)), SLOT(onSliderValueChanged(int)));
...
void Widget::onSliderValueChanged(int value)
{
switch (value)
{
case 0:
return onPushButton0Clicked();
...
}
}
void Widget::onPushButton0Clicked()
{
// do stuff
slider->blockSignals(true);
slider->setValue(0);
slider->blockSignals(false);
}
...