为了账号安全,请及时绑定邮箱和手机立即绑定

使用 QTableView 和 QSelectionModel 选择日历样式

使用 QTableView 和 QSelectionModel 选择日历样式

慕尼黑8549860 2023-01-04 11:29:57
我正在使用 QTableView 构建自定义日历视图,并希望有一个 QItemSelectionModel 可以按天和周连续选择单元格。不确定从哪里开始,因为选择模型不与视图交互。视图的 onCurrentChange 方法提供当前索引,在 selectionModel 中不起作用。视图通常连接到更复杂的日历模型;这里的表格模型是为了说明。from PyQt5.QtCore import QModelIndex, QDatefrom PyQt5.QtCore import Qt, QAbstractTableModel, QItemSelectionModelfrom PyQt5.QtWidgets import QTableViewimport typingclass 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 7class 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_())
查看完整描述

1 回答

?
Qyouu

TA贡献1786条经验 获得超11个赞

这是日历样式选择的解决方案。在表格上设置 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_())




查看完整回答
反对 回复 2023-01-04
  • 1 回答
  • 0 关注
  • 111 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信