How to define the icon of a Dock in pyqtgraph? - icons

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

Related

Change highlight color for a specific item (QAction type) on a QMenuBar

I want to mimic the behavior of the window top-right corner actions when hovering over the minimize-maximize-close buttons.
So I have created a QMenuBar that contains 3 QActions.
class WindowMenuActions(QMenuBar):
def __init__(self):
super(WindowMenuActions, self).__init__()
minimize_action = QAction(self)
minimize_action.setIcon(_MINIMIZE_ICON)
maximize_action = QAction(self)
maximize_action.setIcon(_MAXIMIZE_ICON)
exit_action = QAction(self)
exit_action.setIcon(_CLOSE_ICON)
self.addAction(minimize_action)
self.addAction(maximize_action)
self.addAction(exit_action)
And set the background color when hovering with stylesheet (it is applied to the entire QApplication):
I want the close button to have a different highlight color, so I tried setting a boolean property on the exit_action to change the color only for that specific item, but it does not do any effect (in fact, if I add the property in the stylesheet it doesn't even consider the stylesheet values)
Any idea of how to achieve this?
To extend the question, I would not only use this for the minimize-maximize-close actions, but also to understand how to apply different hover/selected colors on QActions in the QMenuBar (not in the QMenu, which I already found a solution for that).
This is an running example:
from PySide2.QtWidgets import QMenuBar, QAction, QStyle, QApplication, QMainWindow
from PySide2.QtCore import Qt
class WindowMenuActions(QMenuBar):
def __init__(self):
super(WindowMenuActions, self).__init__()
minimize_action = QAction(self)
_MINIMIZE_ICON = self.style().standardIcon(QStyle.SP_TitleBarMinButton)
_MAXIMIZE_ICON = self.style().standardIcon(QStyle.SP_TitleBarMaxButton)
_EXIT_ICON = self.style().standardIcon(QStyle.SP_TitleBarCloseButton)
minimize_action.setIcon(_MINIMIZE_ICON)
minimize_action.setProperty('exit_action', False)
maximize_action = QAction(self)
maximize_action.setProperty('exit_action', False)
maximize_action.setIcon(_MAXIMIZE_ICON)
exit_action = QAction(self)
exit_action.setProperty('exit_action', True)
exit_action.setIcon(_EXIT_ICON)
self.addAction(minimize_action)
self.addAction(maximize_action)
self.addAction(exit_action)
self.setStyleSheet(
'QMenuBar::item:selected {'
'background-color: grey;'
'}'
'QMenuBar::item[exit_action=true]:selected {'
' background-color: red;'
'}')
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
main = QMainWindow()
main.setMenuBar(WindowMenuActions())
main.show()
sys.exit(app.exec_())
To anyone interested, I sorted by inheriting from a regular QWidget instead of a QMenuBar and using QToolButton instead of QAction.
Working example:
from PySide2.QtWidgets import QMenuBar, QStyle, QApplication, QMainWindow, QWidget, QHBoxLayout, QToolButton, QMenu
from PySide2.QtCore import Qt
class MenuBar(QMenuBar):
def __init__(self):
super(MenuBar, self).__init__()
self.addMenu(QMenu('File'))
self.addMenu(QMenu('Help'))
self.setCornerWidget(WindowMenuActions(self))
class WindowMenuActions(QWidget):
def __init__(self, parent=None):
super(WindowMenuActions, self).__init__(parent)
_MINIMIZE_ICON = self.style().standardIcon(QStyle.SP_TitleBarMinButton)
_MAXIMIZE_ICON = self.style().standardIcon(QStyle.SP_TitleBarMaxButton)
_EXIT_ICON = self.style().standardIcon(QStyle.SP_TitleBarCloseButton)
minimize = QToolButton(self)
minimize.setIcon(_MINIMIZE_ICON)
maximize = QToolButton(self)
maximize.setIcon(_MAXIMIZE_ICON)
exit_action = QToolButton(self)
exit_action.setProperty('exit_button', True)
exit_action.setIcon(_EXIT_ICON)
layout = QHBoxLayout()
layout.addWidget(minimize)
layout.addWidget(maximize)
layout.addWidget(exit_action)
self.setLayout(layout)
self.setStyleSheet(
'QToolButton:hover {'
' background: grey;'
'}'
'QToolButton[exit_button=true]:hover {'
' background: red;'
'}'
)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
main = QMainWindow()
main.setWindowFlags(Qt.FramelessWindowHint)
main.setMenuBar(MenuBar())
main.show()
sys.exit(app.exec_())

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())

How can I specify seperators using QDockWidget?

I have the following example code:
from PyQt5 import QtWidgets, QtCore, QtGui
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=parent)
self.bgcolor = self.palette().color(self.backgroundRole()).name()
self.central = QtWidgets.QTextEdit(self)
self.central.setText('this is the central widget')
self.setCentralWidget(self.central)
self.setDockOptions(self.AnimatedDocks) #prevent tabbing
self.rightDock = QtWidgets.QDockWidget('right dock', self)
self.rightDock.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
self.rightDock.setStyleSheet('QDockWidget::title{text-align:left;background:'+self.bgcolor+';}')
self.everywhereDock = QtWidgets.QDockWidget('everywhere dock',self)
self.everywhereDock.setAllowedAreas(QtCore.Qt.BottomDockWidgetArea | QtCore.Qt.TopDockWidgetArea | QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.everywhereDock.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable | QtWidgets.QDockWidget.DockWidgetMovable)
self.everywhereDock.setStyleSheet('QDockWidget::title{text-align:left;background:'+self.bgcolor+';}')
self.dockable = QtWidgets.QTextEdit(self.rightDock)
self.dockable.setText('this is dockable only on the right')
self.dockable2 = QtWidgets.QTextEdit(self.everywhereDock)
self.dockable2.setText('this is dockable everywhere, also its not closable')
self.rightDock.setWidget(self.dockable)
self.everywhereDock.setWidget(self.dockable2)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.rightDock)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.everywhereDock)
self.setTabPosition(QtCore.Qt.AllDockWidgetAreas, QtWidgets.QTabWidget.North)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
m = MainWindow()
m.show()
sys.exit(app.exec_())
The question is how to insert icons, where the borders between DockWidgetAreas are draggable, so that the user has a hint, that there is this functionality.
To clarify:
I want an icon between the black arrows:
The QDockWidget supports a "title widget" which is not a separator, but you can add it into every QDockWidget using QDockWidget::setTitleBarWidget(QWidget *widget).
So you can create a generic QWidget to hold this icon using a QHorizontalLayout or something, and put it into the title bar. The default mouse events handled by Qt (such as the drag events) should continue to works normally and you have a customizable title bar.
self.rightDock = QtWidgets.QDockWidget('right dock', self)
self.rightDock.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
// add custom title widget
self.rightDock.setTitleBarWidget(self.titleWidget)
// add widget to dock widget
self.rightDock.setWidget(self.dockable)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.rightDock)

Can't add widget from event call

I want to add a button during a event, but for some reason it doesn't work.
If i run this code, the TempFunc function will run during creation and a button will be created.
from PySide.QtGui import *
from PySide.QtCore import *
import sys
import math
class Example(QWidget):
def __init__(self, val):
super(Example,self).__init__()
self.scrollAreaConstraint = QLabel()
self.scrollAreaConstraint.setFixedSize(QSize(400,400))
self.scroll = QScrollArea()
self.scroll.setWidget(self.scrollAreaConstraint)
self.scroll.setWidgetResizable(True)
layout = QVBoxLayout(self)
layout.addWidget(self.scroll)
self.CountSlider = QSlider()
self.CountSlider.setOrientation(Qt.Orientation(1))
layout.addWidget(self.CountSlider)
self.TempFunc() #THIS WILL CREATE THE BUTTON!!
def TempFunc(self):
print "SLIDER PRESSED!!! NOW I WILL ADD A BUTTON"
QPushButton(self.scrollAreaConstraint)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Example(25)
window.setGeometry(500, 500, 500, 400)
window.show()
sys.exit(app.exec_())
However running this, pressing the slider will cause the same TempFunc function to run, but the button is not created.
from PySide.QtGui import *
from PySide.QtCore import *
import sys
import math
class Example(QWidget):
def __init__(self, val):
super(Example,self).__init__()
self.scrollAreaConstraint = QLabel()
self.scrollAreaConstraint.setFixedSize(QSize(400,400))
self.scroll = QScrollArea()
self.scroll.setWidget(self.scrollAreaConstraint)
self.scroll.setWidgetResizable(True)
layout = QVBoxLayout(self)
layout.addWidget(self.scroll)
self.CountSlider = QSlider()
self.CountSlider.setOrientation(Qt.Orientation(1))
layout.addWidget(self.CountSlider)
#self.TempFunc() #<----Disabled!!
self.CountSlider.sliderPressed.connect(self.TempFunc)
def TempFunc(self):
print "SLIDER PRESSED!!! NOW I WILL ADD A BUTTON"
QPushButton(self.scrollAreaConstraint)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Example(25)
window.setGeometry(500, 500, 500, 400)
window.show()
sys.exit(app.exec_())
Why is the button not created when not being called directly from the "init"?
The button is created, but then your code does nothing useful with it, which explains why it "doesn't work".
I'm guessing that, since you make scrollAreaConstraint the parent of these buttons, you are expecting them to appear inside the scroll-area. But scrollAreaConstraint is a QLabel, which cannot act as a container for other widgets.
So make scrollAreaConstraint a QWidget, give it a layout, and add the buttons to that layout:
self.scrollAreaConstraint = QWidget()
self.scrollAreaConstraint.setLayout(QVBoxLayout())
...
def TempFunc(self):
button = QPushButton(self.scrollAreaConstraint)
self.scrollAreaConstraint.layout().addWidget(button)
I eventually found that QT will set the .visible flag to false by default.
So just setting it to true makes the buttons visible in both cases.
Still not sure how and why it works when calling it from the init function as they are set to visible(false) aswell.

How to set background color to entire widget with stylesheet in PySide

I am trying to set a background color of a widget, but it only applies to widget's children. The code below is a simple representation of the real app structure. I'd like testWidget to be entirely red, which is 100x100 pixel rectangle due to it's size, but for some reason only the button is red.
from PySide import QtGui
class Widget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
mainLayout = QtGui.QVBoxLayout(self)
testWidget = QtGui.QWidget()
testWidget.setFixedSize(100,100)
testWidget.setStyleSheet('background-color: red;')
testLayout = QtGui.QVBoxLayout()
testWidget.setLayout(testLayout)
but = QtGui.QPushButton('TEST')
but.setFixedSize(20,20)
testLayout.addWidget(but)
mainLayout.addWidget(testWidget)
w = Widget()
w.show()
By default, a QWidget does not fill its background. You can either use a QFrame instead or setting the WA_StyledBackground attribute of the QWidget to True as said here : PySide: QWidget does not draw background color.
To apply the style sheet only to the container, and not to its children, the container widget can be named and the style sheet can specifically be applied to it by referring to its name.
Below is a MWE, derived from your code, that shows how it can be done using a QFrame instead of a QWidget :
from PySide import QtGui
import sys
class Widget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
mainLayout = QtGui.QVBoxLayout(self)
testWidget = QtGui.QFrame()
testWidget.setFixedSize(100,100)
testWidget.setObjectName("myWidget")
testWidget.setStyleSheet("#myWidget {background-color:red;}")
testLayout = QtGui.QVBoxLayout()
testWidget.setLayout(testLayout)
but = QtGui.QPushButton('TEST')
testLayout.addWidget(but)
mainLayout.addWidget(testWidget)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
instance_1 = Widget()
instance_1.show()
sys.exit(app.exec_())
which results in:

Resources