I want to hide a QFrame from the start of the app to later on showing it as a warning message with a function.
But I can't find a solution. The frame keeps showing up without changing its start size.
I would also be happy with a solution in Qt Designer but I can't figure out how to do it either way.
self.frame_top_warning.setFixedHeight(0) seems to work but makes problems later on when animating that frame.
class SampleApp(ui_main.Ui_MainWindow, QtWidgets.QMainWindow):
def __init__(self):
super(SampleApp, self).__init__()
self.setupUi(self)
# Here I want to set the start size to 0 to, later on, animate it in.
self.frame_top_warning.resize(self.frame_top_warning.width(), 0)
One possibility could be to set the maximum height of the widget to 0 with self.frame_top_warning.setMaximumHeight(0) at the beginning to hide the QFrame. Then you can use QtCore.QParallelAnimationGroup to animate two properties at the same time minimumHeight and maximumHeight. In this way you are constraining the height of the widget to be what you want it to be.
I have put together a small example to show you what I mean
import sys
from PyQt5 import QtWidgets, QtCore
class Widget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout()
show_warning_button = QtWidgets.QPushButton('Show Warning')
layout.addWidget(show_warning_button)
show_warning_button.clicked.connect(self.showWarningLabel)
layout.addWidget(QtWidgets.QPushButton('Button'))
layout.addWidget(QtWidgets.QLabel('This is some text'))
self.frame_top_warning = QtWidgets.QFrame()
self.frame_top_warning.setStyleSheet('QFrame {background: red;}')
self.frame_top_warning.setMaximumHeight(0)
layout.addWidget(self.frame_top_warning)
min_height_animation = QtCore.QPropertyAnimation(self.frame_top_warning, b"minimumHeight")
min_height_animation.setDuration(600)
min_height_animation.setStartValue(0)
min_height_animation.setEndValue(400)
max_height_animation = QtCore.QPropertyAnimation(self.frame_top_warning, b"maximumHeight")
max_height_animation.setDuration(600)
max_height_animation.setStartValue(0)
max_height_animation.setEndValue(400)
self.animation = QtCore.QParallelAnimationGroup()
self.animation.addAnimation(min_height_animation)
self.animation.addAnimation(max_height_animation)
self.setLayout(layout)
self.resize(800, 600)
self.show()
def showWarningLabel(self):
self.animation.start()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
Hope this helps =)
Related
I try to create a gui. The window should be resizable. When resized horizontally some of them widgets should expand and vertically too. I illustrated this to make it more clear:
Initial
horizontal resize
vertical resize
In Qt I use QHBoxLayout but without success unfortunately.
Thanks.
For Example :
You need to use the setStretchFactor method on your QSplitter
An example (modified from the QSplitter example Here):
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QtGui.QHBoxLayout(self)
left = QtGui.QFrame(self)
left.setFrameShape(QtGui.QFrame.StyledPanel)
right = QtGui.QFrame(self)
right.setFrameShape(QtGui.QFrame.StyledPanel)
splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
splitter.addWidget(left)
splitter.addWidget(right)
splitter.setStretchFactor(1, 1)
splitter.setSizes([125, 150])
hbox.addWidget(splitter)
self.setLayout(hbox)
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QtGui.QSplitter')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This produces an initial UI that looks like this:
When the image is expanded horizontally, you can see that the left widget stays the same size:
When expanded vertically, both widgets expand:
Finally, the splitter is resizeable:
If you adjust the window size after adjusting the splitter, the left widget will retain it's size and the right will expand/collapse to fill the remainder of the window.
I have this code:
class Window(QWidget):
def __init__(self):
super().__init__()
def init_gui(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.new1()
self.new2()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
scroll_area.setWidget(widget)
layout = QVBoxLayout()
widget.setLayout(layout)
button = QPushButton("Ahoj")
layout.addWidget(button)
self.layout.addLayout(layout)
def new1(self):
self.create_scroll_area()
def new2(self):
self.create_scroll_area()
I get this error message:
QLayout::addChildLayout: layout "" already has a parent
What's wrong?
Who is layout's parent? Widget? I also tried self.widget instead of widget and it still does not work.
Please try this code.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=None)
self.init_gui()
def init_gui(self):
self.create_scroll_area()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
layout = QVBoxLayout()
button = QPushButton("Ahoj")
layout.addWidget(button)
widget.setLayout(layout)
scroll_area.setWidget(widget)
self.setLayout(layout)
def main():
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Let's revise from A to Z.
1 to write self.init_gui() in __init__ constructor.
If you don't do it, you can't execute init_gui method at the first time.
2.setLayout() or setWidget() should be written at the last place at least.
In python, we prepare the things we want to show, and set them on the mainwidget, and show them at the last time.
3.please pay attention to self.layout name.
Widget has originally setLayout() method. and layout() method.
If you make self.layout = ***, you crush the original method of QWidget.
4. it may as well delete new1 and new2 method.
please call them directly.
5. please look create_scroll_area method.
You make three widget.QScrollArea,QWidget,QPushButton.
and make a layout object.and you set the layout into QWidget.
But you set the QWidget before the widget set the layout.
It is not good order for coding.
You make QPushButton but the button doesn't belong to any widget.
Because you set the button on the self.layout certainly, but if you want to show it, you must setLayout(self.layout) at the last position.
I'm very new to PySide/PyQt environment. I'm trying to make a menu of buttons on top and assign a task to each so that when they are clicked a function draws a painting on the central window. But I also want to make the button change when they are clicked.
I think this might be an straighforward problem to solve if I use QPushButton, but my buttons are images and I'm using the method suggested HERE and use QAbstractButton to create them.
It is mentioned there that
You can add second pixmap and draw it only when the mouse pointer is
hover over button.
And I'm trying to do exactly that. My question is this:
what are possible ways to achieve this? Are the same methods in QPushButtons applicable here? If so, are there any examples of it somewhere?
Here is a snippet of my code:
import sys
from PySide import QtGui, QtCore
BACKGROUND_COLOR = '#808080'
ICON_PATH_ACTIVE = 'icons/activ'
ICON_PATH_PASSIVE = 'icons/pasiv'
class MainWindow(QtGui.QMainWindow):
def __init__(self, app=None):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
dockwidget = QtGui.QWidget()
self.setGeometry(200, 200, 400, 300)
hbox = QtGui.QHBoxLayout()
1_button = PicButton(QtGui.QPixmap("icons/pasiv/1.png"))
2_button = PicButton(QtGui.QPixmap("icons/pasiv/2.png"))
3_button = PicButton(QtGui.QPixmap("icons/pasiv/3.png"))
hbox.addWidget(1_button)
hbox.addWidget(2_button)
hbox.addWidget(3_button)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(hbox)
vbox.setAlignment(hbox, QtCore.Qt.AlignTop)
dockwidget.setLayout(vbox)
self.setCentralWidget(dockwidget)
class PicButton(QtGui.QAbstractButton):
def __init__(self, pixmap, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
self.setFixedSize(100, 100)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawPixmap(event.rect(), self.pixmap)
def main():
app = QtGui.QApplication(sys.argv)
central = MainWindow()
central.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Thank you.
Use a regular QPushButton with an icon.
iplay = QtGui.QIcon("path/play_icon.png")
ipause = QtGui.QIcon("path/pause_icon.png")
btn = QtGui.QPushButton(ipause, "", None)
def toggle_play():
if btn.icon() == ipause:
btn.setIcon(iplay)
# Do Pause Action
else:
btn.setIcon(ipause)
# Do Play Action
btn.clicked.connect(toggle_play)
btn.show()
If you want hover functionality then you will have to subclass the QPushButton
class MyButton(QtGui.QPushButton):
custom_click_signal = QtCore.Signal()
def enterEvent(self, event):
super().enterEvent(event)
# Change icon hove image here
def leaveEvent(self, event):
super().leaveEvent(event)
# Change icon back to original image here.
def mousePressEvent(self, event):
super().mousePressEvent(event)
self.custom_click_signal.emit()
# connect to signal btn.custom_click_signal.connect(method)
Icons are probably the easiest way instead of manually managing the paint event. There are also mousePressEvent and mouseReleaseEvents if you want the icon to change for someone holding the button down.
I have a QTabWidget working correctly except that it doesn't re-size how I would expect it.
There are 2 tabs in the widget. Each has a QVBoxLayout with widgets in it. The VBox also works as expected.
The issue is that the first tab has more widgets in its layout than the second tab. When viewing the first tab, the tab sizes to appropriately contain the widgets inside of it. However, when viewing the second tab, the tab widget stays the same size of the first, instead of re-sizing to the visible widgets.
Is this behavior expected? If so, what is a good work around? Id like for the tab widget to always scale to the currently active widget.
EDIT:
Here is an example of the issue. The desired behavior is for Tab B to shrink to its proper size, which can be seen by commenting out the line noted below.
#!/bin/python
import sys
from PySide import QtGui, QtCore
class TabExample(QtGui.QWidget):
def __init__(self):
super(TabExample, self).__init__()
self.initUI()
def initUI(self):
self.vbox_main = QtGui.QVBoxLayout()
self.table_blank = QtGui.QTableWidget(10, 4)
self.tabw = QtGui.QTabWidget()
self.tab_A = QtGui.QWidget()
self.vbox_A = QtGui.QVBoxLayout(self.tab_A)
for i in range(20):
lab = QtGui.QLabel('label %d' %i)
self.vbox_A.addWidget(lab)
self.tab_B = QtGui.QWidget()
self.vbox_B = QtGui.QVBoxLayout(self.tab_B)
for i in range(5):
lab = QtGui.QLabel('labelB %d'%i)
self.vbox_B.addWidget(lab)
#COMMENT OUT NEXT LINE TO SEE DESIRED SIZE OF TAB B
self.tabw.addTab(self.tab_A, 'Tab A')
self.tabw.addTab(self.tab_B, 'Tab B')
self.vbox_main.addWidget(self.table_blank, 1)
self.vbox_main.addWidget(self.tabw)
self.setLayout(self.vbox_main)
self.setGeometry(0,0, 400, 600)
self.move(QtGui.QDesktopWidget().availableGeometry().center() - self.frameGeometry().center())
self.show()
def main():
app = QtGui.QApplication(sys.argv)
tabExample = TabExample()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
This should do the trick; change the size policy depending on which tab is active.
def __init__(self):
super(Widget, self).__init__()
self.setupUi(self)
self.tabWidget_2.currentChanged.connect(self.updateSizes)
def updateSizes(self):
for i in range(self.tabWidget_2.count()):
self.tabWidget_2.widget(i).setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
current = self.tabWidget_2.currentWidget()
current.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
I would like to resize the MainWindow (QMainWindow) after I make some widgets unvisible and vice versa. And I want to block the window resize.
def hideAndShowWidget(self):
self.widgetObject.setVisible(not self.widgetObject.isVisible() )
# change main window size here
# ...
self.setFixedSize(self.width(), self.height())
My problem is, that i can not change the window size after i call setFixedSize() first time. I read here that I must use QWIDGETSIZE_MAX() to remove constraints, but I don't know how can I use it, I get the error:
NameError: name 'QWIDGETSIZE_MAX' is not defined
I think you have the mechanism more or less right. You just have to make sure the height calculation is done correctly (i.e. before the visibility of the widget changes).
The following example works correctly for me (only tested on Linux, though):
from PySide import QtGui
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.widgetObject = QtGui.QTextEdit(self)
self.button = QtGui.QPushButton('Hide Widget', self)
self.button.clicked.connect(self.hideAndShowWidget)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
layout.addWidget(self.widgetObject)
self.setFixedSize(300, 200)
def hideAndShowWidget(self):
height = self.height()
if self.widgetObject.isVisible():
height -= self.widgetObject.height()
self.widgetObject.setVisible(False)
self.button.setText('Show Widget')
else:
height += self.widgetObject.height()
self.widgetObject.setVisible(True)
self.button.setText('Hide Widget')
self.setFixedSize(self.width(), height)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Use the sizeHint(). It contains the size the widget would like to have. Set the fixed size exactly to the size hint.
Working example:
from PySide import QtGui
class Window(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.setFixedSize(400, 300)
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)
button = QtGui.QPushButton('Toggle visibility')
button.clicked.connect(self.hideAndShowWidget)
layout.addWidget(button)
self.widgetObject = QtGui.QLabel('Test')
layout.addWidget(self.widgetObject)
self.setCentralWidget(widget)
def hideAndShowWidget(self):
self.widgetObject.setVisible(not self.widgetObject.isVisible() )
# change main window size
self.setFixedSize(self.sizeHint())
app = QtGui.QApplication([])
w = Window()
w.show()
app.exec_()