Click a button to change a GIF - python

In the App there are a QButton and a QLabel. In the QLabel I put a QMovie in, to show a GIF. By clicking the QButton I want to change the GIF, which path is defined in a list.
The problem: the App shows only the first GIF. The Button seems not working. What have I done wrong?
But: Please dont change the structure of the code. E.g. I want to have the QLabel defined in the sub-function and return from there the QLabel.
The code:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import random
list = ['F:\\test1.gif', 'F:\\test2.gif', 'F:\\test3.gif', 'F:\\test4.gif']
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.resize(600, 600)
self.initUI()
def initUI(self):
self.btn = QPushButton("change", self)
self.btn.clicked.connect(self.changeGIF)
self.grid = QVBoxLayout()
self.grid.addWidget(self.btn)
self.grid.addWidget(self.changeGIF())
self.grid.addStretch(1)
self.setLayout(self.grid)
def changeGIF(self):
randomValue = list[random.randint(1, len(list)-1)]
print(randomValue)
self.lbl = QLabel()
self.gif = QMovie(randomValue)
self.lbl.setMovie(self.gif)
self.gif.start()
return self.lbl
if __name__ == '__main__':
app = QApplication(sys.argv)
MyApp = Window()
MyApp.show()
sys.exit(app.exec_())
Thanks for the help!

since the QLabel will be responsible for showing GIFs in a random way, it is advisable to create a class that only takes care of that task, in this widget you must have a method that changes the QMovie of the QLabel.
list_of_gifs = ['F:\\test1.gif', 'F:\\test2.gif', 'F:\\test3.gif', 'F:\\test4.gif']
class GIFLabel(QLabel):
def __init__(self, gifs, *args, **kwargs):
QLabel.__init__(self, *args, **kwargs)
self.mGifs = gifs
self.changeGIF()
def changeGIF(self):
gif = random.choice(self.mGifs)
movie = QMovie(gif)
self.setMovie(movie)
movie.start()
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.resize(600, 600)
self.initUI()
def initUI(self):
self.btn = QPushButton("change", self)
self.label = GIFLabel(list_of_gifs, self)
self.btn.clicked.connect(self.label.changeGIF)
self.grid = QVBoxLayout(self)
self.grid.addWidget(self.btn)
self.grid.addWidget(self.label)
self.grid.addStretch(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
MyApp = Window()
MyApp.show()
sys.exit(app.exec_())

Related

How to make a floating window when I press the user button in pyqt5?

I am new to the world of pyqt5 I have created a window using this code:
class Ui_menu(QtWidgets.QMainWindow):
def __init__(self):
super(Ui_menu, self).__init__() # Call the inherited classes __init__ method
uic.loadUi('Windows/menu.ui', self) # Load the .ui file
self.show()
app = QtWidgets.QApplication(sys.argv)
window = Ui_menu()
app.exec_()
I want to know if you can create an animation when you click a button at the top and open a floating window as in the attached image.
look this code
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QSize, QPoint, Qt
from PyQt5.QtGui import QIcon
class MyProxyStyle(QProxyStyle):
pass
def pixelMetric(self, QStyle_PixelMetric, option=None, widget=None):
if QStyle_PixelMetric == QStyle.PM_SmallIconSize:
return 100
else:
return QProxyStyle.pixelMetric(self, QStyle_PixelMetric, option, widget)
class main(QMainWindow):
def __init__(self):
super().__init__()
self.central = QWidget()
self.toolbar = toolbar()
self.button1 = toolbutton("your_icon")
self.button2 = toolbutton("your_icon")
self.toolbar.addWidget(self.button1)
self.toolbar.addWidget(self.button2)
self.button1.clicked.connect(lambda: self.open_menu(self.button1))
self.button2.clicked.connect(lambda: self.open_menu(self.button2))
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.toolbar)
self.setCentralWidget(self.central)
self.resize(600,400)
self.show()
def open_menu(self, obj):
self.menu = QMenu()
self.menu.setStyle(MyProxyStyle())
self.menu.addAction(QIcon("your_icon"), "Person")
self.menu.addMenu("Configuration")
self.menu.addSeparator()
self.menu.addMenu("Profile")
pos = self.mapToGlobal(QPoint(obj.x(), obj.y()+obj.height()))
self.menu.exec(pos)
class toolbar(QToolBar):
def __init__(self):
super().__init__()
self.setIconSize(QSize(80,80))
self.setMinimumHeight(80)
self.setMovable(False)
class toolbutton(QToolButton):
def __init__(self, icon):
super().__init__()
self.setIcon(QIcon(icon))
self.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
app = QApplication([])
window = main()
app.exec()

QStackedWidget opening multiple windows

I have build a small application using PyQt and as far as I know QStackedWidget is used for making multipage applications. The issue is that it is opening multiple pages and also I'm unable to redirect to class Xyz using button in class Abc.
main.py
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.stacked_widget = QtGui.QStackedWidget()
layout = QtGui.QVBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.addWidget(self.stacked_widget)
widget = QtGui.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
widget_1 = Abc(self.stacked_widget)
widget_2 = Xyz(self.stacked_widget)
self.stacked_widget.addWidget(widget_1)
self.stacked_widget.addWidget(widget_2)
self.showMaximized()
class Abc(QtGui.QWidget):
def __init__(self, stacked_widget, parent=None):
super(Abc, self).__init__(parent)
self.stacked_widget = stacked_widget
self.frame = QtGui.QFrame()
self.frame_layout = QtGui.QVBoxLayout()
self.button = QtGui.QPushButton('Click me!')
self.button.clicked.connect(self.click)
self.frame_layout.addWidget(self.button)
self.frame.setLayout(self.frame_layout)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.frame)
self.setLayout(self.layout)
self.showMaximized()
def click(self):
print("You clicked me!")
self.stacked_widget.setCurrentIndex(1)
class Xyz(QtGui.QWidget):
def __init__(self, parent=None):
super(Xyz, self).__init__(parent)
self.frame_layout = QtGui.QStackedLayout()
self.page1 = Page("Page 1", self.frame_layout)
self.page2 = Page("Page 2", self.frame_layout)
self.frame_layout.addWidget(self.page1)
self.frame_layout.addWidget(self.page2)
class Page(QtGui.QWidget):
def __init__(self, text, frame_layout, parent=None):
super(Page, self).__init__(parent)
print(self.width(), self.height())
self.frame_layout = frame_layout
self.frame = QtGui.QFrame()
self.frame_layout = QtGui.QVBoxLayout()
self.frame.setStyleSheet("background-color: rgb(191, 191, 191)")
self.label = QtGui.QLabel()
self.label.setText(text)
self.frame_layout.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
self.frame.setLayout(self.frame_layout)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.frame)
self.layout.setContentsMargins(0,0,0,0)
self.setLayout(self.layout)
self.showMaximized()
print(self.width(), self.height())
if __name__ == "__main__":
app = QtGui.QApplication([])
window = Window()
window.show()
sys.exit(app.exec_())
The main problem is that you are not setting the QStackedLayout for the Xyz widget, the result is that all pages will actually appear as top level windows.
When a widget is added to a layout, it takes ownership of it; if the layout is already set to a widget, then the widget that was added to the layout becomes reparented to the other. The same happens if you set the layout afterwards.
Why does it show the first page as a separate window? And why doesn't it show the second?
When a new widget is created without a parent, it becomes a top level window; when a widget is added to a new stacked layout, Qt automatically tries to show it; you didn't set the layout to anything (which would reparent it as explained before), and the result is that the first page is shown as a standalone window.
Now, since the first "screen" is going to be shown only the first time, you can set that widget as the central widget, and then set a Xyz instance (which is actually a QStackedWidget subclass) as a new central widget.
Note that you don't need to use QWidget to add a QFrame if that's the only parent widget shown: you can just subclass QFrame.
This is a much simpler and cleaner version of your code:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.startPage = Abc()
self.setCentralWidget(self.startPage)
self.startPage.startRequest.connect(self.buildPages)
def buildPages(self):
self.pages = Xyz()
self.setCentralWidget(self.pages)
class Abc(QtGui.QFrame):
startRequest = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Abc, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
self.button = QtGui.QPushButton('Click me!')
self.button.clicked.connect(self.startRequest)
layout.addWidget(self.button)
class Xyz(QtGui.QStackedWidget):
def __init__(self, parent=None):
super(Xyz, self).__init__(parent)
self.page1 = Page("Page 1")
self.page2 = Page("Page 2")
self.addWidget(self.page1)
self.addWidget(self.page2)
self.page1.switchRequest.connect(lambda: self.setCurrentIndex(1))
self.page2.switchRequest.connect(lambda: self.setCurrentIndex(0))
class Page(QtGui.QFrame):
switchRequest = QtCore.pyqtSignal()
def __init__(self, text, parent=None):
super(Page, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
# set the background only for QFrame subclasses (which also includes
# QLabel), this prevents setting the background for other classes,
# such as the push button
self.setStyleSheet('''
QFrame {
background-color: rgb(191, 191, 191)
}
''')
# when adding a widget to a layout, the layout tries to automatically
# make it as big as possible (based on the widget's sizeHint); so you
# should not use the alignment argument for layout.addWidget(), but for
# the label instead
self.label = QtGui.QLabel(text, alignment=QtCore.Qt.AlignCenter)
layout.addWidget(self.label)
self.switchButton = QtGui.QPushButton('Switch')
layout.addWidget(self.switchButton)
self.switchButton.clicked.connect(self.switchRequest)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Common buttons and positioning in PyQt5's QStackedLayout

I am creating a Python PyQt5 app for a university project, which uses QStackedLayout to keep the app single-windowed.
First question: how can I create buttons that appear on every window and have the same function and property without having to recreate them in every window's UI setup (like in the code)?
Second question: after switching windows, how can I open the newly opened window at the previous's position? Right now they just open at the centre of the screen. I assume pos() or QPoint should be used but I can not figure out how.
import sys
from PyQt5.QtWidgets import (QApplication,
QMainWindow,
QPushButton,
QWidget,
QStackedLayout)
class Ui(QWidget):
def setupUi(self, Main):
self.application_width = 200
self.application_height = 200
self.stack = QStackedLayout()
self.window_1 = QWidget()
self.window_2 = QWidget()
self.window_1_UI()
self.window_2_UI()
self.stack.addWidget(self.window_1)
self.stack.addWidget(self.window_2)
def window_1_UI(self):
self.window_1.setFixedSize(self.application_width, self.application_height)
self.window_1.setWindowTitle("1")
'''REPLACE THIS BUTTON'''
self.window_1_button = QPushButton("Change window", self.window_1)
def window_2_UI(self):
self.window_2.setFixedSize(self.application_width, self.application_height)
self.window_2.setWindowTitle("2")
'''AND REPLACE THIS BUTTON'''
self.window_2_button = QPushButton("Change window", self.window_2)
class Main(QMainWindow, Ui):
def __init__(self):
super(Main, self).__init__()
self.setupUi(self)
self.window_1_button.clicked.connect(self.change_window)
self.window_2_button.clicked.connect(self.change_window)
def change_window(self):
if self.stack.currentIndex() == 0:
self.stack.setCurrentIndex(1)
else:
self.stack.setCurrentIndex(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
M = Main()
sys.exit(app.exec())
Put your button outside your widgets (in your Main widget). The Ui class should manage the stacked layout.
For example:
class Ui(QWidget):
def setupUi(self, Main):
self.stack = QStackedLayout()
self.window_1 = QWidget()
self.window_2 = QWidget()
self.window_1_UI()
self.window_2_UI()
self.stack.addWidget(self.window_1)
self.stack.addWidget(self.window_2)
# Only one button
self.btn = QPushButton("Change window", self)
# Create the central widget of your Main Window
self.main_widget = QWidget()
layout = QVBoxLayout(self.main_widget)
layout.addLayout(self.stack)
layout.addWidget(self.btn)
self.setCentralWidget(self.main_widget)
self.btn.clicked.connect(self.change_window)
def change_window(self):
if self.stack.currentIndex() == 0:
self.stack.setCurrentIndex(1)
else:
self.stack.setCurrentIndex(0)
def window_1_UI(self):
label = QLabel("In Window 1", self.window_1)
def window_2_UI(self):
label = QLabel("In Window 2", self.window_2)
class Main(QMainWindow, Ui):
def __init__(self):
super(Main, self).__init__()
self.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
M = Main()
M.show()
sys.exit(app.exec())

PyQt: switch windows/layouts created by Qt Designer

I am creating an app using PyQt4. I have created two interfaces with Qt Designer. When a button is pushed I would like to switch between one layout and the other.
A sample of my code is:
from PyQt4 import QtGui, uic
form_class = uic.loadUiType("sample.ui")[0]
form_class2 = uic.loadUiType("sample2.ui")[0]
class SecondLayout(form_class2, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
form_class2.setupUi(self)
class MainWindow(form_class, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.btn.clicked.connect(self.open_new_window)
def open_new_window(self):
self.Window = SecondLayout()
# here I would like to switch the layout with a layout of self.Window
app = QtGui.QApplication(sys.argv)
myWindow = MainWindow(None)
myWindow.show()
app.exec_()
I have done a lot of searching and reading about QStackedLayout, but haven't been able to get it to work with layouts created in Qt Designer.
My Question is how would I be able to have one Main Window and switch its central widget but i'm not sure if that would work for the seperate menus. I have defined all the menus and widgets and status bars, etc. in Qt Designer as two different projects(both main windows) so I would like to have the main program in one of the main windows, then at some point create an instance of the second main window and switch the layout and all the widgets, menus, text edits, etc. I tried using setCentralWidget but hasn't worked for me.
Could someone please explain to me how to do this.
It sounds like you have two completely separate main windows. There is really no point in switching all the widgets, menus, toolbars, etc, because they will have no shared code. You might just as well simply hide one window, and then show the other one.
Here is a simple demo that shows one way to do that:
PyQt5
from PyQt5 import QtWidgets
class Window1(QtWidgets.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtWidgets.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())
PyQt4
from PyQt4 import QtCore, QtGui
class Window1(QtGui.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtGui.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())

Call setCentralWidget from other file

I have different files (main.py and layout.py) and I want to change the windows (I have shortened the example that it should change the window size) of QMainWindow from the file layout.py.
It works fine from main.py, I can change the windows from the file main.py, but it has no effect in layout.py.
UPDATE: I changed the files two a working example with the problem that the Button "Switch to Layout 2" does not work.
main.py
import sys
from PyQt5.QtWidgets import QAction, QApplication, QMainWindow
from layout import Layout1, Layout2
class MainClass(QMainWindow):
def __init__(self):
super(MainClass, self).__init__()
def initUI(self):
self.setGeometry(50, 100, 600, 500)
self.setWindowTitle('program')
self.window1Action = QAction('Window1', self)
self.window1Action.triggered.connect(self.window1)
self.window2Action = QAction('Window2', self)
self.window2Action.triggered.connect(self.window2)
self.menubar = self.menuBar()
menu = self.menubar.addMenu('&Menu')
menu.addAction(self.window1Action)
menu.addAction(self.window2Action)
self.show()
def window1(self):
wsize1 = (1200, 600)
self.resize(*wsize1)
self.form_widget = Layout1()
self.setCentralWidget(self.form_widget)
def window2(self):
wsize2 = (600, 500)
self.resize(*wsize2)
self.form_widget = Layout2()
self.setCentralWidget(self.form_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainClass()
ex.initUI()
sys.exit(app.exec_())
layout.py
from PyQt5.QtWidgets import QFormLayout, QPushButton, QWidget
class Layout1(QWidget):
def __init__(self, parent=None):
super(Layout1, self).__init__(parent)
self.form_layout = QFormLayout(self)
self.button1 = QPushButton('Button1')
self.form_layout.addRow('nonfunctional', self.button1)
self.buttonX = QPushButton('Switch to Layout2')
self.form_layout.addRow('Problem', self.buttonX)
self.buttonX.clicked.connect(self.change_layout)
self.setLayout(self.form_layout)
def change_layout(self):
from main import MainClass
self.change_window = MainClass()
self.change_window.window2()
class Layout2(QWidget):
def __init__(self, parent=None):
super(Layout2, self).__init__(parent)
self.form_layout = QFormLayout(self)
self.button2 = QPushButton('Button3')
self.form_layout.addRow('nonfunctional', self.button2)
self.setLayout(self.form_layout)
Can anybody explain to me what I have done wrong?
Your Layout classes have a parent parameter, so use it. You need to get a reference to the existing instance of the main window, not create a new one:
def window1(self):
...
self.form_widget = Layout1(self)
self.setCentralWidget(self.form_widget)
...
def change_layout(self):
self.parent().window2()

Categories

Resources