Qt's opaqueresize property on QSplitter meaning - qt

I didn't find this on the web...
What does this opaqueResize property on QSplitter (see doc) stand for?
Thanks.

I am not really sure what you are asking here. It's all in the docs.
QSplitter resizes its children
dynamically by default. If you would
rather have QSplitter resize the
children only at the end of a resize
operation, call setOpaqueResize(false)
Meaning if you set setOpaqueResize(false) on your splitter, start your application and try to pull the splitter to resize the widgets it holds it will not actually resize widgets until you release the splitter. On the other hand if it is set to true it will try to resize the widgets while you are dragging the splitter handle.
It can be useful to turn this feature off if your custom widgets take long time to draw for example since it would make resizing quite slow.
But to answer your question, property opaqueResize holds whether resizing is opaque or not, i.e. will it resize the widgets while dragging the splitter or not.
Example:
Here is a PyQt example you can try (I had example laying around in Python, but it should work the same in C++):
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
top = QtGui.QLabel('test', self)
bottom = QtGui.QPushButton('test', self)
splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
# Try changing from False to True
splitter.setOpaqueResize(False)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox = QtGui.QHBoxLayout(self)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(250, 200, 350, 250)
def main():
app = QtGui.QApplication([])
ex = Example()
ex.show()
app.exec_()
if __name__ == '__main__':
main()
Hope this makes things a bit clearer.

Related

How to hide unexpected Python "splash" window that displays before my MainWindow in pyside6

Before my QMainWindow appears on screen, a smaller window titled "Python" opens up for about half a second.
I tried adding self.hide() at the top of the MainWindow init (just after super().init()), but that had no effect. I also tried covering it up with a QSplashScreen, but the window appears on top of the splash screen. Is there any way to prevent this unexpected "Python" window from appearing? Unexpected "Python" window screenshot
Here's my main file splashtest.py:
import sys
from modules.gui.main_window import *
def main():
app = QApplication(sys.argv)
#pixmap = QPixmap('./breadware-splash.png')
#splash = QSplashScreen(pixmap)
#splash.show()
window = Window()
#splash.finish(window)
app.exec()
if __name__ == "__main__":
main()
Here is main_window.py:
from PySide6.QtWidgets import QApplication, QMainWindow, QTabWidget, QSplashScreen
from PySide6.QtGui import QPixmap
from PySide6.QtCore import Qt, QSize, QThread, QObject, Signal
from modules.gui.test_tab import *
class Window(QMainWindow):
def __init__(self):
parent = super().__init__()
self.resize(800, 600)
self.setWindowTitle('Breadware Test')
# Create a tab widget
self.tw = QTabWidget()
self.testtab = self.tw.addTab(TestTab(self), "Test Device")
self.tw.show()
self.setCentralWidget(self.tw)
self.show()
And here is test_tab.py:
from PySide6.QtWidgets import QWidget, QTextEdit, QGridLayout
class TestTab(QWidget):
def __init__(self, parent):
super().__init__()
self.parent = parent
grid = QGridLayout()
self.infoarea = QTextEdit(self)
self.infoarea.setReadOnly(True)
self.infoarea.setStyleSheet("background-color: black; border: 0;")
grid.addWidget(self.infoarea, 5, 1, 1, 2)
self.setLayout(grid)
self.show()
self.infoarea.insertHtml("<span style=\"font-size:12pt; font-weight:800; color:white;\" >Hello There</span><br>")
tl;dr
Remove self.tw.show() from Window and self.show() in TestTab.
Explanation
As a rule of thumb, self.show() should never be called in the __init__() of a widget, especially for widgets that are going to be "reparented" (it becomes a child of another widget).
In your case, you are doing that mistake twice:
the first time, implicitly, in the __init__() of TestTab as written above;
then, again, in the __init__() of Window, before setting it as a central widget, which has the same result, because you are showing it before reparenting it;
Note: calling show() (just like setVisible(True)) more than once within the same function call does not change the result; with your current code, even using just one of the calls above would have created the issue, as you experience showed, based on your comment); such calls are not immediate, the create an extended queue of events that eventually result in what the user can see and interact with on the screen. If the widget is already visible, any further call is a no-op, unless another change in the widget status has happened in the meantime, such as changing the window flags.
The reason is simple: if a widget is created without a parent, it is always considered a top level one (a window). If a widget that has no parent calls self.show(), it will show itself as a separate window.
Your code would not have created the issue if:
you did not call self.tw.show() before self.setCentralWidget();
most importantly, you properly used the parent argument of __init__() by calling super().__init__(parent) (because you used TestTab(self));
Calling show() on a child widget will (obviously) not show it if the parent is not shown, it will only "mark" it as visible and make it as such as soon as the parent is shown. This is extremely important for child widgets created after the parent is being shown: in that case, calling show() is mandatory (unless the widget is added to the layout manager of the parent, see below).
This means that the only cases for which calling self.show() in the init is considerable acceptable is:
when you are completely sure that the widget will always be a top level window;
when the parent argument is properly used in the super call and the parent is actually valid:
class ProperShowCallWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
if parent is not None:
self.show()
The above will make the widget automatically visible when it's created with a parent, even if it is not going to be added to a layout manager.
Be aware that, actually, you should always use layouts managers (unless you really know what you are doing), so calling show() is pointless, as a child widget is implicitly shown when added to a widget layout, unless setVisible(False) (or hide()) is explicitly called.
So, not only you should remove those show() calls as written at the beginning of this post, but you should also remove self.show() in the __init__() of Window and move it into your "main" code:
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec()) # <- you should use sys.exit()
Do not underestimate the documentation
I strongly advise you to take your time to carefully study the related documentation for:
the visible property;
isHidden() (which is not the same as not isVisible());
isVisibleTo();
window() and isWindow();
the Qt.WindowFlags (notably, Qt.Window, automatically set for any widget created without a parent);
parentWidget(), QObject.parent() and the concepts behind Qt object trees and ownership;
the whole documentation about QWidget and the inherited QObject type, starting from their detailed description, going through all their functions, and then doing the same for all the related classes used by those functions;
Finally, consider that there are always exceptions. There are widgets that, even if created with a parent, are still shown as top level widgets. The most common case is QDialog (and all its subclasses, such as QMessageBox), which is always considered a top level window by default, even if it has a parent widget. That is because they are modal windows, and the parent widget is used as a reference to know to what window they are considered modal (blocking any input to those windows until the dialog is closed). Other similar cases are: menus, tooltips, floating tool bars/dock widgets and splash screens (see the Qt.WindowFlags above: they all use a window flag that uses the Qt.Window enum).

QGraphicsView / QGraphicsScene size matching

How do you make a QGraphicsScene with a specified size and a QGraphicsView to monitor that scene with the same size?
This sounds like a stupid question but consider the following test code [1]
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.scene = QtGui.QGraphicsScene(0, 0, 200, 200, self)
self.view = QtGui.QGraphicsView(self.scene, self)
#self.view.setMaximumSize(200, 200)
self.setCentralWidget(self.view)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
When I run this I get a little window with the QGraphicsView and no scroll bars. If I shrink the window scroll bars appear because I've made the view smaller than the specified size of the scene. If I enlarge the window the bars go away and the view resizes with the window. All of this makes sense.
Now I run the same code again but with the commented line (preceded by #) un-commented. The Window appears with the view inside, but the view has scroll bars. When I shrink the window the view also shrinks, but when I enlarge the window the view only enlarges to a certain size. This is not surprising. What is surprising is that with the view at it's maximum size, the scroll bars are still there. I don't understand this because the maximum size of the view is explicitly matched to the size of the scene in the code.
Why does this happen?
I am aware that other questions have explained how to force the scene and view to fit together but I want to understand what size view and scene I have actually made, hence my attempt to use explicitly specified sizes.
[1] I'm using PyQt, C++ users just read "self" as "this" and "import" as "#include"
EDIT: The accepted answer below is absolutely correct. I would just like to add for others who read this that if your view is in a layout you have to account for the layout margins as well. These can be explicitly set in the QtDesigner etc.
Ok, I worked it out for you!
The QGraphicsView (which subclasses QFrame) has a border. If you add the below line to your init method:
self.view.setFrameShape(QtGui.QFrame.NoFrame)
then you remove the 1px frame and it works as you expect!

Qt:How to create a Window that does not minimize and do not block background GUI

I have a QMainWindow that is a child to another window. When the user clicks anywhere in the parent window, I do not want the child window to be minimized. The child window should lose the focus and user should be able to continue working on the parent window.
This functionality is similar to the find/replace dialogs found in libreoffice/excel/openoffice etc as shown below. We can see that the task-bar shows only the parent application window and the child window is not visible in task-bar.
Are there any signals on QMainWindow that could help me achieve this? Or what would be the best way to do this?
If you open the new window as Dialog and give it a parent, it should stay on top of the parent. Since you're using QMainWindow, you can pass this with the constructor. If you decide to use QDialog, make sure you make it modeless with setModal(False). Otherwise it will block the parent.
A small example:
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
w = QtGui.QWidget()
layout = QtGui.QVBoxLayout(w)
self.button = QtGui.QPushButton('Open Dialog')
self.text = QtGui.QTextEdit()
layout.addWidget(self.button)
layout.addWidget(self.text)
self.setCentralWidget(w)
self.button.clicked.connect(self.openDialog)
def openDialog(self):
self.dialog = QtGui.QMainWindow(self, QtCore.Qt.Dialog)
self.dialog.show()
app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

PyQt/Qt: How do I temporarily override the paintEvent() method for a QTextEdit? (What am I doing wrong??)

I am trying to temporarily display a QWebPage in the viewport of a QTextEdit. Here is the pertinent code from my program:
class Editor(QTextEdit):
def __init__(self):
super(Editor, self).__init__()
self.webpage = QWebPage(self)
self.paintwebpage = False
def showWebPage(self, html):
self.webpage.mainFrame().setHtml(html)
self.paintwebpage = True
self.update()
def hideWebPage(self):
self.paintwebpage = False
self.update()
def paintEvent(self, event):
if self.paintwebpage:
self.webpage.setViewportSize(self.viewport().size())
painter = QPainter(self.viewport())
self.webpage.mainFrame().render(painter)
painter.end()
else:
super(Editor, self).paintEvent(event)
And it never works. I have tried many variations, including telling it exactly the rectangle to paint, or first painting to an image and then painting the image, etc. It always displays maybe a line or two of the webpage, in strange positions in the viewport. Why can't I get it to overwrite the entire viewport from 0,0? Where am I going wrong?
[I want to display a preview of html code from the editor, without the need for multiple space taking widgets; for example, while the user holds down a certain button, the view will temporarily flip to the preview of the html near the cursor.]
Rather than overloading the paintEvent, you could use a QStackedWidget and just swap the widgets over.
This may be a simpler solution to the problem, as it is only a single call to setCurrentIndex to swap the visible widget.

Why won't my dialog show properly when I set its parent on instantiation?

In the attached example script, why won't the MyDialog instance show properly when I set MyDialog's parent to self on line 20 instead of leaving it blank? First I thought the shortcut had stopped working somehow, but obviously that's not the case.
In this case it doesn't really make any difference whether the parent is set, but in my real case I need the parent to be set.
Am I missing something obvious here?
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MyDialog(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setFocusPolicy(Qt.StrongFocus)
label = QLabel(self)
label.setText("World")
hbox = QHBoxLayout()
hbox.addWidget(label)
self.setLayout(hbox)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.my_dialog = MyDialog()
#self.my_dialog = MyDialog(self)
label = QLabel(self)
label.setText("Hello")
self.setCentralWidget(label)
shortcut = QShortcut(QKeySequence(Qt.Key_Tab), self, self.show_my_dialog)
shortcut.setContext(Qt.ApplicationShortcut)
self.show()
def show_my_dialog(self):
md = self.my_dialog
if md.isVisible():
md.hide()
print 'hide'
else:
md.show()
print 'show'
def main():
app = QApplication([])
main_window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
On my machine (Kubuntu 11.10) it's working.
If Dialog's parent is None - it opens another frameless window, and i have two entries in taskbar. If i close the main window, dialog remains.
If you are using Windows - the behavior you described might be related to it. Maybe the window is shown, it's just behind other windows?
If Dialog's parent is the main window - the frameless dialog is shown inside the main window - in the top left corner near the label.
You might be interested in this info:
A dialog window is a top-level window mostly used for short-term tasks
and brief communications with the user. QDialogs may be modal or
modeless. QDialogs can provide a return value, and they can have
default buttons. QDialogs can also have a QSizeGrip in their
lower-right corner, using setSizeGripEnabled().
Note that QDialog (an
any other widget that has type Qt::Dialog) uses the parent widget
slightly differently from other classes in Qt. A dialog is always a
top-level widget, but if it has a parent, its default location is
centered on top of the parent's top-level widget (if it is not
top-level itself). It will also share the parent's taskbar entry.
Use
the overload of the QWidget::setParent() function to change the
ownership of a QDialog widget. This function allows you to explicitly
set the window flags of the reparented widget; using the overloaded
function will clear the window flags specifying the window-system
properties for the widget (in particular it will reset the Qt::Dialog
flag).

Resources