Pyside - 获取焦点时全选QLineEdit文本
我刚接触Qt/PySide,想要实现一个功能:当QLineEdit
获得焦点时,里面的所有文字都被选中。然后在选中所有文字后,只有在失去焦点再重新获得焦点时,才会再次选中所有文字。而在QLineEdit
获得焦点后,如果我只是移动光标位置,不希望它自动选中所有文字。请问我该怎么做?
更新:我根据Ashwani Kumar的建议改进了我的代码,但还是没能让它正常工作:
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_()
5 个回答
这些回答其实没有提供你可能想要的那种标准操作体验(用户也可能会期待这样的体验)。举个例子,如果你在一个没有全选的QLE上单击一次,然后再单击一次,通常你希望第一次单击是全选,第二次单击则是让光标放在你选择的具体位置。
这可以通过简单的方式来实现:
def mousePressEvent(self, event):
already_select_all = self.text() == self.selectedText()
super().mousePressEvent(event)
if not already_select_all:
self.selectAll()
实际上,这个问题是关于获得焦点的,不仅仅是通过鼠标点击。如果你是个喜欢用键盘的人,或者一般不喜欢用鼠标的人,你可能也希望每次QLE获得焦点时,整个文本都被选中,比如通过按Tab键或者使用QLabel
的“伙伴”助记符。这似乎可以解决这个问题:
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
这是一个关于使用 QTimer
的解决方案,来源于 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)
而且,这个解决方案不需要你去重新定义 QLineEdit
类。
你需要创建一个新的类,这个类要继承自 QLineEdit
,然后在你的代码中使用这个新创建的类,而不是直接使用 QLineEdit
。比如:
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent=None)
super(MyLineEdit, self).__init__(parent)
def focusInEvent(self, e):
self.selectAll()
lineedit = MyLineEdit()
为了将来访问这个页面的人,我在这里分享一段对我有效的代码。因为我还是个新手,所以不太确定这段代码是否有不好的写法。如果有的话,请随时留言,我会更新我的代码或回答。代码如下:
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_()
当你点击这个小部件时,focusInEvent
会被触发,但因为你在点击,所以它会把选中的文字去掉。
为了避免这个问题,我们需要使用mousePressEvent
,这可以通过两种方式来实现:
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_()
或者你也可以通过简单地重写基础的QLineEdit
类来做到这一点:
txt_demo = QtGui.QLineEdit()
txt_demo.mousePressEvent = lambda _ : txt_demo.selectAll()
不过,因为我们在修改mousePressEvent
,每当你尝试点击文字时,它都会先把所有文字选中。