【问题标题】:Calendar Style Selection With QTableView and QSelectionModel使用 QTableView 和 QSelectionModel 选择日历样式
【发布时间】:2020-09-29 03:04:31
【问题描述】:

我正在使用 QTableView 构建一个自定义日历视图,并希望有一个 QItemSelectionModel 可以按天和周连续选择单元格。不确定从哪里开始,因为选择模型不与视图交互。视图的 onCurrentChange 方法给出了当前索引,在 selectionModel 中不起作用。

视图通常连接到更复杂的日历模型;这里的表格模型是为了说明。

from PyQt5.QtCore import QModelIndex, QDate
from PyQt5.QtCore import Qt, QAbstractTableModel, QItemSelectionModel

from PyQt5.QtWidgets import QTableView
import typing


class TableModel(QAbstractTableModel):
    def __init__(self):
        super(TableModel, self).__init__()

    def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return QDate.longDayName(section + 1)

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return index.row() * 7 + index.column() + 1

    def rowCount(self, index):
        return 6

    def columnCount(self, index):
        return 7


class CalendarSelectionModel(QItemSelectionModel):

    def __init__(self, *args, **kwargs):
        super(CalendarSelectionModel, self).__init__(*args, *kwargs)

    def currentChanged(self, current: QModelIndex, previous: QModelIndex) -> None:
        print(current, previous)


class CalendarView(QTableView):

    def __init__(self):
        super(CalendarView, self).__init__()

    # def currentChanged(self, current: QModelIndex, previous: QModelIndex) -> None:
    #     print(current)


if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication, QTableView

    app = QApplication(sys.argv)

    model = TableModel()

    cal = CalendarView()
    cal.setModel(model)
    sel = CalendarSelectionModel(model)
    cal.setSelectionModel(sel)
    cal.show()

    cal.resize(860, 640)

    sys.exit(app.exec_())

【问题讨论】:

标签: python pyqt pyqt5 qtableview


【解决方案1】:

这是日历样式选择的解决方案。在table上设置QAbstractItemView.NoSelection,把选择逻辑放在currentChanged里面就是办法。

import typing

from PyQt5.QtCore import QDate
from PyQt5.QtCore import Qt, QAbstractTableModel, QItemSelectionModel, QItemSelection, QModelIndex
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QTableView, QAbstractItemView


class TableModel(QAbstractTableModel):
    def __init__(self):
        super(TableModel, self).__init__()

    def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return QDate.longDayName(section + 1)

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return index.row() * 7 + index.column() + 1

    def rowCount(self, index):
        return 6

    def columnCount(self, index):
        return 7


class CalendarView(QTableView):

    def __init__(self):
        super(CalendarView, self).__init__()
        self.setSelectionMode(QAbstractItemView.NoSelection)
        self._start: typing.Union[QModelIndex, None] = None

    def mousePressEvent(self, e: QMouseEvent) -> None:
        self._start = self.indexAt(e.pos())
        self.clearSelection()
        self.selectionModel().select(self._start, QItemSelectionModel.Select)
        super(CalendarView, self).mousePressEvent(e)

    def index(self, row, col):
        return self.model().index(row, col)

    def currentChanged(self, current: QModelIndex, previous: QModelIndex) -> None:
        if self.state() == QAbstractItemView.DragSelectingState:
            self.clearSelection()
            if current.row() == self._start.row():  # we only have one row, select from start to current
                selection = QItemSelection(self._start, self.model().index(self._start.row(), current.column()))
            else:  # more than one row selected make the other 2 selections
                selection = QItemSelection(self._start, current)
                if current.row() < self._start.row():  # stencil out diagonal
                    right = QItemSelection(current, self.index(self._start.row() - 1, 6))
                    left = QItemSelection(self.index(current.row() + 1, 0), self._start)
                    selection.merge(right, QItemSelectionModel.Select)
                    selection.merge(left, QItemSelectionModel.Select)
                    if current.column() > self._start.column():
                        stencil = QItemSelection(self.index(current.row(), current.column() - 1),
                                                 self.index(current.row(), 0))
                        stencil2 = QItemSelection(self.index(self._start.row(), self._start.column() + 1),
                                                  self.index(self._start.row(), 6))
                        selection.merge(stencil, QItemSelectionModel.Deselect)
                        selection.merge(stencil2, QItemSelectionModel.Deselect)
                else:
                    right = QItemSelection(self._start, self.index(current.row() - 1, 6))
                    left = QItemSelection(self.index(self._start.row() + 1, 0), current)
                    selection.merge(right, QItemSelectionModel.Select)
                    selection.merge(left, QItemSelectionModel.Select)
                    if current.column() < self._start.column():  # stencil out diagonal
                        stencil = QItemSelection(self.index(self._start.row(), self._start.column() - 1),
                                                 self.index(self._start.row(), 0))
                        stencil2 = QItemSelection(self.index(current.row(), current.column() + 1),
                                                  self.index(current.row(), 6))
                        selection.merge(stencil, QItemSelectionModel.Deselect)
                        selection.merge(stencil2, QItemSelectionModel.Deselect)
            self.selectionModel().select(selection, QItemSelectionModel.Select)


if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication, QTableView

    app = QApplication(sys.argv)

    model = TableModel()

    cal = CalendarView()
    cal.setModel(model)
    cal.show()

    cal.resize(860, 640)

    sys.exit(app.exec_())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 2019-02-05
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多