How can I make PyQt QSplitter visible? - pyqt

Can I define the width/height for a QSplitter object? Can I make it visible with a proper arrow?

In my C++ code, I use QSplitter::setHandleWidth()
Adjusting the height would probably require adjusting the height of the container itself.

Here's how you can overwrite the QSplitter class to make the splitters to have some icon to let user know they can resize the widgets, See the image for output.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Handle(QWidget):
def paintEvent(self, e=None):
painter = QPainter(self)
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.Dense6Pattern)
painter.drawRect(self.rect())
class customSplitter(QSplitter):
def addWidget(self, wdg):
super().addWidget(wdg)
self.width = self.handleWidth()
l_handle = Handle()
l_handle.setMaximumSize(self.width*2, self.width*10)
layout = QHBoxLayout(self.handle(self.count()-1))
layout.setSpacing(0)
layout.setContentsMargins(0,0,0,0)
layout.addWidget(l_handle)
class Window(QMainWindow):
def setUI(self, MainWindow):
self.splt_v = customSplitter(Qt.Vertical)
self.splt_v.setHandleWidth(8)
self.splt_v.addWidget(QGroupBox("Box 1"))
self.splt_v.addWidget(QGroupBox("Box 2"))
self.splt_v.addWidget(QGroupBox("Box 3"))
self.wdg = QWidget()
self.v_lt = QVBoxLayout(self.wdg)
self.v_lt.addWidget(self.splt_v)
self.spl_h = customSplitter()
self.spl_h.addWidget(self.wdg)
self.spl_h.addWidget(QGroupBox("Box 4"))
self.spl_h.addWidget(QGroupBox("Box 5"))
self.h_lt = QHBoxLayout()
self.h_lt.addWidget(self.spl_h)
self.w = QWidget()
self.w.setLayout(self.h_lt)
self.w.setGeometry(0,0,1280,720)
self.w.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
MainWindow = QMainWindow()
ui = Window()
ui.setUI(MainWindow)
sys.exit(app.exec_())

Related

Resizing QDialog after removing QWidget

Is there any way by which I can resize a QDialog after removing a QWidget from its layout?
I'm still a beginner so bear with me if the code looks a bit silly.
The main dialog geometry is stored during the resizeEvent()
Before creating the widget:
https://imgur.com/a/vFORp4t
When the widget is created:
https://imgur.com/z7KUa3I
When the widget is removed:
https://imgur.com/KdzULUe
def resizeEvent(self, event):
QtWidgets.QMainWindow.resizeEvent(self, event)
window = self.window()
self.dialog_rect = window.geometry()
self.DialogSizeChanged.emit() # pylint: disable=E1101
Here's the "create widget" code:
def create_info_widget(self):
px = self.dialog_rect.x()
py = self.dialog_rect.y()
w = self.dialog_rect.width()
h = self.dialog_rect.height()
self.dialog_stored_rect = self.dialog_rect
self.info_wdg = abw.ThumbnailInfo("Asset Info")
self.asset_wdg_layout.addWidget(self.info_wdg)
data = self.list_wdg.get_list_thumbnails_data()
path = data['thumbnail']
self.info_wdg.set_info_thumbnail(path)
wdg_h = self.info_wdg.height()
self.setGeometry(px, py, w, h + wdg_h)
self.updateGeometry()
And the "remove widget" code:
def remove_info_widget(self):
wdg = self.findChild(QtWidgets.QFrame, "Asset Info")
if wdg:
self.asset_wdg_layout.removeWidget(wdg)
wdg.deleteLater()
self.info_wdg = None
self.setGeometry(self.dialog_stored_rect)
self.updateGeometry()
As shown on grabbed images, when the widget is removed, it doesn't get back to its size before it was created.
Thank you,
Jacques.
We will first resize it and then use adjustSize to let QApplication know.
We are using resize for just resizing, not for fixed values
Make sure not to apply this when maximized
from PySide2.QtWidgets import (
QApplication,
QPushButton,
QWidget,
QVBoxLayout
)
class Test(QWidget):
def __init__(self):
super().__init__()
self.setLayout(QVBoxLayout(self))
self.add = QPushButton(self, text="Toggle")
self.added = QPushButton(self, text="Hello There")
self.added.setMinimumHeight(600)
self.added.setVisible(False)
self.layout().addWidget(self.add)
self.layout().addWidget(self.added)
self.add.clicked.connect(
lambda: self.added.setVisible(not self.added.isVisible())
)
self.add.clicked.connect(self.toggle)
# trick is to use resize and self.adjustSize
def toggle(self):
if self.isMaximized():
return ...
self.resize(self.width(), 600 if self.added.isVisible() else 100)
self.adjustSize()
sample = QApplication([])
test = Test()
test.show()
sample.exec_()

Qt pass focus between windows

In the following example I have a Qt button which opens a pop-out window. However, the pop-out window takes the focus entirely. Is it possible to modify this such that I can still interact with the main window by moving the mouse over it, e.g. to change the value of QDoubleSpinBox even when the pop-out window is open? I think I may need to use the QtHoverEvent class put I can't find a good example of how to do this.
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QGridLayout, QDoubleSpinBox,\
QLabel
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = QPushButton('Button', self)
btn.move(50, 50)
btn2 = QDoubleSpinBox(self)
btn2.move(50,100)
self.sideWindowTest = sideWindowTest(self)
btn.clicked.connect(lambda: self.sideWindowTest.setupWindow())
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Main')
self.show()
class sideWindowTest(object):
myWdg = None
def __init__(self, parent):
super().__init__()
self.viewer = parent
def initiateMenuBar(self):
self.myWdg.setWindowTitle('Phasing')
self.myWdg.setWindowModality(Qt.ApplicationModal)
MenuBar = QVBoxLayout()
self.labels = {
'phase 0': QLabel('Phase 0', self.myWdg),
}
self.inputs = {
'phase 0': QDoubleSpinBox(self.myWdg),
}
for i in self.inputs.values():
i.installEventFilter(self.myWdg)
self.inputs['phase 0'].setValue(0)
MenuBar.addWidget(self.labels['phase 0'])
MenuBar.addWidget(self.inputs['phase 0'])
MenuBar.addStretch(1)
return MenuBar
def setupWindow(self):
if not self.myWdg:
self.myWdg = QWidget()
MenuBar = self.initiateMenuBar()
grid = QGridLayout()
grid.setSpacing(10)
grid.addLayout(MenuBar, 0, 0, 1, 2)
self.myWdg.setLayout(grid)
self.myWdg.setGeometry(0, 0, 400, 100)
self.myWdg.show()
self.myWdg.activateWindow()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Yes, but you have to explicitly wrap your QWidget's in a QDialog or a QMainWindow. By default, if you create a orphan QWidget (as you are doing), Qt will wrap it in a QDialog.
Just change your class type to QDialog. Also, you should probably pass in the initial main window as the parent.
btn.clicked.connect(lambda: self.sideWindowTest.setupWindow(self))
...
def setupWindow(self, parent=None):
if not self.myWdg:
self.myWdg = QDialog(parent)

QGraphicsview + scene + QGroupBox movement issue

For past few days I was trying to solve the issue of widget movement. At some point I tried rewriting QComboBox classes with mouse signals but that did not work. As a work around I settled for parenting my widget to a QGraphicsWidget but once I try to add another item it does not display any more and I'm not sure what to do. Here is full test script:
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QApplication,QGraphicsItem, QGraphicsView, QGraphicsScene, QDesktopWidget, QCheckBox, QGroupBox, QPushButton, QGridLayout, QLabel, QLineEdit, QComboBox, QFont, QRadioButton, QButtonGroup, QWidget, QShortcut, QKeySequence, QIcon, QListView, QStandardItemModel, QStandardItem, QAction, QIntValidator, QListWidget, QProgressBar, QSpacerItem
from PyQt4.QtCore import QRect
from functools import partial
import sys
class node_GUI(QtGui.QWidget):
def __init__(self):
super(node_GUI, self).__init__()
class Main(QtGui.QMainWindow):
def __init__(self, *args):
super(Main, self).__init__(*args)#QtGui.QMainWindow.__init__(self)
self.init_defaults()
def init_defaults(self):
self.setGeometry(800,800,500,200)
self.lay_main = QGridLayout()
self.centralwidget = QtGui.QWidget()
self.centralwidget.setLayout(self.lay_main)
self.setCentralWidget(self.centralwidget)
btn_create_node = QPushButton("Create Node View")
btn_create_node.clicked.connect(self.create_node_view)
self.lay_main.addWidget(btn_create_node)
def showWindow(self,window):
window.show()
def printTest(self):
print "Start"
box = QGroupBox("subWidget")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(400,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
print "END"
def create_node_view(self):
print "creting node view"
window = node_GUI()
window.setGeometry(QRect(100, 100, 400, 200))
window.setWindowTitle("node ")
window.setObjectName("node")
show_window = QPushButton("Show Node Editor")
show_window.setObjectName("btn")
show_window.clicked.connect(partial(self.showWindow,window))
self.lay_main.addWidget(show_window)
box = QGroupBox("Widgets")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(300,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
area.setAutoFillBackground(True)
ecs = QtGui.QGraphicsEllipseItem()
ecs.setRect(QtCore.QRectF(79,79,79,79))
ecs.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
ecs.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
view = QGraphicsView()
self.scene = QGraphicsScene()
self.scene.addItem(area)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
self.scene.addItem(ecs)
view.setScene(self.scene)
lay_window = QGridLayout()
window.setLayout(lay_window)
lay_window.addWidget(view)
def main():
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
When you click on Create Node View > Show Node Editor > Test button > a new GroupBox should appear but that does not work. Not sure why.
Right so I stopped using QGraphicsWidget() and instead I just use QGraphicsRectItem(ecs for example) once I did that change everything started to work as expected.

PyQt5 - Add image in background of MainWindow layout

New to PyQt5... Here is a very basic question.
I would like to add an image inside the layout of a widget. This widget is the Main Window / root widget of my application. I use the following code, but I get an error message.
import sys
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300,300,300,220)
self.setWindowTitle("Hello !")
oImage = QImage("backgound.png")
oLayout = QVBoxLayout()
oLayout.addWidget(oImage)
self.setLayout(oLayout)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())
TypeError: QBoxLayout.addWidget(QWidget, int stretch=0, Qt.Alignment alignment=0): argument 1 has unexpected type 'QImage'
Apparently a QLayoutWidget does not accept a QImage as an input. Is there a workaround to have an image appear as a brackground in a QWidget ?
The QVBoxLayout class lines up widgets vertically.
documentation QVBoxLayout
QImage is no widget.
on many widgets e.g. QmainWindow, QLabel you can use
widget.setStyleSheet(„ background-image: url(backgound.png);“)
on my machine this doesn't work with QWidget. In this case you can use the following rewrite of your code:
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QImage, QPalette, QBrush
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setGeometry(100,100,300,200)
oImage = QImage("test.png")
sImage = oImage.scaled(QSize(300,200)) # resize Image to widgets size
palette = QPalette()
palette.setBrush(QPalette.Window, QBrush(sImage))
self.setPalette(palette)
self.label = QLabel('Test', self) # test, if it's really backgroundimage
self.label.setGeometry(50,50,200,50)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())

PyQt4 Mdi sub window not resizing properly

In the following example, when you click the button, the entire form is rebuilt adding a new label each time. At the end is a resize call that doesn't appear to work. While debugging, I validated the sizeHint() is returning the correct dimensions, and internally the widget thinks it is the correct size, but what is drawn is not correct. What can I do to force the MDI window to resize correctly? Also of note, when not sized correctly, if you manually start resizing, it suddenly snaps to the appropriate size.
import sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class MdiWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.buildWindow()
def buildWindow(self):
main = QVBoxLayout()
button = QPushButton('Change Count')
button.clicked.connect(self.changeCount)
main.addWidget(button)
for i in range(self.count):
main.addWidget(QLabel(str(i)))
widget = QWidget()
widget.setLayout(main)
self.setCentralWidget(widget)
self.resize(main.sizeHint())
def changeCount(self, event):
self.count += 1
self.buildWindow()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Resize Test')
self.mdiArea = QMdiArea()
self.setCentralWidget(self.mdiArea)
child = MdiWindow()
self.mdiArea.addSubWindow(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())

Resources