How to get different context menu from qgraphicsitem inside a qgraphicsview? - qt

I have a qgraphicsview it contains a scene and inside it there are some graphicsitem.
I have enabled the context menu in qgraphicsview by setcontextmenupolicy(qt::actionscontextmenu), but now my qgraphicsitem cannot receive any qgraphicsscenecontextmenuevent event. Thus only the context menu of qgraphicsview appear.
How could I solve this?

in the code below I've created my own scene class, in inheriting from QGraphicsScene
Then re-implementing the contextMenuEvent I first check if there is an item at the event position, i.e. if I'm right clicking on an item in the scene.
If so, ill instead try to run any contextMenuEvent on that item.
If there is no item, or if it doesn't have its own contextMenuEvent ill just run the scene's version of the context event.
import PySide.QtGui as QtGui
import PySide.QtCore as QtCore
import PySide.QtGui as QtGui
import PySide.QtCore as QtCore
class MyScene(QtGui.QGraphicsScene):
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
def contextMenuEvent(self, event):
# Check it item exists on event position
item = self.itemAt(event.scenePos().toPoint())
if item:
# Try run items context if it has one
try:
item.contextMenuEvent(event)
return
except:
pass
menu = QtGui.QMenu()
action = menu.addAction('ACTION')

Related

How to disable and re-enable QPushButton

I made MainWindow and Dialog with Qt-designer.The MainWindow and Dialog have one QPushButton. Clicking a button in the MainWindow disables the button and opens a Dialog Window. When you click the Dialog button, the Dialog window closes and the MainWindow's button is activated again.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5 import uic
form_mainwindow = uic.loadUiType("dialog_mainWindow.ui")[0]
form_dialog = uic.loadUiType("Dialog__.ui")[0]
class dialog(QDialog, form_dialog) :
def __init__(self):
super(dialog, self).__init__()
self.setupUi(self)
self.closeBtn.clicked.connect(self.close)
self.closeBtn.clicked.connect(self.closeFN)
def closeFN(self):
main = mainwindow()
main.pushButton.setEnabled(True)
class mainwindow(QtWidgets.QMainWindow, form_mainwindow) :
def __init__(self):
super(mainwindow, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.dia)
def dia(self,checked):
d = dialog()
self.pushButton.setEnabled(False)
d.show()
d.exec_()
if __name__ == "__main__" :
app = QtWidgets.QApplication(sys.argv)
Window = mainwindow()
Window.show()
sys.exit(app.exec_())
This is my code. However, my code is that when the Dialog window is closed, the button in the MainWindow is not activated again. Why??
You are calling mainwindow() in your dialogs closeFN method, which creates a new mainwindow widget. So the button that you are setting to be enabled is not the same one that you used to create the dialog in the first place. You are setting a button on a new window that isn't visible yet because you never call .show() or similar method that makes top level windows visible, and you also are not keeping a reference to the new window so it would be garbage collected anyway.
A solution to this is to have your mainwindow connect to the dialogs closebtn.clicked signal which could then trigger it's own method that set's the pushbutton to be enabled.
For example:
...
class dialog(QDialog) :
def __init__(self):
super(dialog, self).__init__()
...
# self.closeFN is no longer necessary
self.closeBtn.clicked.connect(self.close)
class mainwindow(QtWidgets.QMainWindow):
def __init__(self):
super(mainwindow, self).__init__()
...
self.pushButton.clicked.connect(self.dia)
def dia(self):
d = dialog()
self.pushButton.setEnabled(False)
# connect to closeBtn signal to enable the pushButton
d.closeBtn.clicked.connect(lambda: self.pushButton.setEnabled(True))
d.exec_()
...

How to define the icon of a Dock in pyqtgraph?

In pyqtgraph, Docks can be torn out of the DockArea by dragging or double clicking. The popups use a default icon. I would like to define my own icon. In the code below I set the application window. The same code has no effect on the dock, though there is no error message.
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout
from pyqtgraph.dockarea import Dock, DockArea
from PyQt5.QtGui import QIcon
class Foo(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowIcon(QIcon('direction'))
lay = QVBoxLayout(self)
da = DockArea()
d = Dock("Dock")
d.setWindowIcon(QIcon('direction')) # no effect
da.addDock(d)
lay.addWidget(da)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = Foo()
w.show()
sys.exit(app.exec_())
I looked in the source code of Dock and DockArea of pyqtgraph and found out I had to overwrite floatDock function.
I created a function
def floatDockPatched(self, dock):
"""Removes *dock* from this DockArea and places it in a new window."""
area = self.addTempArea()
area.win.resize(dock.size())
area.win.setWindowIcon(QIcon("res/haip.png"))
area.win.setWindowTitle(dock.label.text())
area.moveDock(dock, 'top', None)
and assigned it to the class as overwrite
DockArea.floatDock = floatDockPatched

Set editor width in QTreeWidget to fill cell

By default if a cell is edited in a QTreeWidget, the editor changes its width based on length of text.
Is it possible to set the editorĀ“s width to fill the cell?
Here is the code to reproduce the screenshot:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Example(QTreeWidget):
def __init__(self):
super().__init__()
self.resize(600, 400)
self.setHeaderLabels(['Col1', 'Col2', 'Col3', 'Col4'])
self.setRootIsDecorated(False)
self.setAlternatingRowColors(True)
self.setSelectionBehavior(QAbstractItemView.SelectItems)
# self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setStyleSheet('QTreeView { show-decoration-selected: 1;}')
for i in range(5):
item = QTreeWidgetItem(['hello', 'bello'])
item.setFlags(item.flags() | Qt.ItemIsEditable)
self.addTopLevelItem(item)
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You can create a simple QStyledItemDelegate and override its updateEditorGeometry() in order to always resize it to the index rectangle:
class FullSizedDelegate(QStyledItemDelegate):
def updateEditorGeometry(self, editor, opt, index):
editor.setGeometry(opt.rect)
class Example(QTreeWidget):
def __init__(self):
# ...
self.setItemDelegate(FullSizedDelegate(self))
** UPDATE **
The default text editor for all item views is an auto expanding QLineEdit, which tries to expand itself to the maximum available width (the right edge of the viewport) if the text is longer than the visual rectangle of the item. In order to avoid this behavior and always use the item rect, you have to return a standard QLineEdit. In this case the updateGeometry override is usually not necessary anymore (but I'd keep it anyway, as some styles might still prevent that):
class FullSizedDelegate(QStyledItemDelegate):
def createEditor(self, parent, opt, index):
if index.data() is None or isinstance(index.data(), str):
return QLineEdit(parent)
return super().createEditor(parent, opt, index)

How to keep the shortcuts of a hidden widget in PyQt5?

I have a menu bar with a shortcut associated to it. I want to hide the menu bar but in that case the associated shortcut will be disabled. Here is an example:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.InitWindow()
def InitWindow(self):
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu("&File")
mainMenu.hide() # comment it and the shortcut 'q' will work
quitItem = QAction("Quit", self)
quitItem.setShortcut("Q")
quitItem.triggered.connect(self.close)
fileMenu.addAction(quitItem)
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
If you put the line mainMenu.hide() in a comment, i.e. if the menu bar is shown, then the app. will quit with the shortcut 'q'. How could I keep the shortcuts of a hidden widget?
In the app. I want to add full-screen support, and in that case I want to hide the menu bar, but also, I want to keep the shortcuts in full-screen mode.
I found a working solution. The idea is the following: the main window has a shortcut ('q' in the example), and the menu bar also has this shortcut. To avoid conflict, disable the window's shortcut if the menu bar is present. If the menu bar is hidden, enable the window's shortcut.
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QShortcut
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.shortcutQuit = QShortcut(QKeySequence("q"), self)
self.shortcutQuit.activated.connect(self.close)
self.shortcutQuit.setEnabled(False) # disable it if the menu bar is visible
self.InitWindow()
def InitWindow(self):
self.mainMenu = self.menuBar()
fileMenu = self.mainMenu.addMenu("&File")
hideItem = QAction("Hide Menu Bar", self)
hideItem.setShortcut("h")
hideItem.triggered.connect(self.my_hide)
quitItem = QAction("Quit", self)
quitItem.setShortcut("Q")
quitItem.triggered.connect(self.close)
fileMenu.addAction(hideItem)
fileMenu.addAction(quitItem)
def my_hide(self):
self.mainMenu.hide()
self.shortcutQuit.setEnabled(True)
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())

python qt : automatically resizing main window to fit content

I have a main window which contains a main widget, to which a vertical layout is set. To the layout is added a QTableWidget only (for the moment).
When I start the application and call show on the main_window, only part of the QTableWidget is shown. I can extend the window manually to see it all, but I would like the window to have its size nicely adapted to the size of the QTableWidget.
Googling the question found a lot of posts on how to use resize to an arbitrary size, and call to resize(int) works fine, but this is not quite what I am asking
Lots of other posts are not explicit enough, e.g "use sizePolicy" or "use frameGeometry" or "use geometry" or "use sizeHint". I am sure all of them may be right, but an example on how to would be awesome.
You can do something like this, from within your MainWindow after placing all the elements you need in the layout:
self.setFixedSize(self.layout.sizeHint())
This will set the size of the MainWindow to the size of the layout, which is calculated using the size of widgets that are arranged in the layout.
I think overriding sizeHint() on the QTableWidget is the key:
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget
class Table(QTableWidget):
def sizeHint(self):
horizontal = self.horizontalHeader()
vertical = self.verticalHeader()
frame = self.frameWidth() * 2
return QSize(horizontal.length() + vertical.width() + frame,
vertical.length() + horizontal.height() + frame)
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
top = Table(3, 5, self)
self.setCentralWidget(top)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
You can use sizeHint() but not as stated in the other answers. sizeHint() returns a QSize object with a width and height. Let's say you have a main window mainWindow and a widget inside it called content. If your resizing involves content height to get bigger, you can fit the mainWindow to it like this:
mainWindow.resize(mainWindow.sizeHint().width,
mainWindow.size().height() + content.sizeHint().height());
Old but i experienced this a while back and seeing how the answers here didn't exactly work for me.
Here's what i did:
Please make sure you have the central widget for the 'mainwindow' set properly and the parent of the layout is the central widget,
Then set a sizepolicy for the mainwindow/widget as you wish.
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class RandomWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(RandomWidget, self).__init__(parent)
self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
self.ui()
self.layout.addWidget(self.table)
self.layout.addWidget(self.table2)
def ui(self):
self.table = QtWidgets.QTableWidget()
self.table.setMinimumSize(800,200)
self.table2 = QtWidgets.QTableWidget()
class Mainwindow(QtWidgets.QMainWindow):
def __init__(self):
self.widget = None
super(Mainwindow, self).__init__()
self.setWindowTitle('test')
def ui(self):
self.setCentralWidget(self.widget)
self.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
Window = Mainwindow()
Window.widget = RandomWidget(Window)
Window.ui()
sys.exit(app.exec_())

Resources