QTableView header 菜单位置
QTableView header menu position
我正在 Python3 下使用 PyQt5 开发 GUI。我正在尝试将菜单添加到相当宽的 QTableView 的 headers 列(比我的屏幕宽 => 这很好!)。
我的代码根据需要将这些菜单放置在它们各自的列 headers 中,作为初始列。但是,当我使用 QTableView 小部件底部的滚动条横向滚动时,菜单的位置是关闭的(基本上,Qt 将每个菜单放置在相应列不会滚动的位置)。
如何让 menu-position 知道 side-scrolling,以便菜单显示在所有列的正确位置?
这是一个有效的 mini-example(相关部分是 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()
编辑:
澄清一下:由于菜单实际上是 filter-menus,我宁愿不使用光标定位它们,而是将 menu-position 锚定到列,以提供 "dropdown"-类似于原始代码中的界面。
如果使用 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))
我正在 Python3 下使用 PyQt5 开发 GUI。我正在尝试将菜单添加到相当宽的 QTableView 的 headers 列(比我的屏幕宽 => 这很好!)。
我的代码根据需要将这些菜单放置在它们各自的列 headers 中,作为初始列。但是,当我使用 QTableView 小部件底部的滚动条横向滚动时,菜单的位置是关闭的(基本上,Qt 将每个菜单放置在相应列不会滚动的位置)。
如何让 menu-position 知道 side-scrolling,以便菜单显示在所有列的正确位置?
这是一个有效的 mini-example(相关部分是 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()
编辑:
澄清一下:由于菜单实际上是 filter-menus,我宁愿不使用光标定位它们,而是将 menu-position 锚定到列,以提供 "dropdown"-类似于原始代码中的界面。
如果使用 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))