【问题标题】:Fill in QtableView's bottom space with empty rows用空行填充 QtableView 的底部空间
【发布时间】:2016-05-09 21:55:47
【问题描述】:

我有QTableView,我想通过添加空行来填充它的底部空间:

  • 如果QTableView中没有数据,最后这个必须填n 带有n = QTableView.height() / QTableView.rowHeight() 的空行
  • 如果有m 填充的行(QTableView 的底部有空白空间),我们必须将n 空行添加到QTableView,与n = (QTableView.height() / QTableView.rowHeight()) - m
  • 否则什么都不做

我真正的问题是,在调整 QTableView 的大小时,我们必须以 TableView 必须保持填充的方式添加/删除空行(而没有 ScrollBar

我正在寻找一种方法来更新 QTableView 项目的尺寸变化。

注意:

  • 当有ScrollBar时,不需要添加任何空行。
  • 我在计算空行数时确实计算了QHeader 的高度。
  • 您无法获取QTableView 的当前高度,因为QTableView.height() 不会返回确切的高度除非您在 QTableView 显示后调用它

我真的偶然发现了这个问题,我没有找到任何解决方案,我有一些想法但它们似乎并不实用。

更新:

到目前为止,我的代码已经取得了不错的进步,但仍然不是我想要的。

最大的问题是,在添加或删除行时,我不知道应该考虑什么方法。

这是我的问题的示例代码。

主类:

import sys
from math import floor

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QEvent
from PyQt4.QtGui import QTableView, QAbstractItemView

from modeltest import TestModel

DEFAULT_ROW_HEIGHT = 30


class App(QtGui.QApplication):
    """Main application class"""

    def __init__(self, sys_argv):
        """Constructor for App"""
        super(App, self).__init__(sys_argv)

        self.tableView = QTableView()
        self.tableView.resize(500, 400)
        self.tableView.setAttribute(QtCore.Qt.WA_DeleteOnClose)  # Fix QObject::startTimer error message.
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.setAlternatingRowColors(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.tableView.installEventFilter(self)

        self.model = TestModel()
        self.tableView.setModel(self.model)

        self.tableView.show()

    def eventFilter(self, source, event):
        if event.type() == QEvent.Resize and source is self.tableView:
            totalRowsNumber = (self.tableView.height() - 31) / DEFAULT_ROW_HEIGHT
            if totalRowsNumber > self.model.tasksCount():
                emptyRowsToAdd = totalRowsNumber - self.model.tasksCount()
            else:
                emptyRowsToAdd = 0

            self.model.emptyRowCount = floor(emptyRowsToAdd)

        return QtGui.QWidget.eventFilter(self, source, event)

if __name__ == '__main__':
    app = App(sys.argv)
    sys.exit(app.exec_())

模型类:

from PyQt4 import QtCore


class TestModel(QtCore.QAbstractTableModel):
    """The model associated with tasks table view"""

    def __init__(self, parent=None):
        """Constructor for TestModel"""
        super(TestModel, self).__init__(parent)
        self.__tasks = [['Task 1', 141546123, 80],
                        ['Task 2', 141546123, 80],
                        ['Task 3', 141546123, 80],
                        ['Task 4', 141546123, 80],
                        ['Task 5', 141546123, 80]]
        # self.__tasks = [[]]
        self.__header = ['Task', 'Timestamp', 'Status']
        self.__empty_row_count = 0

    @property
    def emptyRowCount(self):
        return self.__empty_row_count

    @emptyRowCount.setter
    def emptyRowCount(self, n):
        self.reset()    # reset model data.
        self.__empty_row_count = n

    def tasksCount(self):
        if len(self.__tasks) == 1 and self.__tasks[0] == []:
            return 0
        return len(self.__tasks)

    def rowCount(self, parent=None, *args, **kwargs):
        return self.tasksCount() + self.__empty_row_count

    def columnCount(self, parent=None, *args, **kwargs):
        return len(self.__header) + 1

    def flags(self, index):
        row = index.row()
        if row >= self.tasksCount():
            return QtCore.Qt.ItemIsEnabled

        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def data(self, index, role=QtCore.Qt.DisplayRole):
        row = index.row()
        column = index.column()
        if row < self.tasksCount() and column < len(self.__header):
            if role == QtCore.Qt.DisplayRole:
                return self.__tasks[row][column]

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            if orientation == QtCore.Qt.Horizontal:
                if section < len(self.__header):
                    return self.__header[section]

【问题讨论】:

  • 发布你目前的代码。

标签: python c++ qt pyqt


【解决方案1】:

嗯,在我看来,我找到了一个可以接受的答案,我希望它很好,但肯定有更好的答案。

不过,我确实使用了上面相同的代码以及一些核心更改。

注意:

  • 您可以通过按ReturnDelete 按钮来测试添加或删除行。

主类

import sys
from math import floor

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QEvent
from PyQt4.QtGui import QTableView, QAbstractItemView

from modeltest import TestModel

DEFAULT_ROW_HEIGHT = 30


class App(QtGui.QApplication):
    """Main application class"""

    def __init__(self, sys_argv):
        """Constructor for App"""
        super(App, self).__init__(sys_argv)

        self.tableView = QTableView()
        self.tableView.resize(500, 400)
        self.tableView.setAttribute(QtCore.Qt.WA_DeleteOnClose)  # Fix QObject::startTimer error message.
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.setAlternatingRowColors(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.tableView.installEventFilter(self)

        self.model = TestModel()
        self.tableView.setModel(self.model)

        self.tableView.show()

    def setScrollBarVisibility(self, emptyRowCount):
        if emptyRowCount > 0:
            self.tableView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        else:
            self.tableView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)

    def eventFilter(self, source, event):
        if event.type() == QEvent.Resize and source is self.tableView:
            totalRowNumber = (self.tableView.height()) / DEFAULT_ROW_HEIGHT
            self.model.updateRows(floor(totalRowNumber))
            self.setScrollBarVisibility(self.model.emptyRowCount())
        if event.type() == QEvent.KeyPress:
            if event.key() == QtCore.Qt.Key_Return:
                self.model.addRow()
                self.setScrollBarVisibility(self.model.emptyRowCount())
            elif event.key() == QtCore.Qt.Key_Delete:
                self.model.delRow()
                self.setScrollBarVisibility(self.model.emptyRowCount())

        return QtGui.QWidget.eventFilter(self, source, event)

if __name__ == '__main__':
    app = App(sys.argv)
    sys.exit(app.exec_())

模型类

from PyQt4 import QtCore


class TestModel(QtCore.QAbstractTableModel):
    """The model associated with tasks table view"""

    def __init__(self, parent=None):
        """Constructor for TestModel"""
        super(TestModel, self).__init__(parent)
        self.__tasks = [['Task 1', 141546123, 80],
                        ['Task 2', 141546123, 80],
                        ['Task 3', 141546123, 80],
                        ['Task 4', 141546123, 80],
                        ['Task 5', 141546123, 80]]
        # self.__tasks = [[]]
        self.__header = ['Task', 'Timestamp', 'Status']
        self.__empty_row_count = 0
        self.__total_row_count = 0  # Max visible rows.

    def updateRows(self, n):
        self.__total_row_count = n
        if n > self.tasksCount():  # If the view has an empty space.
            self.__empty_row_count = n - self.tasksCount()
        else:
            self.__empty_row_count = 0

        self.reset()  # Reset the view, results to call rowCount method.

    def emptyRowCount(self):
        return self.__empty_row_count

    def tasksCount(self):
        if len(self.__tasks) == 1 and self.__tasks[0] == []:
            return 0
        return len(self.__tasks)

    def rowCount(self, parent=None, *args, **kwargs):
        return self.tasksCount() + self.__empty_row_count
        # Data rows + empty rows.

    def columnCount(self, parent=None, *args, **kwargs):
        return len(self.__header) + 1
        # headers + the last stretched column

    def flags(self, index):
        row = index.row()
        if row >= self.tasksCount():  # If it's an empty row.
            return QtCore.Qt.ItemIsEnabled  # Non selectable.

        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def data(self, index, role=QtCore.Qt.DisplayRole):
        row = index.row()
        column = index.column()
        if row < self.tasksCount() and column < len(self.__header):
            if role == QtCore.Qt.DisplayRole:
                return self.__tasks[row][column]

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            if orientation == QtCore.Qt.Horizontal:
                if section < len(self.__header):
                    return self.__header[section]

    def addRow(self):

        success = self.__tasks.append(['Task x', 141546123, 80])
        if self.__empty_row_count > 0:
            self.__empty_row_count -= 1
        self.reset()  # Update the view.

        return success

    def delRow(self):
        if self.__tasks:
            self.__tasks = self.__tasks[:-1]
            if self.__empty_row_count == 0:  # If the visible view was full before the deleting.
                if self.__total_row_count - self.tasksCount() == 1:  # If the view didn't remain full.
                    self.__empty_row_count += 1
            else:
                self.__empty_row_count += 1
            self.reset()  # Update the view.
            return True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多