#pyqt #contextmenu #alignment
#pyqt ( пикт ) #контекстное меню #выравнивание #pyqt #contextmenu
Вопрос:
В приведенном ниже примере кода (на который сильно повлияло здесь) контекстное меню, вызываемое правой кнопкой мыши, на самом деле не выровнено должным образом.
Как видно на скриншоте, результирующее меню находится совсем немного выше курсора мыши. Я бы ожидал, что верхний левый угол меню будет точно выровнен с указателем мыши.
Есть ли какой-нибудь способ приспособиться к этому?
import re
import operator
import os
import sys
import sqlite3
import cookies
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()
Ответ №1:
позиция находится в координатах окна просмотра, поэтому, если вы используете
self.tableView.setContextMenuPolicy(Qt.CustomContextMenu)
чтобы вы не event
перешли к popup
, вы можете сделать следующее
action = menu.exec_(self.tableView.viewport().mapToGlobal(pos))
вместо этого.
Комментарии:
1. После нескольких часов поиска это работает для PyQt5
Ответ №2:
Это было немного сложно, но следуя примеру создания подклассов в этом примере вики и заменяя
15 action = menu.exec_(self.mapToGlobal(event.pos()))
с помощью
15 action = menu.exec_(event.globalPos())
верхний левый угол всплывающего меню будет точно соответствовать щелчку мыши.
Ответ №3:
Это будет работать для развернутых / уменьшенных окон. Меню будет сгенерировано в правом нижнем положении мыши.
menu.exec_(self.mapToGlobal(self.mapFromGlobal(QtGui.QCursor.pos())))