c00*_*ter 7 python contextmenu header pyqt qtableview
下面的示例代码(受此处影响很大)有一个右键单击上下文菜单,当用户单击表格中的单元格时,该菜单将显示.是否可以在表格的标题中右键单击右键单击上下文菜单?如果是这样,我如何更改代码以包含此内容?
import re
import operator
import os
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
def main():
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.tabledata = [('apple', 'red', 'small'),
('apple', 'red', 'medium'),
('apple', 'green', 'small'),
('banana', 'yellow', 'large')]
self.header = ['fruit', 'color', 'size']
# create table
self.createTable()
# layout
layout = QVBoxLayout()
layout.addWidget(self.tv)
self.setLayout(layout)
def popup(self, pos):
for i in self.tv.selectionModel().selection().indexes():
print i.row(), i.column()
menu = QMenu()
quitAction = menu.addAction("Quit")
action = menu.exec_(self.mapToGlobal(pos))
if action == quitAction:
qApp.quit()
def createTable(self):
# create the view
self.tv = QTableView()
self.tv.setStyleSheet("gridline-color: rgb(191, 191, 191)")
self.tv.setContextMenuPolicy(Qt.CustomContextMenu)
self.tv.customContextMenuRequested.connect(self.popup)
# set the table model
tm = MyTableModel(self.tabledata, self.header, self)
self.tv.setModel(tm)
# set the minimum size
self.tv.setMinimumSize(400, 300)
# hide grid
self.tv.setShowGrid(True)
# set the font
font = QFont("Calibri (Body)", 12)
self.tv.setFont(font)
# hide vertical header
vh = self.tv.verticalHeader()
vh.setVisible(False)
# set horizontal header properties
hh = self.tv.horizontalHeader()
hh.setStretchLastSection(True)
# set column width to fit contents
self.tv.resizeColumnsToContents()
# set row height
nrows = len(self.tabledata)
for row in xrange(nrows):
self.tv.setRowHeight(row, 18)
# enable sorting
self.tv.setSortingEnabled(True)
return self.tv
class MyTableModel(QAbstractTableModel):
def __init__(self, datain, headerdata, parent=None, *args):
""" datain: a list of lists
headerdata: a list of strings
"""
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = datain
self.headerdata = headerdata
def rowCount(self, parent):
return len(self.arraydata)
def columnCount(self, parent):
return len(self.arraydata[0])
def data(self, index, role):
if not index.isValid():
return QVariant()
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.arraydata[index.row()][index.column()])
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return QVariant(self.headerdata[col])
return QVariant()
def sort(self, Ncol, order):
"""Sort table by given column number.
"""
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.arraydata = sorted(self.arraydata, key=operator.itemgetter(Ncol))
if order == Qt.DescendingOrder:
self.arraydata.reverse()
self.emit(SIGNAL("layoutChanged()"))
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
c00*_*ter 11
结果比我想象的要简单.与我为QTableView小部件本身添加弹出菜单的方式相同,我可以从表对象中获取标题,然后以与常规上下文菜单相同的方式附加上下文菜单.
headers = self.tv.horizontalHeader()
headers.setContextMenuPolicy(Qt.CustomContextMenu)
headers.customContextMenuRequested.connect(self.header_popup)
Run Code Online (Sandbox Code Playgroud)
如果您采取步骤并继承视图而不是简单地组合它,那么还有另一种可能更强大的方法来做到这一点。自定义上下文菜单在这里工作吗?是的,但是为什么除了视图之外的任何东西都需要知道呢?它还将有助于更好地塑造您的代码以正确处理其他问题。目前该实现不提供任何封装、内聚或支持职责分离。最后你会得到一个大的斑点,这是好的设计的对立面。我提到这一点是因为您似乎将所有 GUI 逻辑都放在这个不断增长的主函数中,这也是您最终将排序实现放在模型中的原因,这对我来说毫无意义。(如果你有模型的两个视图,你强制它们以相同的方式排序怎么办)
它是更多的代码吗?是的,但它给了你更多的力量,我认为值得一提。下面我将演示如何处理标题以及您想要的任何给定单元格。还要注意,在我的实现中,如果存在一些 OTHER 小部件,它也定义了一个上下文菜单事件处理程序,它可能有机会在我之后处理事件;这样如果其他人只为某些情况添加处理程序,他们就可以这样做而不会使我的代码复杂化。这样做的一部分是标记您是否处理了事件。
我的漫无边际和想法已经足够了,代码如下:
#Alteration : instead of self.tv = QTableView...
self.tv = MyTableView()
....
# somewhere in your TableView object's __init__ method
# yeah IMHO you should be inheriting and thus extending TableView
class MyTableView(QTableView):
def __init__(self, parent = None):
super(MyTableView, self).__init__()
self.setContextMenuPolicy(Qt.DefaultContextMenu)
## uniform one for the horizontal headers.
self.horizontalHeader().setContextMenuPolicy(Qt.ActionsContextMenu)
''' Build a header action list once instead of every time they click it'''
doSomething = QAction("&DoSomething", self.verticalHeader(),
statusTip = "Do something uniformly for headerss",
triggered = SOME_FUNCTION
self.verticalHeader().addAction(doSomething)
...
return
def contextMenuEvent(self, event)
''' The super function that can handle each cell as you want it'''
handled = False
index = self.indexAt(event.pos())
menu = QMenu()
#an action for everyone
every = QAction("I'm for everyone", menu, triggered = FOO)
if index.column() == N: #treat the Nth column special row...
action_1 = QAction("Something Awesome", menu,
triggered = SOME_FUNCTION_TO_CALL )
action_2 = QAction("Something Else Awesome", menu,
triggered = SOME_OTHER_FUNCTION )
menu.addActions([action_1, action_2])
handled = True
pass
elif index.column() == SOME_OTHER_SPECIAL_COLUMN:
action_1 = QAction("Uh Oh", menu, triggered = YET_ANOTHER_FUNCTION)
menu.addActions([action_1])
handled = True
pass
if handled:
menu.addAction(every)
menu.exec_(event.globalPos())
event.accept() #TELL QT IVE HANDLED THIS THING
pass
else:
event.ignore() #GIVE SOMEONE ELSE A CHANCE TO HANDLE IT
pass
return
pass #end of class
Run Code Online (Sandbox Code Playgroud)