How to get Click Event of QLineEdit in Qt? - qt

How to get Click Event of QLineEdit in Qt ?
I am not able to see any SLOT related to click in QLineEdit ?

I don't think subclassing a QLineEdit is the right choice. Why subclass if you don't need to? You could instead use event filters. Check out QObject::eventFilter.
Example:
MyClass::MyClass() :
edit(new QLineEdit(this))
{
edit->installEventFilter(this);
}
bool MyClass::eventFilter(QObject* object, QEvent* event)
{
if(object == edit && event->type() == QEvent::FocusIn) {
// bring up your custom edit
return false; // lets the event continue to the edit
}
return false;
}

You need to reimplement focusInEvent in a new class extending QLineEdit. The following links are going to help you.
http://doc.qt.io/qt-5/qwidget.html#focusInEvent
QLineEdit - focus event
How to know if a QLineEdit got focus?
QLineEdit Focus Event

Although there is no "clicked" or "entered" event. You can use the
void cursorPositionChanged(int old, int new)
Signal. It is emitted when the user clicks the lineedit (if it is enabled) and also on a few other occasions so you have to verify which of the events actually happened but I think this is still easier than subclassing or using the event listener for some applications.

I dono if this will help,
i had to call a function once a text is entered. This is how i did it.
connect(ui->passwordSetLineEdit,SIGNAL(textEdited(QString)),this,SLOT(onTextEdit(QString)));
when a text is entered textEdited signal will be emited, thus my onTextEdit function will be called.

There is no signals like clicked() for QLineEdit, but you can subclass it and emit such signal in your custom implementation of mouseReleaseEvent.

I used this solution many times
def clickable(widget): # make this function global
class Filter(QObject):
clicked = pyqtSignal()
def eventFilter(self, obj, event):
if obj == widget and event.type() == QEvent.MouseButtonRelease and obj.rect().contains(event.pos()):
self.clicked.emit()
return True
else:
return False
filter = Filter(widget)
widget.installEventFilter(filter)
return filter.clicked
clickable(self.lineedit).connect(self.test) #use this in class
def test(self):
print("lineedit pressed")
pass

Just use the Pushbutton clicked event. Change the backcolor of the Pushbutton into Transparent then remove the text of it. Lay it in front of the LineEdit then use the setfocus property of the LineEdit when the push button was clicked. That's the easiest way to get the clicked event and use it in LineEdit.. 😉

Related

Triggering an action based on its custom shortcut

Suppose I have some action to happen. For that I can create a QAction object and connect its triggered() signal to the slot that executes the desired function. Also, I can have a shortcut associated with the action; by changing the shortcut I'll be able to execute the same action with that shortcut.
My problem now is that the "shortcut" I wanna set to the action, contains also a mouse button press (and mouse events cannot be assigned to action shortcuts); say I want Shift+Left mouse button. Maybe this sounds a little bit harsh but bear with me.
What do I need? Well, I have a button, and an action (say "execute a script"). I want the script to execute when Shift+Left click is clicked, and I want this "shortcut" to be customized, i.e. the user should be able to change to shortcut to, say Ctrl+Left click (from some GUI element, e.g. button text), and now Ctrl+Left click should execute the script.
How can I achieve this?
Note: I as a user would expect an action triggered by a mouse button to be position dependent. If so, the following gets a bit simpler.
Qt doesn't have an option to specify such a shortcut.
You can roll your own by reacting to mouse events:
Maybe you have an event handler mousePressEvent(),
or a generic eventFilter(QObject *obj, QEvent *evt),
or utilize QApplication::notify
Whichever, at some place you need to catch a QMouseEvent *mouseEvt.
Choose the widget (or qApp) that is as outmost as needed.
There, compare mouseEvt->button() and mouseEvt->modifiers() to your list of actions and trigger the selected action. When the user chooses another trigger method, adjust your list of actions.
Let's put this to practice:
class MainWindow : public QWidget {
Q_OBJECT
public:
QMap<QPair<Qt::MouseButton, Qt::KeyboardModifiers>, QAction*> mapMouseShortcuts;
QAction *pLaunchScript;
MainWindow() : QWidget() {
mapMouseShortcuts.insert(qMakePair(Qt::LeftButton, Qt::ControlModifier), pLaunchScript);
}
void mousePressEvent(QMouseEvent *me) {
QAction *action = mapMouseShortcuts.value(qMakePair(me->button(), me->modifiers()), Q_NULLPTR);
if(action != Q_NULLPTR) {
action->trigger();
me->accept(); // optional
}
// optional:
if(!me->isAccepted()) {
QWidget::mousePressEvent(me);
}
}
};

How to disable right click in a QTreeWidget in PyQt?

I have a QTreeWidget where I want to disable right click on the item. Currently I am using itemClicked signal to detect clicks on children of the treeWidget, but I only want to do something when the user left clicks an item and do nothing on right click. Both left and right clicks are getting detected right now and I am not able to differentiate between the two.
Thanks in advance!
You can reimplement the treewidget's mouse release event:
class TreeWidget(QtGui.QTreeWidget):
def mouseReleaseEvent(self, event):
if event.button() != QtCore.Qt.RightButton:
super(TreeWidget, self).mouseReleaseEvent(event)
or install an event-filter on the treewidget's viewport:
class MainWindow(QtGui.QMainWindow):
def __init__(self):
...
self.tree = QtGui.QTreeWidget(self)
self.tree.viewport().installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.MouseButtonRelease and
event.button() == QtCore.Qt.RightButton and
source is self.tree.viewport()):
return True
return super(Window, self).eventFilter(source, event)
You can override the MouseEvent:
void MyTreeWidget::mousePressEvent ( QMouseEvent * event )
{
event->accept();
}
To preserve the usual behaviour of the Widget you have to call the base class for all Buttons you want to work.
void MyTreeWidget::mousePressEvent ( QMouseEvent * event )
{
if(event->button() == Qt::RightButton)
event->accept(); // accept event and do nothing
else:
QTreeView::mousePressEvent(event)
}
EDIT:
Have just noticed that you are working with Python: the mechanics are the same so the above Example should work if translated to Python.
If I understad you correctly you want to disable selection .
I'm not familiar to PyQT but in C++ you should write code like this:
yourtreeView->setSelectionMode(QAbstractItemView::NoSelection);
In this case items would not get selected but you still will see focus rectangle around them. To fix this you can set your widget to not accept focus by calling:
yourtreeView->setFocusPolicy(Qt::NoFocus);

How to catch QComboBox popup close event

A am using QComboBox derived class to show my items. My combo box is read only. But how can I catch the event when popup view of combo box closes?.For example, when user clicks a mouse button somewhere out of my combo box?
Thank you very much in advance.
What for do you want this event? If the QComboBox closes without selection nothing changed. The signals given will only be activated when a selection has been made.
If you insist on reading a "close-event", you could subclass focusOutEvent(QFocusEvent*) or use an event handler for the focus out event and emit a custom signal. Eventually you want to have a boolean flag set on hadEditFocus() before, so you can see if the dropdown would be opened.
Edit:
Eventually it would be easier to subclass and reimplement showPopup() and hidePopup() as:
void MyClass::showPopup()
{
QComboBox::showPopup();
emit signalPopupShown();
}
void MyClass::hidePopup()
{
QComboBox::hidePopup();
emit signalPopupHidden();
}
but I am not sure if hidePopup() gets called on focus-loose.

Esc key press event for QListView

I created a simple QListView added a QStringListModel that allow items to be added and their text edited. But I don't want to allow empty fields to be added and I partially achieved this by using the dataChanged signal from the model which is emitted if the list item loses focus without text inserted or the user presses the Enter key without adding text.
However if you press the Esc key, the field remains empty and no dataChanged signal is emitted. How can I get notified if the field was left empty without overloading the QListView class which would be tedious(I used the designer to create the form)?
Is there another signal that is emitted or method I can use to achieve that?
Thanks!
Use event filters in your main GUI class:
void GUI::GUI()
{
ui->mListView->installEventFilter(this);
}
bool GUI::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->mListView && event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Escape)
// special Esc handling here
}
else
return false;
}
It's simple to use your custom widgets in Qt Designer. Right click on the QListView and choose Promote to ... there add a new class and apply it to the widget.
http://qt-project.org/doc/qt-4.8/designer-using-custom-widgets.html

Is it possible to deselect in a QTreeView by clicking off an item?

I'd like to be able to deselect items in my QTreeView by clicking in a part of the QTreeView with no items in, but I can't seem to find anyway of doing this. I'd intercept a click that's not on an item, but the QTreeView doesn't have a clicked signal, so I can't work out how to do this.
Based on #Eric's solution, and as it only deselects if the clicked item was selected, here is what I came up with.
This solution also works when you click the blank area of the QTreeView
#ifndef DESELECTABLETREEVIEW_H
#define DESELECTABLETREEVIEW_H
#include "QTreeView"
#include "QMouseEvent"
#include "QDebug"
class DeselectableTreeView : public QTreeView
{
public:
DeselectableTreeView(QWidget *parent) : QTreeView(parent) {}
virtual ~DeselectableTreeView() {}
private:
virtual void mousePressEvent(QMouseEvent *event)
{
QModelIndex item = indexAt(event->pos());
bool selected = selectionModel()->isSelected(indexAt(event->pos()));
QTreeView::mousePressEvent(event);
if ((item.row() == -1 && item.column() == -1) || selected)
{
clearSelection();
const QModelIndex index;
selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
}
}
};
#endif // DESELECTABLETREEVIEW_H
Yassir
This is actually quite simple (in PyQt):
class DeselectableTreeView(QtGui.QTreeView):
def mousePressEvent(self, event):
self.clearSelection()
QtGui.QTreeView.mousePressEvent(self, event)
Qt uses mousePressEvent to emit clicked. If you clear the selection before sending on the event, then if an item is clicked it will be selected, otherwise nothing will be selected. Many thanks to Patrice for helping me out with this one :)
The clearSelection does not work in my case. I'm using treeviews with a singleselection mode. Here is what I've coded:
class DeselectableTreeView : public QTreeView
{
public:
DeselectableTreeView(QWidget *parent) : QTreeView(parent) {}
virtual ~DeselectableTreeView() {}
private:
virtual void mousePressEvent(QMouseEvent *event)
{
QModelIndex item = indexAt(event->pos());
bool selected = selectionModel()->isSelected(item);
QTreeView::mousePressEvent(event);
if (selected)
selectionModel()->select(item, QItemSelectionModel::Deselect);
}
};
This works really fine.
Eric
QTreeView inherits from QAbstractView (http://doc.qt.digia.com/4.6/qtreeview.html) which has a clicked signal. The problem is that the signal is emitted only when index is valid so you can not achieve what you want with this signal.
Try to intercept the mousePressEvent instead. In the function you can find where the user has clicked and deselect selected item if needed.
In the answer by #Skilldrick, we risk sending superfluous events. If an item is already selected, and we're clicking it again, we are raising deselected and selected events. Based on other listeners in your application, this might not be what you want.
The solution by #eric-maeker only deselects an item if we click it again while it is already selected. Strictly speaking, this is not the answer to the original question, which was how to deselect the selected item when clicking somewhere else.
#yassir-ennazk gets close, but as pointed out by #adrian-maire, the solution is not optimal. event->pos() is evaluated twice. Also, the mouse event is always evaluated by calling QTreeView::mousePressEvent.
Here's the solution I've come up with, based on the other answers mentioned above. If we're clicking at a point where another tree view item is present, the new item is selected by forwarding the event to the TreeView. If not, we're clearing the selection.
Note that this works for QTreeWidgets as well.
virtual void mousePressEvent(QMouseEvent* event)
{
QModelIndex item = indexAt(event->pos());
if (item.isValid())
{
QTreeView::mousePressEvent(event);
}
else
{
clearSelection();
const QModelIndex index;
selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
}
}
To add to #Skilldrick's answer, if you need to apply this to a view that has already been instantiated because you're using Qt Designer, you can do something like this:
import new
def mousePressEvent(self, event):
self.clearSelection()
QtGui.QTableView.mousePressEvent(self, event)
self.ui.tableView.mousePressEvent = new.instancemethod(mousePressEvent, self.ui.tableView, None)
This assumes that your view is self.ui.tableView.
Thanks to this answer: https://stackoverflow.com/a/1647616/1300519
You could try setting a different selection mode for your widget. I don't know if any of them quite covers what it appears you want (single selection, but deselectable).
Since the question is specifically about PyQt, I'd like to add this based on the answer by Nick Pruehs and the comment by ekhumoro, the simplest way to achieve this:
class TreeView(QTreeView):
def __init__(self, *args, **kwds):
QTreeView.__init__(self, *args, **kwds)
def mousePressEvent(self, event):
item = self.indexAt(event.pos())
if not item.isValid():
self.clearSelection()
QTreeView.mousePressEvent(self, event)

Resources