Pressing Tab in QTextEdit in Dialog - change behavior - qt

I have QDialog that contains few buttons and a QTextEdit.
after writing something in the QTextEdit, I press tab in order to get to one of the buttons, but when I pressing tab, a tab space is added to the QTextEdit. How can I change this behavior?

You can use setTabChangesFocus method of QTextEdit:
yourTextEdit.setTabChangesFocus(true);

You can subclass QTextEdit and override the keyPressEvent to intercept the tab key. Then, use nextInFocusChain to determine the next focus widget and call setFocus on it
Outline:
class MyTextEdit : public QTextEdit
{
public:
MyTextEdit(QWidget *parent = 0) : QTextEdit(parent) {}
protected:
void keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Tab) {
nextInFocusChain()->setFocus(Qt::TabFocusReason);
} else {
QTextEdit::keyPressEvent(e);
}
}
};

Related

Identifying which label was clicked in qt

I have 10 Qlabels with an image on each. When i click on a label, its image should be cleared. I am able to identify which label was clicked theorotically, using the pixel clicked and size of each image. But how to use that information?
Eg. each label has dimension 100*100, the first label starting from 0,0. if pixel clicked is 250,50, i know that the third label was clicked, but how to use this to clear the label.
Im stuck.
There are a few ways how to implement it.
First. I would recommend to use a new class that inherits QLabel and overloads mouseReleaseEvent() handler where you just call clear() method. In this case the label will detect the mouse clicks itself and will clear its content internally.
class SelfClearingLabel : public QLabel
{
public:
using QLabel::QLabel;
protected:
void mouseReleaseEvent(QMouseEvent * event)
{
if (event->button()==Qt::LeftButton)
// process only clicks on the left button
{
clear();
}
QLabel::mouseReleaseEvent(event);
}
};
Second. You can catch mouseReleaseEvent() in your top widget and iterate over all of your child QLabel widgets and check which one is currently under mouse and clear the one. If you have other labels on this widget that shouldn't be cleared on mouse clicks then you can add some property to the QLabels that are under your interest.
void SomeTopFrame::createImageLabels(int count)
{
for (int i=0;i<count;i++)
{
QLabel* label=new QLabel(this);
label->setProperty("clear_on_click",true);
// assume that labels are added to layout *m_labelsLayout;
m_labelsLayout->addWidget(label);
}
}
void SomeTopFrame::mouseReleaseEvent(QMouseEvent * event)
{
if (event->button()==Qt::LeftButton)
// process only clicks on the left button
{
QList<QLabel*> labels=findChildren<QLabel*>();
foreach (QLabel* label, labels)
{
if (label->property("clear_on_click")&&label->underMouse())
{
label->clear();
break;
}
}
}
QFrame::mouseReleaseEvent(event);
}
It is a sample code just to show the principle. In production you can add a check that mouseReleaseEvent() is on the same widget as the mousePressEvent() to avoid triggering on drag and drop events.
Create the custom class that inherit QLabel :
ClickableLabel.h
class ClickableLabel : public QLabel
{
Q_OBJECT
public:
explicit ClickableLabel( const QString& text="", QWidget* parent=0 );
~ClickableLabel();
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent* event);
};
ClickableLabel.cpp
ClickableLabel::ClickableLabel(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
ClickableLabel::~ClickableLabel()
{
}
void ClickableLabel::mousePressEvent(QMouseEvent* event)
{
emit clicked();
}
Just connect all labels clicked signal to following slot :
MyClass::labelClicked()
{
ClickableLabel *label = (ClickableLabel*)QObject::sender;
if(label)
label->clear();
}

Toggle A QAction To Set QStackedWidget's Current Widget

So what I am trying to do is when I press the showMenu (QAction), the container (QStackedWidget) changes the current widget to menuWidget AND when I press it again it hides.
Ok so I have managed to get this code:
connect(showMenu, SIGNAL(triggered()), map, SLOT(map()));
map->setMapping(menuWidget, container);
Object::connect(map, SIGNAL(mapped(QWidget *)), container, SLOT(setCurrentWidget(QWidget *)));
also if I run:
container->setCurrentWidget(menuWidget);
directly, it works fine, so I have not messed up in that way.
You should create a slot in your class where you show/hide menuWidget.
If you are using a checkable QAction object, then you can use QAction::toggled(bool checked) signal, and use the checked variable to determine if you should show or hide your widget.
If you're not using a checkable QAction object, then you should create a class member variable of type bool that you toggle in your slot:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
...
private:
bool toggleStatus; // set this to false in your constructor
...
};
 
void MainWindow::menuToggled()
{
toggleStatus = !toggleStatus;
if(toggleStatus)
{
container->setCurrentWidget(menuWidget);
}
else
{
container->setCurrentWidget(mdiContainer);
}
}

What is the signal for when a widget loses focus?

In a dialog, when the tab key is pressed, the focus changes to another widget. In Qt, is there any signal for when a widget loses its focus? Can I use it to check if the input is valid or not? If not, can I set the focus back and ask the user to re-input?
There's no signal but if you want to know when your widget has lost focus, override and reimplement void QWidget::focusOutEvent(QFocusEvent* event) in your widget. It will be called whenever your widget has lost focus. To give focus to a widget, use QWidget::setFocus(Qt::FocusReason).
To validate input in a QLineEdit or QComboBox you can subclass QValidator and implement your own validator, or use one of the existing subclasses, QIntValidator, QDoubleValidator, or QRegExpValidator. Set the validator with QLineEdit::setValidator(const QValidator*) and QComboBox::setValidator(const QValidator*) respectively.
If you want to validate the contents of a modal dialog box, one way would be to override QDialog::exec() with an implementation like this:
int MyDialog::exec() {
while (true) {
if (QDialog::exec() == QDialog::Rejected) {
return QDialog::Rejected;
}
if (validate()) {
return QDialog::Accepted;
}
}
}
bool MyDialog::validate() {
if (lineEdit->text().isEmpty()) {
QMessageBox::critical(this, "Invalid value", "The specified value is not valid");
lineEdit->setFocus();
lineEdit->selectAll();
return false;
}
return true;
}
It will not allow the user to close the dialog with the OK button or any other button with the Accepted role unless the contents of the dialog is successfully validated. In this example I assume the dialog has a QLineEdit named lineEdit and the validate function will make sure that its content is not empty. If it is, it will set the focus to the QLineEdit and show the dialog again.
It is also possible (and easier) to create the signal yourself
In the .cpp (do not forget to include the moc)
class FocusWatcher : public QObject
{
Q_OBJECT
public:
explicit FocusWatcher(QObject* parent = nullptr) : QObject(parent)
{
if (parent)
parent->installEventFilter(this);
}
virtual bool eventFilter(QObject *obj, QEvent *event) override
{
Q_UNUSED(obj)
if (event->type() == QEvent::FocusIn)
emit focusChanged(true);
else if (event->type() == QEvent::FocusOut)
emit focusChanged(false);
return false;
}
Q_SIGNALS:
void focusChanged(bool in);
};
And to connect it:
connect(new FocusWatcher(myWidget), &FocusWatcher::focusChanged, this, &View::doSomething);

Signal click on QSpinBox Qt

I would like to open a window when I click on a QSpinBox. The problem is that there is no such signal "clicked" for this widget.
Does someone has an idea how to do that?
A QSpinBox is just a QLineEdit with two buttons, input validation and event handling. It doesn't have clicked signal because it's supposed to handle the mouse even itself.
The problem is that even making a custom widget derived from QSpinBox won't be enough since it doesn't receive the mouse events itself, they are handled by its children widgets. You could install an event filter on the QSpinBox children in order to catch the click event, but that's not the neatest way.
If you just want to display a numpad when the user select the box, you can use directly a QLineEdit. You will lose the QSpinBox buttons (but you can add your own ones if you need them) and the validation (but you can add you own using QValidator).
Then you just have to derive it in order to catch the focus event, trigger a custom signal which would show your keyboard :
class MySpinBox: public QLineEdit
{
Q_OBJECT
public:
MySpinBox(QWidget *parent = 0);
~MySpinBox();
signals:
needNumpad(bool hasFocus);
protected:
virtual void focusInEvent(QFocusEvent *e) {
QLineEdit::focusInEvent(e);
emit(needNumpad(true));
}
virtual void focusOutEvent(QFocusEvent *e) {
QLineEdit::focusInEvent(e);
emit(needNumpad(false));
}
}
You can use an event filter and do something like this:
ui->spinBox->installEventFilter(this);
QObjectList o_list = ui->spinBox->children();
for(int i = 0; i < o_list.length(); i++)
{
QLineEdit *cast = qobject_cast<QLineEdit*>(o_list[i]);
if(cast)
cast->installEventFilter(this);
}
And in the event filter you check for a mouse click (in this example its triggered by all mouse buttons, left click, right click, scroll wheel click etc.).
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
showNumpadDialog();
}
return false;
}
You do not need to create your own QSpinBox with QLineEdit and two buttons.
Since QLineEdit is the child of QSpinBox. You can create an event filter for QLineEdit and check whether its parent is a spinbox. Then so, you would get a click event for spin box.
if(event->type() == QEvent::MouseButtonPress && dynamic_cast<QSpinBox *>(dynamic_cast<QLineEdit *>(obj)->parent()) )

selecting the complete default text by a mouse click

I have a QLineEdit widget in my menubar which shows the text "search by ID" by default. How can I implement a MouseClicked event handler for the QLineEdit, such that when I click on the LineEdit widget, the default text is cleared and user can enter the text that he wants to search?.
so far
#ifndef SEARCH_H
#define SEARCH_H
#include<QLineEdit>
class search : public QLineEdit
{
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *);
};
#endif
You just need to connect QLineEdit::mousePressEvent ( QMouseEvent * e ) signal with function. When this signal will be emited, clear QLineEdit in your function. Simply, isn't it?
EDIT
Or if u have
void mousePressEvent(QMouseEvent *);
in your widget, all what you need is write definition for that method. When user press mouse over QLineEdit, this function will be invoked. Like:
void search::mousePressEvent(QMouseEvent *e)
{
myQLineEdit->setText("");
}
EDIT 2
Then try to do it this way:
class YourWidget : public QLineEdit
{
Q_OBJECT
protected:
void focusInEvent(QFocusEvent* e);
};
and
void YourWidget::focusInEvent(QFocusEvent* e)
{
if (e->reason() == Qt::MouseFocusReason)
{
myQLineEdit->setText("");
}
// You might also call the parent method.
QLineEdit::focusInEvent(e);
}
You'll want to use the QLineEdit::placeholderText property. It shows a grey text which disappears when the user starts editing it (i.e. when it gains focus).
QLineEdit * edit = new QLineEdit;
edit->setPlaceholderText("Search by ID");

Resources