【问题标题】:Tab over non-editable cells in QtableView选项卡在 QtableView 中的不可编辑单元格上
【发布时间】:2016-10-31 17:28:08
【问题描述】:

我正在使用 PYQT5。我有一个 QtableView 小部件,用于快速输入数据,类似于电子表格。有些列是可编辑的,而其他列(标签等)则不是。我通过继承 QItemDelegate 非常简单地实现了这一点。

我想要做的是当用户从可编辑单元格中选择标签时,它会跳过任何不可编辑的单元格并转到下一个可编辑的单元格。我想我需要在某处编辑后检查按键事件并确定下一列。或者,当我进入一个不可编辑的单元格时,我应该立即移动到下一个可编辑的单元格。我的代码是:

class Rates_sheet(QDialog, Ui_rates_sheet):
    """Displays rates for the next x days for quick changes"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        QDialog.__init__(self)
        self.ui = Ui_rates_sheet()
        self.ui.setupUi(self)
        self.ui.num_days.setValue(45)
        self.ui.get_avail.clicked.connect(self.make_rate_sheet)
        self.ui.publish_avail.clicked.connect(self.publish_rates)
        self.populate()

    def populate(self):
        self.rates_model = QSqlTableModel()
        self.rates_model.setTable("rates_sheet")
        self.rates_model.select()
        self.rates_view = self.ui.rates_grid
        self.rates_view.setModel(self.rates_model)
        self.rates_view.resizeColumnsToContents()
        self.rates_view.setSortingEnabled(True)
        self.rates_view.setColumnHidden(0, True)
        for x in range(7,12):
            self.rates_view.setColumnHidden(x, True)
        self.rates_view.horizontalHeader().moveSection(3,10)
        self.rates_view.horizontalHeader().moveSection(3,12)
        self.rates_view.horizontalHeader().moveSection(13,2)
        self.rates_view.setItemDelegate(Tmodel(self))
        self.rates_model.setHeaderData(1, Qt.Horizontal, "Date")
        self.rates_model.sort(1, Qt.AscendingOrder)



    def make_rate_sheet(self):
        pass

    def publish_rates(self):
        pass


class Tmodel(QItemDelegate):
    """Remplement rates_sheet table"""

    def __init__(self, parent=None):
        QItemDelegate.__init__(self)


    def createEditor(self, parent, option, index):
        if index.column() == 4:
            spinbox = QSpinBox(parent)
            spinbox.setRange(1,4)
            return spinbox
        elif index.column() in [5,6,11,12]:
            spinbox = QSpinBox(parent)
            spinbox.setRange(49,499)
            return spinbox

编辑:

我尝试重新实现 QSqlTableModel 以更改标志中的值,但最终出现运行时错误:

class MySqlTableModel(QSqlTableModel):
def __init__(self):
    QSqlTableModel.__init__(self)

def flags(self, index):
    if index.isValid():
        if index.column() == 4:
            flags ^= 1
            return flags

我得到的错误是:

    File "f:\Dropbox\pms\main-5.py", line 2658, in <module>
  sys.exit(app.exec_())

builtins.TypeError: invalid result from MySqlTableModel.flags(), NoneType cannot be converted to PyQt5.QtCore.ItemFlags in this context

现在我更加困惑了。

【问题讨论】:

  • 据我所知,您可以实现模型的 flags 方法并退出 ItemIsSelectable 选项,这也可能有助于在其上使用选项卡。见doc.qt.io/qt-5/qabstractitemmodel.html#flags
  • 我真的很困惑。我会认为一个项目是否可选择将是视图的工作。我正在努力重新实现 QSqlTableModel 并使其工作。能否提供更多 PYQT 的详细信息?
  • Qt 以不同的方式处理这种情况,请参阅doc.qt.io/qt-5.6/model-view-programming.html。关于 PyQt 我不适合你,对不起。但是阅读本文以及此处的一些示例doc.qt.io/qt-5.6/modelview.html 应该可以被 Python 采用。愿原力与你同在。

标签: python qt pyqt pyqt5


【解决方案1】:

经过几天的努力,答案是您可以成功地重新实现 QsqlTableModel。以下是我得出答案的方法。

首先我在网上看到的建议主要是在 C++ 的 QT 论坛上,你应该重新实现 QsqlQueryModel 而不是 QsqlTableModel。但是你必须为 setdata、data、rowcount、columncount、insertrows、deleterows 创建方法,更不用说你自己了。这看起来工作量很大,而且容易出错。我无法让它工作。

认为以上所有内容都毫无意义且工作量很大,我从stackoverflow 找到了一个代码 sn-p,其中有人试图使用来自 QsqlQueryModel 的 dataChanged 信号,并建议他们覆盖 QsqlTableModel。最后,我看到了一个如何精确地做我正在尝试的事情的例子。因此我更新了我的代码如下:

class Rates_sheet(QDialog, Ui_rates_sheet):
    """Displays rates for the next x days for quick changes"""

    def __init__(self):
        """Constructor"""
        QDialog.__init__(self)
        self.ui = Ui_rates_sheet()
        self.ui.setupUi(self)
        self.ui.num_days.setValue(45)
        self.ui.get_avail.clicked.connect(self.make_rate_sheet)
        self.ui.publish_avail.clicked.connect(self.publish_rates)
        self.populate()

    def populate(self):
        self.rates_model = MySqlTableModel()
        self.rates_model.setTable("rates_sheet")
        self.rates_model.select()
        self.rates_view = self.ui.rates_grid
        self.rates_view.setModel(self.rates_model)
        self.rates_view.resizeColumnsToContents()
        self.rates_view.setSortingEnabled(True)
        self.rates_view.setColumnHidden(0, True)
        self.rates_view.setItemDelegate(Tmodel(self))
        self.rates_model.setHeaderData(1, Qt.Horizontal, "Date")
        self.rates_model.sort(1, Qt.AscendingOrder)

    def make_rate_sheet(self):
        pass

    def publish_rates(self):
        pass

class MySqlTableModel(QSqlTableModel):
    """Overides QSqlTableModel to make columns not selectable"""

    def __init__(self):
        QSqlTableModel.__init__(self)

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            value = value.strip() if type(value) == str else value

        return super(MySqlTableModel, self).setData(index, value, role)

    def flags(self, index):
        flags = super(MySqlTableModel, self).flags(index)

        if index.column() in (4, 5, 6, 11):
            flags |= Qt.ItemIsEditable
        else:
            flags &= Qt.ItemIsSelectable
        return flags

这就是解决方案。我还在测试,但我还没有发现任何问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-08
    • 2012-01-18
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多