QTableWdiget 单元格中的 QLineEdit 不会失去焦点
QLineEdit in QTableWdiget cell not losing focus
我目前正在尝试使用 PyQt5 制作图形界面。到现在为止一切都很好(毕竟我在这方面有一些经验),但是我已经为这个问题苦苦挣扎了几天,我在任何地方都找不到解决方案。
在我的应用程序中,我显示了来自 matplotlib 的 FigureCanvas(以及其他各种小部件),其中我有一个键事件连接到一个函数,该函数从鼠标单击中选取一个点并将该点保存在 QTableWidget 中。但是,我希望用户能够编辑使用验证器获取的 y 值,因此我将第二列从保存 QTableWidgetItem 更改为 QLineEdit 小部件。一切正常,除了当我在 table 中编辑 QLineEdit 小部件后按 enter 键时,焦点没有按预期更改(我将焦点设置为返回 canvas 但单元格保持活动状态光标闪烁)。
在同一个应用程序中,我在布局的其他地方有另一个 QLineEdit 小部件,它按预期工作。当我在此框中按下 enter 时,连接到其 returnPressed 信号的函数将焦点发送回 canvas。
谁能帮我弄清楚这是怎么回事?
此外,我不明白为什么当我在创建主框架时明确将焦点设置到 canvas 时应用程序启动时焦点在 QLineEdit 上。你知道如何解决这个问题吗?
我已将我的应用剥离回下面粘贴的最小示例,并且行为保持不变。
总结一下:
- 我点击 canvas 并按下 'a' 调用函数 'add_point'.
- 然后我单击绘图中的一个点,这会在 Widget 中创建一个新行并将焦点设置到第二列。
- 我在这里输入我想要的任何浮点值,然后按 Enter。
然后调用了函数 'print_val',但焦点并未按预期 return 到 canvas。光标在 table 单元格中保持闪烁。
当我编辑最左边的 QLineEdit(在 table 之外)并按下 Enter 时,函数 'func' 被调用并正确地将焦点发送回 canvas.
为什么 QLineEdit 的两个实例表现不同?
作为参考,函数 'print_val' 的输出给我:
TableWidget 有焦点?错误的
单元格编辑器有焦点?假
提前致谢!
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class GraphicInterface(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.setWindowTitle('Test')
self._main = QWidget()
self.setCentralWidget(self._main)
# Create Toolbar and Menubar
toolbar = QToolBar()
toolbar.setMovable(False)
toolbar_fontsize = QFont()
toolbar_fontsize.setPointSize(14)
quit_action = QAction("Close", self)
quit_action.setFont(toolbar_fontsize)
quit_action.setStatusTip("Quit the application")
quit_action.triggered.connect(self.close)
quit_action.setShortcut("ctrl+Q")
toolbar.addAction(quit_action)
# =============================================================
# Start Layout:
layout = QHBoxLayout(self._main)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.line_editor = QLineEdit("3")
self.line_editor.setValidator(QIntValidator(1, 100))
self.line_editor.returnPressed.connect(self.func)
layout.addWidget(self.line_editor)
# Create Table for Pixel Identifications:
pixtab_layout = QVBoxLayout()
label_pixtab_header = QLabel("Pixel Table\n")
label_pixtab_header.setAlignment(Qt.AlignCenter)
self.linetable = QTableWidget()
self.linetable.verticalHeader().hide()
self.linetable.setColumnCount(2)
self.linetable.setHorizontalHeaderLabels(["Pixel", "Wavelength"])
self.linetable.setColumnWidth(0, 80)
self.linetable.setColumnWidth(1, 90)
self.linetable.setFixedWidth(180)
pixtab_layout.addWidget(label_pixtab_header)
pixtab_layout.addWidget(self.linetable)
layout.addLayout(pixtab_layout)
# Create Figure Canvas:
right_layout = QVBoxLayout()
self.fig = Figure(figsize=(6, 6))
self.canvas = FigureCanvas(self.fig)
self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.canvas.updateGeometry()
self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.canvas.setFocusPolicy(Qt.StrongFocus)
self.canvas.setFocus()
right_layout.addWidget(self.canvas)
self.mpl_toolbar = NavigationToolbar(self.canvas, self)
right_layout.addWidget(self.mpl_toolbar)
layout.addLayout(right_layout)
# Plot some random data:
self.ax = self.fig.add_subplot(111)
self.ax.plot([0, 1, 5, 10, 20], [-1, 2, -4, 5, -2])
def on_key_press(self, e):
if e.key == "a":
self.add_point()
def add_point(self):
print("Select point...")
point = self.fig.ginput(1)
x0, _ = point[0]
rowPosition = self.linetable.rowCount()
self.linetable.insertRow(rowPosition)
item = QTableWidgetItem("%.2f" % x0)
item.setFlags(Qt.ItemIsEnabled)
item.setBackground(QColor('lightgray'))
self.linetable.setItem(rowPosition, 0, item)
y_item = QLineEdit("")
y_item.setValidator(QDoubleValidator())
y_item.returnPressed.connect(self.print_val)
self.linetable.setCellWidget(rowPosition, 1, y_item)
self.linetable.cellWidget(rowPosition, 1).setFocus()
def print_val(self):
rowPosition = self.linetable.rowCount()
editor = self.linetable.cellWidget(rowPosition-1, 1)
y_in = float(editor.text())
print(" Table value: %.2f" % y_in)
# and set focus back to canvas:
self.canvas.setFocus()
# Check which widget has focus:
focus_widget = self.focusWidget()
print(focus_widget.__class__)
print("TableWidget has focus? %r" % self.linetable.hasFocus())
print("Cell editor has focus? %r" % editor.hasFocus())
def func(self):
# dome some stuff
print(self.line_editor.text())
# and set focus back to canvas:
self.canvas.setFocus()
if __name__ == '__main__':
# Launch App:
qapp = QApplication(sys.argv)
app = GraphicInterface()
app.show()
qapp.exec_()
如果要验证 QTableWidget 的信息,则无需插入 QLineEdit,而是使用委托创建的 QValidator 并在那里设置 QValidator:
class ValidatorDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(ValidatorDelegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QLineEdit):
editor.setValidator(QtGui.QDoubleValidator(editor))
return editor
然后用view的edit方法打开编辑器,改变焦点可以使用delegate的closeEditor信号:
import sys
from matplotlib.backends.backend_qt5agg import (
FigureCanvas,
NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
from PyQt5 import QtCore, QtGui, QtWidgets
class ValidatorDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(ValidatorDelegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QLineEdit):
editor.setValidator(QtGui.QDoubleValidator(editor))
return editor
class GraphicInterface(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(GraphicInterface, self).__init__(parent)
self.setWindowTitle("Test")
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
# Create Toolbar and Menubar
toolbar = QtWidgets.QToolBar(movable=False)
toolbar_fontsize = QtGui.QFont()
toolbar_fontsize.setPointSize(14)
quit_action = QtWidgets.QAction("Close", self)
quit_action.setFont(toolbar_fontsize)
quit_action.setStatusTip("Quit the application")
quit_action.triggered.connect(self.close)
quit_action.setShortcut("ctrl+Q")
toolbar.addAction(quit_action)
self.line_editor = QtWidgets.QLineEdit("3")
self.line_editor.setValidator(QtGui.QIntValidator(1, 100))
label_pixtab_header = QtWidgets.QLabel(
"Pixel Table\n", alignment=QtCore.Qt.AlignCenter
)
self.linetable = QtWidgets.QTableWidget()
self.linetable.verticalHeader().hide()
self.linetable.setColumnCount(2)
self.linetable.setHorizontalHeaderLabels(["Pixel", "Wavelength"])
self.linetable.setColumnWidth(0, 80)
self.linetable.setColumnWidth(1, 90)
self.linetable.setFixedWidth(180)
delegate = ValidatorDelegate(self.linetable)
self.linetable.setItemDelegate(delegate)
layout = QtWidgets.QHBoxLayout(self._main)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(self.line_editor)
pixtab_layout = QtWidgets.QVBoxLayout()
pixtab_layout.addWidget(label_pixtab_header)
pixtab_layout.addWidget(self.linetable)
layout.addLayout(pixtab_layout)
# Create Figure Canvas:
right_layout = QtWidgets.QVBoxLayout()
self.fig = Figure(figsize=(6, 6))
self.canvas = FigureCanvas(self.fig)
self.canvas.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
self.canvas.updateGeometry()
self.canvas.mpl_connect("key_press_event", self.on_key_press)
self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.canvas.setFocus()
right_layout.addWidget(self.canvas)
self.mpl_toolbar = NavigationToolbar(self.canvas, self)
right_layout.addWidget(self.mpl_toolbar)
layout.addLayout(right_layout)
delegate.closeEditor.connect(self.canvas.setFocus)
# Plot some random data:
self.ax = self.fig.add_subplot(111)
self.ax.plot([0, 1, 5, 10, 20], [-1, 2, -4, 5, -2])
def on_key_press(self, e):
if e.key == "a":
self.add_point()
def add_point(self):
print("Select point...")
point = self.fig.ginput(1)
if not point:
return
x0, _ = point[0]
row = self.linetable.rowCount()
self.linetable.insertRow(row)
item = QtWidgets.QTableWidgetItem("%.2f" % x0)
item.setFlags(QtCore.Qt.ItemIsEnabled)
item.setBackground(QtGui.QColor("lightgray"))
self.linetable.setItem(row, 0, item)
index = self.linetable.model().index(row, 1)
self.linetable.edit(index)
if __name__ == "__main__":
# Launch App:
qapp = QtWidgets.QApplication(sys.argv)
app = GraphicInterface()
app.show()
qapp.exec_()
我目前正在尝试使用 PyQt5 制作图形界面。到现在为止一切都很好(毕竟我在这方面有一些经验),但是我已经为这个问题苦苦挣扎了几天,我在任何地方都找不到解决方案。
在我的应用程序中,我显示了来自 matplotlib 的 FigureCanvas(以及其他各种小部件),其中我有一个键事件连接到一个函数,该函数从鼠标单击中选取一个点并将该点保存在 QTableWidget 中。但是,我希望用户能够编辑使用验证器获取的 y 值,因此我将第二列从保存 QTableWidgetItem 更改为 QLineEdit 小部件。一切正常,除了当我在 table 中编辑 QLineEdit 小部件后按 enter 键时,焦点没有按预期更改(我将焦点设置为返回 canvas 但单元格保持活动状态光标闪烁)。
在同一个应用程序中,我在布局的其他地方有另一个 QLineEdit 小部件,它按预期工作。当我在此框中按下 enter 时,连接到其 returnPressed 信号的函数将焦点发送回 canvas。
谁能帮我弄清楚这是怎么回事?
此外,我不明白为什么当我在创建主框架时明确将焦点设置到 canvas 时应用程序启动时焦点在 QLineEdit 上。你知道如何解决这个问题吗?
我已将我的应用剥离回下面粘贴的最小示例,并且行为保持不变。
总结一下:
- 我点击 canvas 并按下 'a' 调用函数 'add_point'.
- 然后我单击绘图中的一个点,这会在 Widget 中创建一个新行并将焦点设置到第二列。
- 我在这里输入我想要的任何浮点值,然后按 Enter。
然后调用了函数 'print_val',但焦点并未按预期 return 到 canvas。光标在 table 单元格中保持闪烁。
当我编辑最左边的 QLineEdit(在 table 之外)并按下 Enter 时,函数 'func' 被调用并正确地将焦点发送回 canvas.
为什么 QLineEdit 的两个实例表现不同?
作为参考,函数 'print_val' 的输出给我: TableWidget 有焦点?错误的 单元格编辑器有焦点?假
提前致谢!
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class GraphicInterface(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.setWindowTitle('Test')
self._main = QWidget()
self.setCentralWidget(self._main)
# Create Toolbar and Menubar
toolbar = QToolBar()
toolbar.setMovable(False)
toolbar_fontsize = QFont()
toolbar_fontsize.setPointSize(14)
quit_action = QAction("Close", self)
quit_action.setFont(toolbar_fontsize)
quit_action.setStatusTip("Quit the application")
quit_action.triggered.connect(self.close)
quit_action.setShortcut("ctrl+Q")
toolbar.addAction(quit_action)
# =============================================================
# Start Layout:
layout = QHBoxLayout(self._main)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.line_editor = QLineEdit("3")
self.line_editor.setValidator(QIntValidator(1, 100))
self.line_editor.returnPressed.connect(self.func)
layout.addWidget(self.line_editor)
# Create Table for Pixel Identifications:
pixtab_layout = QVBoxLayout()
label_pixtab_header = QLabel("Pixel Table\n")
label_pixtab_header.setAlignment(Qt.AlignCenter)
self.linetable = QTableWidget()
self.linetable.verticalHeader().hide()
self.linetable.setColumnCount(2)
self.linetable.setHorizontalHeaderLabels(["Pixel", "Wavelength"])
self.linetable.setColumnWidth(0, 80)
self.linetable.setColumnWidth(1, 90)
self.linetable.setFixedWidth(180)
pixtab_layout.addWidget(label_pixtab_header)
pixtab_layout.addWidget(self.linetable)
layout.addLayout(pixtab_layout)
# Create Figure Canvas:
right_layout = QVBoxLayout()
self.fig = Figure(figsize=(6, 6))
self.canvas = FigureCanvas(self.fig)
self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.canvas.updateGeometry()
self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.canvas.setFocusPolicy(Qt.StrongFocus)
self.canvas.setFocus()
right_layout.addWidget(self.canvas)
self.mpl_toolbar = NavigationToolbar(self.canvas, self)
right_layout.addWidget(self.mpl_toolbar)
layout.addLayout(right_layout)
# Plot some random data:
self.ax = self.fig.add_subplot(111)
self.ax.plot([0, 1, 5, 10, 20], [-1, 2, -4, 5, -2])
def on_key_press(self, e):
if e.key == "a":
self.add_point()
def add_point(self):
print("Select point...")
point = self.fig.ginput(1)
x0, _ = point[0]
rowPosition = self.linetable.rowCount()
self.linetable.insertRow(rowPosition)
item = QTableWidgetItem("%.2f" % x0)
item.setFlags(Qt.ItemIsEnabled)
item.setBackground(QColor('lightgray'))
self.linetable.setItem(rowPosition, 0, item)
y_item = QLineEdit("")
y_item.setValidator(QDoubleValidator())
y_item.returnPressed.connect(self.print_val)
self.linetable.setCellWidget(rowPosition, 1, y_item)
self.linetable.cellWidget(rowPosition, 1).setFocus()
def print_val(self):
rowPosition = self.linetable.rowCount()
editor = self.linetable.cellWidget(rowPosition-1, 1)
y_in = float(editor.text())
print(" Table value: %.2f" % y_in)
# and set focus back to canvas:
self.canvas.setFocus()
# Check which widget has focus:
focus_widget = self.focusWidget()
print(focus_widget.__class__)
print("TableWidget has focus? %r" % self.linetable.hasFocus())
print("Cell editor has focus? %r" % editor.hasFocus())
def func(self):
# dome some stuff
print(self.line_editor.text())
# and set focus back to canvas:
self.canvas.setFocus()
if __name__ == '__main__':
# Launch App:
qapp = QApplication(sys.argv)
app = GraphicInterface()
app.show()
qapp.exec_()
如果要验证 QTableWidget 的信息,则无需插入 QLineEdit,而是使用委托创建的 QValidator 并在那里设置 QValidator:
class ValidatorDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(ValidatorDelegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QLineEdit):
editor.setValidator(QtGui.QDoubleValidator(editor))
return editor
然后用view的edit方法打开编辑器,改变焦点可以使用delegate的closeEditor信号:
import sys
from matplotlib.backends.backend_qt5agg import (
FigureCanvas,
NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
from PyQt5 import QtCore, QtGui, QtWidgets
class ValidatorDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = super(ValidatorDelegate, self).createEditor(parent, option, index)
if isinstance(editor, QtWidgets.QLineEdit):
editor.setValidator(QtGui.QDoubleValidator(editor))
return editor
class GraphicInterface(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(GraphicInterface, self).__init__(parent)
self.setWindowTitle("Test")
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
# Create Toolbar and Menubar
toolbar = QtWidgets.QToolBar(movable=False)
toolbar_fontsize = QtGui.QFont()
toolbar_fontsize.setPointSize(14)
quit_action = QtWidgets.QAction("Close", self)
quit_action.setFont(toolbar_fontsize)
quit_action.setStatusTip("Quit the application")
quit_action.triggered.connect(self.close)
quit_action.setShortcut("ctrl+Q")
toolbar.addAction(quit_action)
self.line_editor = QtWidgets.QLineEdit("3")
self.line_editor.setValidator(QtGui.QIntValidator(1, 100))
label_pixtab_header = QtWidgets.QLabel(
"Pixel Table\n", alignment=QtCore.Qt.AlignCenter
)
self.linetable = QtWidgets.QTableWidget()
self.linetable.verticalHeader().hide()
self.linetable.setColumnCount(2)
self.linetable.setHorizontalHeaderLabels(["Pixel", "Wavelength"])
self.linetable.setColumnWidth(0, 80)
self.linetable.setColumnWidth(1, 90)
self.linetable.setFixedWidth(180)
delegate = ValidatorDelegate(self.linetable)
self.linetable.setItemDelegate(delegate)
layout = QtWidgets.QHBoxLayout(self._main)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(self.line_editor)
pixtab_layout = QtWidgets.QVBoxLayout()
pixtab_layout.addWidget(label_pixtab_header)
pixtab_layout.addWidget(self.linetable)
layout.addLayout(pixtab_layout)
# Create Figure Canvas:
right_layout = QtWidgets.QVBoxLayout()
self.fig = Figure(figsize=(6, 6))
self.canvas = FigureCanvas(self.fig)
self.canvas.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
self.canvas.updateGeometry()
self.canvas.mpl_connect("key_press_event", self.on_key_press)
self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.canvas.setFocus()
right_layout.addWidget(self.canvas)
self.mpl_toolbar = NavigationToolbar(self.canvas, self)
right_layout.addWidget(self.mpl_toolbar)
layout.addLayout(right_layout)
delegate.closeEditor.connect(self.canvas.setFocus)
# Plot some random data:
self.ax = self.fig.add_subplot(111)
self.ax.plot([0, 1, 5, 10, 20], [-1, 2, -4, 5, -2])
def on_key_press(self, e):
if e.key == "a":
self.add_point()
def add_point(self):
print("Select point...")
point = self.fig.ginput(1)
if not point:
return
x0, _ = point[0]
row = self.linetable.rowCount()
self.linetable.insertRow(row)
item = QtWidgets.QTableWidgetItem("%.2f" % x0)
item.setFlags(QtCore.Qt.ItemIsEnabled)
item.setBackground(QtGui.QColor("lightgray"))
self.linetable.setItem(row, 0, item)
index = self.linetable.model().index(row, 1)
self.linetable.edit(index)
if __name__ == "__main__":
# Launch App:
qapp = QtWidgets.QApplication(sys.argv)
app = GraphicInterface()
app.show()
qapp.exec_()