【问题标题】:QLineEdit in QTableWdiget cell not losing focusQTableWdiget 单元格中的 QLineEdit 不会失去焦点
【发布时间】:2020-08-09 04:22:33
【问题描述】:

我目前正在尝试使用 PyQt5 制作图形界面。到目前为止,一切都运行良好(毕竟我在这方面有一些经验),但是我已经为这个问题苦苦挣扎了几天,我在任何地方都找不到解决方案。

在我的应用程序中,我显示了来自 matplotlib 的 FigureCanvas(以及各种其他小部件),其中我有一个连接到函数的键事件,该函数从鼠标单击中选择一个点并将该点保存在 QTableWidget 中。但是,我希望用户能够编辑使用验证器获取的 y 值,因此我将第二列从持有 QTableWidgetItem 更改为 QLineEdit 小部件。一切正常,除了当我在表格中编辑 QLineEdit 小部件后按 Enter 键时,焦点没有按预期改变(我将焦点设置为返回画布,但单元格保持活动状态,光标闪烁)。

在同一个应用程序中,我在布局的其他地方有另一个 QLineEdit 小部件,它按预期工作。当我在此框中按 enter 时,连接到其 returnPressed 信号的函数将焦点发送回画布。

谁能帮我弄清楚这是怎么回事?

另外,当我在创建主框架时明确将焦点设置到画布时,我不明白为什么应用程序启动时焦点位于 QLineEdit 上。你知道如何解决这个问题吗?

我已将我的应用程序剥离为粘贴在下面的最小示例,并且行为保持不变。

总结一下:

  1. 我在画布上单击并按“a”,调用函数“add_point”。
  2. 然后我单击绘图中的一个点,该点在小部件中创建一个新行并将焦点设置到第二列。
  3. 我在这里输入我想要的任何浮点值,然后按 Enter。
  4. 然后调用函数“print_val”,但焦点没有按预期返回到画布。光标在表格单元格中一直闪烁。

  5. 当我编辑最左边的 QLineEdit(表格外)并按 Enter 键时,会调用函数 'func' 并将焦点正确地发送回画布。

为什么 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_()

【问题讨论】:

    标签: python pyqt5 qlineedit


    【解决方案1】:

    如果您想验证 QTableWidget 的信息,则无需插入 QLineEdit,而是使用委托创建的并在那里设置 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
    

    然后用视图的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_()
    

    【讨论】:

    • 太棒了!非常感谢。我最初正在寻找类似的东西,但找不到解决方案。但是,我仍然不明白为什么在我的示例中焦点没有按预期改变......为什么 QLineEdit 在这两种情况下的行为不同?
    猜你喜欢
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2016-10-22
    • 1970-01-01
    相关资源
    最近更新 更多