QGraphicsview + scene + QGroupBox movement issue - pyqt

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.

Related

PyQt5 does not redrawing widget

Force repainting does not repaint PyQt5 widget (Qlabel, QTextEdit, even QProgressBar and etc)
Tested platforms: Linux, MacOS
PyQt5 version: 5.15.7
Installed from pip
As example I created simple app that updating text in QLabel widget in for loop. Force repainting doesnt working
import sys
from time import sleep
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)
class Example(QWidget):
def __init__(self):
super().__init__()
self.text = QLabel('Test', self)
self.text.move(10, 10)
self.text.resize(60,20)
self.button = QPushButton('Run', self)
self.button.move(17,40)
self.button.clicked.connect(self.some_activity)
self.setGeometry(300, 300, 100, 80)
self.show()
def some_activity(self):
for i in range(100):
text = f'i = {i}'
self.text.setText(text)
# self.text.update() -> Nothing happens (it shouldnt: https://doc.qt.io/qt-5/qwidget.html#update)
self.text.repaint() # -> Nothing happens
self.repaint() # -> Nothing happens
print(f'Text updated: {text}')
sleep(0.03)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Video demonstration: link
Just needed to use QThread to use for loop in my program
Thanks #musicamante for helping.
import sys
from time import sleep
from PyQt5 import QtCore
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)
class Thread(QtCore.QThread):
signal = QtCore.pyqtSignal(str)
def __init__(self, parent=None): QtCore.QThread.__init__(self, parent)
def run(self):
for i in range(100):
text = f'i = {i}'
print(f'Text updated: {text}')
self.signal.emit(text)
sleep(.3)
class Example(QWidget):
def __init__(self):
super().__init__()
self.text = QLabel('Test', self)
self.text.move(10, 10)
self.text.resize(60,20)
self.thread = Thread()
self.thread.signal.connect(self.signal, QtCore.Qt.QueuedConnection)
self.button = QPushButton('Run', self)
self.button.move(17,40)
self.button.clicked.connect(self.thread.start)
self.setGeometry(300, 300, 100, 80)
self.show()
def signal(self, text): self.text.setText(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

PyQt5: QLineEdit doesn't show inside a QGroupBox

I'm creating a PyQt5 application in which I want to put some of QLineEdit widgets inside a QGroupBox.
When I run my application, GroupBox is visible and LineEdit is not.
In CreateLinesEdit() I commented a line which sets the line edit visible, but it opens lineEdit in a new window.
from PyQt5.QtWidgets import QGroupBox, QApplication, QLineEdit, QVBoxLayout, QWidget, QHBoxLayout
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.InitWindow()
def InitWindow(self):
self.BoxLayout()
self.AddBox()
self.CreateLinesEdit()
self.show()
def BoxLayout(self):
self.groupBoxScreen = QGroupBox()
self.vbox = QVBoxLayout()
self.vbox_screenGame = QVBoxLayout()
self.hbox_lineEdit = QHBoxLayout()
def AddBox(self):
self.vbox_screenGame.addItem(self.hbox_lineEdit)
self.groupBoxScreen.setLayout(self.vbox_screenGame)
self.vbox.addWidget(self.groupBoxScreen)
self.setLayout(self.vbox)
def CreateLinesEdit(self):
self.lines_edit = []
for i in range(0, 4):
LineEdit = QLineEdit()
# LineEdit.setVisible(True)
self.lines_edit.append(LineEdit)
self.hbox_lineEdit.addWidget(self.lines_edit[i])
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

Get a selected font in a subclassed QFontDialog

I'm trying to subclass QFontDialog and would like to retrieve the characteristics of the selected font. If I use getFont() a QFontDialog window appears first, ... I'm certainly doing something wrong.
Here's my example code :
from PyQt5.QtWidgets import (QFontDialog, QPushButton,
QMainWindow, QApplication,
QTabWidget, QWidget, QVBoxLayout)
import sys
class FontSelection(QFontDialog) :
def __init__(self, parent=None):
super(FontSelection, self).__init__(parent)
self.setOption(self.DontUseNativeDialog, True)
self.bouton = self.findChildren(QPushButton)
self.intitule_bouton = self.bouton[0].text().lower()
self.ouvertureBouton = [x for x in self.bouton if self.intitule_bouton in str(x.text()).lower()][0]
self.ouvertureBouton.clicked.disconnect()
self.ouvertureBouton.clicked.connect(self.font_recup)
def font_recup(self) :
self.font_capture()
def font_capture(self) :
if self.intitule_bouton in ['ok', '&ok'] :
font, self.intitule_bouton = self.getFont()
print(font)
class MainQFontDialogTry(QMainWindow):
def __init__(self):
super(MainQFontDialogTry, self).__init__()
self.setWindowTitle('QFontDialog subclassed try')
self.setGeometry(0, 0, 1000, 760)
self.setMinimumSize(1000, 760)
self.tab_widget = QTabWidget()
self.win_widget_1 = FontSelection(self)
widget = QWidget()
layout = QVBoxLayout(widget)
self.tab_widget.addTab(self.win_widget_1, "QFontDialog Tab")
layout.addWidget(self.tab_widget)
self.setCentralWidget(widget)
self.qfont = FontSelection()
self.qfont.font_recup()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainQFontDialogTry()
ex.show()
sys.exit(app.exec_())

PyQt5 shortcut in menubar is not working

I'm trying to create a simple UI that has the functionality to close when I use the shortcut Ctrl+Q or when I use the Exit into the File menu, to make it clearer I've created a fairly simple UI that goes with the code:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp
class MGen(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
exit_action = QAction('Exit', self)
exit_action.setShortcut('Ctrl+Q')
exit_action.triggered.connect(qApp.quit)
menu_bar = self.menuBar()
file_menu = menu_bar.addMenu('&File')
file_menu.addAction(exit_action)
self.setGeometry(0, 0, 500, 500)
self.setWindowTitle('MGen')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mgen = MGen()
sys.exit(app.exec_())
Could anyone point what I'm doing wrong?

How can I make PyQt QSplitter visible?

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

Resources