QTableView 标题菜单位置

Posted

技术标签:

【中文标题】QTableView 标题菜单位置【英文标题】:QTableView header menu position 【发布时间】:2018-03-22 14:21:40 【问题描述】:

我正在 Python3 下使用 PyQt5 开发一个 GUI。我正在尝试将菜单添加到相当宽的 QTableView 的列标题(比我的屏幕宽 => 这很好!)。

我的代码根据需要将这些菜单与它们各自的列标题一起放置在初始列中。但是,当我使用 QTableView 小部件底部的滚动条横向滚动时,菜单的位置是关闭的(基本上,Qt 将每个菜单放置在相应列不滚动的位置)。

如何让菜单位置知道横向滚动,以便所有列的菜单都显示在正确的位置?

这是一个工作小示例(相关部分是on_header_sectionClicked 方法)。

#!/usr/bin/python3
from PyQt5 import QtSql
from PyQt5.QtWidgets import (QMainWindow, QTableView, QApplication, 
                             QAbstractItemView, QHeaderView, QMenu,
                             QAction)
from PyQt5.QtCore import QPoint
import sys

class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(300, 150)

        self.createConnection()
        self.fillTable()
        self.createModel()
        self.initUI()

    def createConnection(self):
        self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        self.db.setDatabaseName("test.db")
        if not self.db.open():
            print("Cannot establish a database connection")
            return False

    def fillTable(self):
        self.db.transaction()
        q = QtSql.QSqlQuery()
        q.exec_("DROP TABLE IF EXISTS Cars;")
        q.exec_("""CREATE TABLE Cars (Company TEXT, Model TEXT, Year_bought INT, Month_bought INT, Day_bought INT, 
        Owner_surname Text, Owner_firstname, Color TEXT)""") 
        q.exec_("INSERT INTO Cars VALUES ('Honda', 'Civic', 2009, 2, 12,'Meyers', 'Peter', 'sunflower-yellow')") 
        q.exec_("INSERT INTO Cars VALUES ('Volkswagen', 'Beetle Cabriolet', 2013, 10, 30, 'Heffernon', 'Jeremiah', 'skyblue')")
        self.db.commit()

    def createModel(self):
        self.model = QtSql.QSqlQueryModel()
        q = QtSql.QSqlQuery()
        query = "select * from cars"
        q.exec_(query)
        self.model.setQuery(q)

    def initUI(self):
        self.view = QTableView()
        self.view.setModel(self.model)
        self.header = self.view.horizontalHeader()
        self.header.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.header.sectionClicked.connect(self.on_header_sectionClicked)
        mode = QAbstractItemView.SingleSelection
        self.view.setSelectionMode(mode)
        self.setCentralWidget(self.view) 

    def on_header_sectionClicked(self, index):
        self.col_index = index
        menu = QMenu(self)
        action1 = QAction("Filter me", self)
        action1.triggered.connect(self.on_menu_clicked)  
        menu.addAction(action1)

        #FIXME: position the menu correctly
        headerPos = self.view.mapToGlobal(self.header.pos())        
        posY = headerPos.y() + self.header.height()
        posX = headerPos.x() + self.header.sectionPosition(self.col_index)
        menu.exec_(QPoint(posX, posY))

    def on_menu_clicked(self):
        print("Filtering column !".format(self.col_index))

    def closeEvent(self, e):
        if (self.db.open()):
            self.db.close()


def main():
    app = QApplication([])
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

编辑

澄清一下:由于菜单实际上是过滤器菜单,我宁愿不使用光标定位它们,而是将菜单位置锚定到列,以提供类似于原始“下拉”的界面代码。

【问题讨论】:

【参考方案1】:

如果使用sectionViewportPosition,您的示例可以正常工作:

def on_header_sectionClicked(self, index):
    ...
    #FIXME: position the menu correctly
    headerPos = self.view.mapToGlobal(self.header.pos())        
    posY = headerPos.y() + self.header.height()
    posX = headerPos.x() + self.header.sectionViewportPosition(self.col_index)        
    menu.exec_(QPoint(posX, posY))

【讨论】:

以上是关于QTableView 标题菜单位置的主要内容,如果未能解决你的问题,请参考以下文章

在 Qt 中为 QTableView 创建弹出菜单

通过上下文菜单为 PyQt 中的 QTableView 和 QTableWidget 传递一个实例

24.QTableView函数使用,右击菜单实现

Qt4:未捕获 QTableView 鼠标按钮事件

QTableView中左键和右键的区别

将分隔符添加到 QTableView 的操作?