I'm having difficulty getting widgets in a QDialog resized automatically when the dialog itself is resized.
In the following program, the textarea resizes automatically if you resize the main window. However, the textarea within the dialog stays the same size when the dialog is resized.
Is there any way of making the textarea in the dialog resize automatically? I've tried using setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) on the dialog itself and the two widgets within, but that seems to have no effect.
I'm using Qt version 3.3.7 and PyQt version 3.5.5-29 on openSuSE 10.2, if that's relevant.
import sys
from qt import *
# The numbers 1 to 1000 as a string.
NUMBERS = ("%d " * 1000) % (tuple(range(1,1001)))
# Add a textarea containing the numbers 1 to 1000 to the given
# QWidget.
def addTextArea(parent, size):
textbox = QTextEdit(parent)
textbox.setReadOnly(True)
textbox.setMinimumSize(QSize(size, size*0.75))
textbox.setText(NUMBERS)
class TestDialog(QDialog):
def __init__(self,parent=None):
QDialog.__init__(self,parent)
self.setCaption("Dialog")
everything = QVBox(self)
addTextArea(everything, 400)
everything.resize(everything.sizeHint())
class TestMainWindow(QMainWindow):
def __init__(self,parent=None):
QMainWindow.__init__(self,parent)
self.setCaption("Main Window")
everything = QVBox(self)
addTextArea(everything, 800)
button = QPushButton("Open dialog", everything)
self.connect(button, SIGNAL('clicked()'), self.openDialog)
self.setCentralWidget(everything)
self.resize(self.sizeHint())
self.dialog = TestDialog(self)
def openDialog(self):
self.dialog.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainwin = TestMainWindow(None)
app.setMainWidget(mainwin)
mainwin.show()
app.exec_loop()
QMainWindow has special behavior for the central widget that a QDialog does not. To achieve the desired behavior you need to create a layout, add the text area to the layout and assign the layout to the dialog.
Just to add a little note about this - I was trying to have a child window spawned from an application, which is a QDialog, containing a single QTextEdit as a child/content - and I wanted the QTextEdit to resize automatically whenever the QDialog window size changes. This seems to have done the trick for me with PyQt4:
def showTextWindow(self):
#QVBox, QHBox # don't exist in Qt4
dialog = QDialog(self)
#dialog.setGeometry(QRect(100, 100, 400, 200))
dialog.setWindowTitle("Title")
dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
textbox = QTextEdit(dialog)
textbox.setReadOnly(True)
textbox.setMinimumSize(QSize(400, 400*0.75))
textbox.setText("AHAAA!")
# this seems enough to have the QTextEdit
# autoresize to window size changes of dialog!
layout = QHBoxLayout(dialog)
layout.addWidget(textbox)
dialog.setLayout(layout)
dialog.exec_()
I had looked at using a QLayout before but had no luck. I was trying to do something like
dialog.setLayout(some_layout)
but I couldn't get that approach to work so I gave up.
My mistake was that I was trying to pass the layout to the dialog when I should have been passing the dialog to the layout.
Adding the lines
layout = QVBoxLayout(self)
layout.add(everything)
to the end of TestDialog.__init__ fixes the problem.
Thanks to Monjardin for prompting me to reconsider layouts.
Check out Python QT Automatic Widget Resizer It's suppose to work well.
Related
I am learning how to use PyQt5 and I came across this issue where "my first label" does not complete display on my screen.
Display after running the code:
Code:
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) #enable highdpi scaling
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) #use highdpi icons
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Tech with Aeijan")
label = QtWidgets.QLabel(win)
label.setText("my first label!")
label.move(50,50)
win.show()
sys.exit(app.exec_())
window()
QLabel adapts its contents based on the (possible) parent layout manager, but you didn't use any, so it doesn't know how to correctly display itself or adapt its size to do that.
The simplest solution is to call label.adjustSize(), which will cause the label to resize itself so that it will be able to display its contents.
That wouldn't be a very good idea, though: you are trying to use a fixed position for a widget (which is normally considered a bad thing to do, for plenty of reasons); the result will be that if the label text is too big and the user resizes the window, the text won't be completely visible as it should be, nor the label would know how to resize or eventually wrap its contents to do ensure that all its text is shown.
The better approach is to use a layout manager, but that is a solution reserved for simpler widgets (like a QWidget or a QDialog); a QMainWindow doesn't work like that, and it requires a central widget to be set to ensure that its contents are correctly displayed and managed.
In your case, you could simply use self.setCentralWidget(label), but that would prevent you to add any other widget to your window.
A "container" widget should be used instead, and that widget would be set as the central one for the main window; then you can set a layout for that widget and add the label to it:
def window():
app = QApplication(sys.argv)
win = QMainWindow()
central = QWidget()
win.setCentralWidget(central)
layout = QVBoxLayout()
central.setLayout(layout)
# alternatively, the above is the same as this:
# layout = QVBoxLayout(central)
label = QtWidgets.QLabel(win)
label.setText("my first label!")
layout.addWidget(label)
# ...
I have two buttons and both of the has some hovering effect. The first button has a menu as well, and the problem is, when the first button is clicked and menu appears, the mouse hover doesn't work for the second button at the same time until the menu is closed.
I'm not sure, but I believe it is due to some sort of focusPolicy, and I tried to find the solution but I couldn't. I just want to make hovering effect on the buttons of the widget available even while showing the menu.
from PySide2 import QtWidgets, QtGui, QtCore
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.resize(300, 300)
layout = QtWidgets.QHBoxLayout(self)
btn = QtWidgets.QPushButton('Button 1')
btn.setStyleSheet('QPushButton::hover{background-color: gray;}')
layout.addWidget(btn)
menu = QtWidgets.QMenu(self)
action = QtWidgets.QAction('buttonAction', menu)
menu.addAction(action)
btn.setMenu(menu)
btn = QtWidgets.QPushButton('Button 2')
btn.setStyleSheet('QPushButton::hover{background-color: gray;}')
layout.addWidget(btn)
self.setLayout(layout)
app = QtWidgets.QApplication([])
wig = MyWidget()
wig.show()
sys.exit(app.exec_())
Please be noted, instead of stylesheet, I even tried using evenFilter changing the colors on Enter/Leave events and returning True/`False values.
TL; DR; The behavior you want is not possible.
Explanation:
Only one window can have the focus and only the widgets that belong to that window can get the focus. In this case, the QMenu lives in a different window that is on top of the original window and that window is the one with the focus and no longer the original window.
I am learning how to use PyQt5 and I came across this issue where "my first label" does not complete display on my screen.
Display after running the code:
Code:
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) #enable highdpi scaling
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) #use highdpi icons
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Tech with Aeijan")
label = QtWidgets.QLabel(win)
label.setText("my first label!")
label.move(50,50)
win.show()
sys.exit(app.exec_())
window()
QLabel adapts its contents based on the (possible) parent layout manager, but you didn't use any, so it doesn't know how to correctly display itself or adapt its size to do that.
The simplest solution is to call label.adjustSize(), which will cause the label to resize itself so that it will be able to display its contents.
That wouldn't be a very good idea, though: you are trying to use a fixed position for a widget (which is normally considered a bad thing to do, for plenty of reasons); the result will be that if the label text is too big and the user resizes the window, the text won't be completely visible as it should be, nor the label would know how to resize or eventually wrap its contents to do ensure that all its text is shown.
The better approach is to use a layout manager, but that is a solution reserved for simpler widgets (like a QWidget or a QDialog); a QMainWindow doesn't work like that, and it requires a central widget to be set to ensure that its contents are correctly displayed and managed.
In your case, you could simply use self.setCentralWidget(label), but that would prevent you to add any other widget to your window.
A "container" widget should be used instead, and that widget would be set as the central one for the main window; then you can set a layout for that widget and add the label to it:
def window():
app = QApplication(sys.argv)
win = QMainWindow()
central = QWidget()
win.setCentralWidget(central)
layout = QVBoxLayout()
central.setLayout(layout)
# alternatively, the above is the same as this:
# layout = QVBoxLayout(central)
label = QtWidgets.QLabel(win)
label.setText("my first label!")
layout.addWidget(label)
# ...
Using PyQt4, when I hide a window and show it afterwards, it appears at another position (at least here on Linux). Example code:
#!/usr/bin/python3
from PyQt4.QtGui import *
app = QApplication([])
widget = QWidget()
widget.setLayout(QVBoxLayout())
label = QLabel()
widget.layout().addWidget(label)
def hideShow():
widget.hide()
widget.show()
widget.layout().addWidget(QPushButton('Hide/Show', clicked = hideShow))
widget.show()
app.exec_()
The window disappears and appears, but a bit below and to the right of the original position. I think it's displaced by the size of the window manager's frame around the actual widget.
How can I place the window at the exact position where it was? And why does it move at all? Shouldn't it stay where it is?
On Linux, window placement can be very unpredictable. See this section in the Qt documentation for a break-down of the issues.
There's probably no general solution to the problem, but for me, setting the geometry before the initial show() seems to work:
...
widget.setGeometry(200, 200, 100, 50)
widget.show()
app.exec_()
UPDATE
After some testing with the KDE window manager, I may have discovered a potential solution.
It seems that calling show() immediately after hide() does not give the window manager enough time to calculate the correct window position. So a simple workaround is to explicitly set the geometry after a small delay:
from PyQt4.QtGui import *
from PyQt4.QtCore import QTimer
app = QApplication([])
widget = QWidget()
widget.setLayout(QVBoxLayout())
label = QLabel()
widget.layout().addWidget(label)
def hideShow():
widget.hide()
QTimer.singleShot(25, showWidget)
def showWidget():
widget.setGeometry(widget.geometry())
widget.show()
widget.layout().addWidget(QPushButton('Hide/Show', clicked = hideShow))
widget.show()
app.exec_()
This works for me using KDE-4.8 and OpenBox, but of course YMMV.
I have had similar problem with xfce. Perhaps you could get the position before hiding it (or when displaying it, depending on what you want), store it away, and then set it when it is displayed again with setGeometry()? A bit hacky perhaps..
I created a small window using PyQt4 and Pydev. The code is below:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
# Create GUI object
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
widget.setGeometry(400,300,800,800) # Position window
widget.resize(450,250) # Resize window
widget.setWindowTitle('Sample') # Set Title of the window
Password = QtGui.QLineEdit() # Input Box for password
widget.show() # Display window
# Exit program
sys.exit(app.exec_())
I created the Password LineEdit box but how to show on the active window, which is represented by widget?
Just use
Password = QtGui.QLineEdit(widget)
This tells Qt that you want widget to be the parent of the QLineEdit. If you leave out the widget, then the QLineEdit has no parent, so it's not shown.
Update: To position child items in parent windows, you'll have to read up about layouts (I assume you want to do it properly, not as a toy/learning exercise). Any good PyQt book should be able to help, e.g. this one.