I am new to Qt/PySide. I want QLineEdit to select all text in it when it gets focus. After getting focus and selecting all text, it should select all text only after focus is lost and gained again. It should not select all text when I change cursor position after QLineEdit gains focus. How do I do that?
Update: My current code improved as suggested by Ashwani Kumar. I still can't get it to work though:
import sys
from PySide.QtGui import QLineEdit, QApplication, QVBoxLayout, QWidget
class MyLineEdit(QLineEdit):
def __init__(self, parent=None):
super(MyLineEdit, self).__init__(parent)
def focusInEvent(self, e):
self.selectAll()
app = QApplication(sys.argv)
top = QWidget()
layout = QVBoxLayout()
layout.addWidget(MyLineEdit())
layout.addWidget(MyLineEdit())
top.setLayout(layout)
top.show()
app.exec_()
With focusInEvent, when you click the widget, it gets executed, but since you click, it removes the selected text.
To overcome this, we must use the mousePressEvent, this can be done two ways:
import sys
from PySide.QtGui import QLineEdit, QApplication, QVBoxLayout, QWidget
class MyLineEdit(QLineEdit):
def __init__(self, parent=None):
super(MyLineEdit, self).__init__(parent)
def mousePressEvent(self, e):
self.selectAll()
app = QApplication(sys.argv)
top = QWidget()
layout = QVBoxLayout()
layout.addWidget(MyLineEdit())
layout.addWidget(MyLineEdit())
top.setLayout(layout)
top.show()
app.exec_()
Or you can do it by simply overriding the base QLineEdit class:
txt_demo = QtGui.QLineEdit()
txt_demo.mousePressEvent = lambda _ : txt_demo.selectAll()
However, since we are modifying the mousePressEvent, whenever you try to click text, it will always select all first.
For future visitors, I am posting code that is working for me. As I am a newbie I am not sure if the code contains any malpractices. If it does feel free to comment and I'll update my code/answer. Code:
import sys
from PySide.QtGui import QLineEdit, QApplication, QVBoxLayout, QWidget
class LineEdit(QLineEdit):
def __init__(self, parent=None):
super(LineEdit, self).__init__(parent)
self.readyToEdit = True
def mousePressEvent(self, e, Parent=None):
super(LineEdit, self).mousePressEvent(e) #required to deselect on 2e click
if self.readyToEdit:
self.selectAll()
self.readyToEdit = False
def focusOutEvent(self, e):
super(LineEdit, self).focusOutEvent(e) #required to remove cursor on focusOut
self.deselect()
self.readyToEdit = True
app = QApplication(sys.argv)
top = QWidget()
layout = QVBoxLayout()
layout.addWidget(LineEdit())
layout.addWidget(LineEdit())
top.setLayout(layout)
top.show()
app.exec_()
You have to subclass the QLineEdit and then use the new class instead of QLineEdit.
e.g: -
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent=None)
super(MyLineEdit, self).__init__(parent)
def focusInEvent(self, e):
self.selectAll()
lineedit = MyLineEdit()
QTimer solution as seen on QtCentre:
import types
from PyQt4 import QtCore
def bind(func, to):
"Bind function to instance, unbind if needed"
return types.MethodType(func.__func__ if hasattr(func, "__self__") else func, to)
...
self.txtSrc.focusInEvent = bind(lambda w, e: QtCore.QTimer.singleShot(0, w.selectAll), self.txtSrc)
Also the provided solution doesn't require to subclass QLineEdit.
These answers don't really provide the sort of standard ergonomics you'd probably want (and users might expect). For example, if you single-click once on a QLE which is not currently all-selected, and then single-click again, typically you'd want the first click to select-all, and the second click to allow you to place the cursor in the specific spot you have chosen.
This can be achieved simply by doing this:
def mousePressEvent(self, event):
already_select_all = self.text() == self.selectedText()
super().mousePressEvent(event)
if not already_select_all:
self.selectAll()
The question in fact asks about gaining focus, not specifically by mouse-clicking, and indeed, if you are a keyboardist or generally musophobic you'll probably also want the whole text to be selected any time the QLE gains focus, e.g. by tabbing or by use of a QLabel "buddy" mnemonic. This seems to do the job:
class MyLineEdit(QtWidgets.QLineEdit):
def __init__(self, *args):
super().__init__(*args)
self.focus_in_reason = None
def focusInEvent(self, event):
super().focusInEvent(event)
self.selectAll()
self.focus_in_reason = event.reason()
def mousePressEvent(self, event):
super().mousePressEvent(event)
if self.focus_in_reason == QtCore.Qt.MouseFocusReason:
self.selectAll()
self.focus_in_reason = None
Related
This question already has an answer here:
How to Catch Hover and Mouse Leave Signal In PyQt5
(1 answer)
Closed 2 years ago.
I know someone had asked this almost exact same question previously (How to Catch Hover and Mouse Leave Signal In PyQt5)
But I didn't really understand how or where to implement it, I just need some clarification.
Basically, what the user did was he created a second class called button, which he used to create a button. For example, this was the code:
class Button(QPushButton):
def __init__(self, parent=None):
super(Button, self).__init__(parent)
# other initializations...
def enterEvent(self, QEvent):
print("enter")
pass
def leaveEvent(self, QEvent):
print("leave")
pass
Now, in order to create a button with this class, all we need to do is call the class like this:
self.buttn = Button(self)
This creates a button using the previous class. Therefore, this is what the whole code will look like:
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
import PyQt5.QtGui
from PyQt5.QtCore import QEvent
import sys
class Button(QPushButton):
def __init__(self, parent=None):
super(Button, self).__init__(parent)
# other initializations...
def enterEvent(self, QEvent):
print("enter")
pass
def leaveEvent(self, QEvent):
print("leave")
pass
class Main(QWidget):
def __init__(self):
super(Main,self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Button")
self.setGeometry(400,400,300,260)
self.buttn = Button(self)
self.buttn.setText("Button") #text
self.buttn.clicked.connect(self.close)
self.buttn.move(100,100)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())
I have some trouble customizing a class including a QPushButton and QLabel, and I just want to set the QPushButton checkable and define a slot to its toggled signal, in addition, the custom class inherents QObject.
The code is shown below,
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSlot, QObject
class CustomButton(QPushButton):
def __init__(self, label='', parent=None):
super().__init__(label, parent)
self.setCheckable(True)
self.toggled.connect(self.update)
def update(self, state):
if state:
self.setStyleSheet('background-color: green')
else:
self.setStyleSheet('background-color: red')
class ButtonCtrl(QObject):
def __init__(self, parent=None, label=''):
super().__init__()
if isinstance(parent, QLayout):
col = QVBoxLayout()
parent.addLayout(col)
else:
col = QVBoxLayout(parent)
self.text = ['ON', 'OFF']
self.label = QLabel(label)
self.button = QPushButton('ON')
# self.button = CustomButton('ON')
col.addWidget(self.label)
col.addWidget(self.button)
self.button.setCheckable(True)
self.button.setChecked(True)
self.button.toggled.connect(self.update)
self.update(True)
self.label.setFont(QFont('Microsoft YaHei', 14))
self.button.setFont(QFont('Microsoft YaHei', 12, True))
self.button.toggle()
# #pyqtSlot(bool)
def update(self, state):
if state:
self.button.setText(self.text[0])
self.button.setStyleSheet('background-color: green')
else:
self.button.setText(self.text[-1])
self.button.setStyleSheet('background-color: red')
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# set the layout
layout = QVBoxLayout(self)
but = ButtonCtrl(layout, "Test")
#self.but = ButtonCtrl(layout, "Test")
btn = CustomButton()
layout.addWidget(btn)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion')
main = Window()
main.show()
sys.exit(app.exec_())
I have customized two buttons, named CustomButton(QPushButton) and ButtonCtrl(QObject), and I have tested the slot in the main window, however the background update slot works for CustomButton(QPushbutton) and does not work for ButtonCtrl(QObject), the slot function is not even invoked.
However, if I change the button member of ButtonCtrl(QObject) from QPushButton into my CustomButton(QPushButton), the it will work well in the main window. Furthermore, if the but in main window becomes a member of the main window class by setting self.but=ButtonCtrl(layout, "Test"), it will work as well.
I didn't find direct answer to it in Qt documentation which explains that
Signals are emitted by an object when its internal state has changed in some way that might be interesting to the object's client or owner. Signals are public access functions and can be emitted from anywhere, but we recommend to only emit them from the class that defines the signal and its subclasses.
I am not sure if the lifetime of the but causing this effect, hope to get an answer, thank you.
The problem is simple: The ButtonCtrl class object has a local scope so it will be destroyed, and why doesn't the same happen with the CustomButton class object? Well, because the ownership of a QWidget has its parent, and the parent of that button is the window, instead the ButtonCtrl object does not have it. In this case the solution is to extend the life cycle of the variable, and in the case of a QObject there are several options:
make the class member variable,
Place it in a container with a longer life cycle, or
establish a QObject parent with a longer life cycle.
Using the third alternative is just to change to:
class ButtonCtrl(QObject):
def __init__(self, parent=None, label=''):
super().__init__(parent)
# ...
The first option is the one commented on in your code:
self.but = ButtonCtrl(layout, "Test")
and the second is similar:
self.container = list()
but = ButtonCtrl(layout, "Test")
self.container.append(but)
I am new to PyQt. I designed a form in QtDeveloper which have three controls. One push button, one combo box and one line edit. The name of the line edit widget in my ui form is myLineEdit. I want to know which Qwidget got focus (QLineEdit or QComboBox). I implement the code obtained from internet. When the code run, a separate line edit is created and it works fine. But I want to give the focusInEvent to myLineEdit widget created in the .ui form. My code is given. Please help.
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent=None):
super(MyLineEdit, self).__init__(parent)
def focusInEvent(self, event):
print 'focus in event'
self.clear()
QLineEdit.focusInEvent(self, QFocusEvent(QEvent.FocusIn))
class MainWindow(QtGui.QMainWindow,Ui_MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.myLineEdit = MyLineEdit(self)
You must implement the eventFilter method and enable this property to the widgets that are needed with:
{your widget}.installEventFilter(self)
The eventFilter method has as information the object and type of event.
Example
import sys
from PyQt5 import uic
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import QApplication, QWidget
uiFile = "widget.ui" # Enter file here.
Ui_Widget, _ = uic.loadUiType(uiFile)
class Widget(QWidget, Ui_Widget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.setupUi(self)
self.lineEdit.installEventFilter(self)
self.pushButton.installEventFilter(self)
self.comboBox.installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == QEvent.FocusIn:
if obj == self.lineEdit:
print("lineedit")
elif obj == self.pushButton:
print("pushbutton")
elif obj == self.comboBox:
print("combobox")
return super(Widget, self).eventFilter(obj, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Ouput:
lineedit
pushbutton
combobox
pushbutton
lineedit
I have created two different pyqt windows, and within one of them, by pressing a button, it should bring up another smaller window. While my code does pretty much exactly what I just dais it should do, there is a problem with the way the smaller popup window is displayed.
This is my code for displaying the windows and the button functionality:
from PyQt4 import QtGui
from EnterprisePassport import Ui_StudentEnterprisePassport
from Session_tracker import Ui_Session_tracker
class StudentEnterprisePassport(Ui_StudentEnterprisePassport):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.sessionTracker_btn.clicked.connect(self.handleButton)
self.window2 = None
def handleButton(self):
if self.window2 is None:
self.window2 = Session_tracker(self)
self.window2.show()
class Session_tracker(Ui_Session_tracker):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = StudentEnterprisePassport()
window.show()
sys.exit(app.exec_())
I can still use the functions within the window, but I can't move it, or close it, and there is no title bar. Have I done something wrong within my code for the popup window to appear like this?
Edit:
Original Session tracker window: Original window
Popup session tracker window: Popup window
In order to show the other widget in it's own window, it has to be a QMainWindow or a QDialog.
One option, if you don't want to convert your existing Session_tracker to a QDialog, is to just wrap it in a QDialog
def handleButton(self):
if self.window2 is None:
self.window2 = QtGui.QDialog(self)
lay = QtGui.QVBoxLayout()
self.window2.setLayout(lay)
self.session_tracker = Session_tracker(self.window2)
lay.addWidget(self.session_tracker)
self.window2.show()
I currently have a hidden QWidget, which contains a QLineEdit
Upon showing that hidden QWidget, I want the cursor to be on the QLineEdit. Any help with implementation?
This class is shown when a button is clicked in an earlier class
class showInfo(QtGui.QWidget):
def __init__(self, parent=None):
super(showInfo, self).__init__(parent)
showName = QtGui.QLabel("Name of Show:")
self.showNameEdit = QtGui.QLineEdit()
self.showNameEdit.setCursorPosition(0) #THIS SHOULD WORK
self.mainLayout = QtGui.QGridLayout()
self.mainLayout.addWidget(self.showNameEdit)
self.setLayout(self.mainLayout)
try calling self.showNameEdit.setFocus()