PyQt5 changing images - python

I'm trying to make a player for a custom file in PyQT5 and I have a set of images that I want to render in a PyQt widget one after another so I can play it as a continious video. So my question is how can I do something like that? Some code example or a guide would be great. Thank you.
EDIT:
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.scene = QGraphicsScene()
self.pixmap = QGraphicsPixmapItem()
self.scene.addItem(self.pixmap)
self.initUI().graphicsView.setScene(self.scene)
self.initUI()
def initUI(self):
graphicsView = QGraphicsView()
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Test')
self.show()

In your widget, you can add a QGraphicsVew, add a QGraphicsScene to the graphicsview, add a pixmap to the scene and continuously change the pixmap through setPixmap() function.
So in the constructor of your widget, add these (it is assumed that your .ui file has a QGraphicsView called graphicsView):
self.scene = QtWidgets.QGraphicsScene()
self.pixmap = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.pixmap)
self.ui.graphicsView.setScene(self.scene)
In your player function, which is called periodically, you set the pixmap:
self.t1_pixmap.setPixmap(img)
where img contains the pixmap loaded from your image files.
Update (based on the code given, and a correction):
import sys
from PyQt5 import QtWidgets, QtGui
class Example(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.initUI()
def initUI(self):
graphicsView = QtWidgets.QGraphicsView(self)
scene = QtWidgets.QGraphicsScene()
self.pixmap = QtWidgets.QGraphicsPixmapItem()
scene.addItem(self.pixmap)
graphicsView.setScene(scene)
self.setGeometry(300, 300, 300, 200)
graphicsView.resize(300,200)
self.setWindowTitle('Test')
self.show()
def play(self):
img = QtGui.QPixmap('D:\\tmp\\image.png')
self.pixmap.setPixmap(img)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Example()
window.play()
app.exec()
sys.exit()

Related

Access A Variable from another class in PyQt5

In PyQt5, I've wrote a GUI. Basically, when a button is pressed, it open a new window, where choose an item from a list. What I want is that after you close the new window, the item you chose appears as text on the first window. It's a hard to explain.
This is the code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class Add(QtWidgets.QMainWindow):
def __init__(self):
super(Add, self).__init__()
#Set The UI
self.initUI()
#Set The GUI Position And Size
self.setGeometry(1050, 500, 400, 50)
#Set The GUI Title
self.setWindowTitle("Add")
def initUI(self):
Central = QtWidgets.QWidget(self)
self.setCentralWidget(Central)
self.deckButton = QtWidgets.QPushButton(self)
self.deckButton.setText("Choose")
self.deckButton.clicked.connect(self.open_deck_browser)
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.deckButton, 1)
Central.setLayout(hbox)
def open_deck_browser(self):
self.w = SetDeck()
self.w.show()
class SetDeck(QtWidgets.QMainWindow):
def __init__(self):
super(SetDeck, self).__init__()
#Set The UI
self.initUI()
#Set The GUI Position And Size
self.setGeometry(200, 200, 800, 640)
#Set The GUI Title
self.setWindowTitle("Choose Deck")
def initUI(self):
widAddToDeckWindow = QtWidgets.QWidget(self)
self.setCentralWidget(widAddToDeckWindow)
#Create The List Widget
self.deckList = QtWidgets.QListWidget()
self.deckList.insertItem(0, "Hello")
self.deckList.insertItem(1, "Hi")
self.deckList.insertItem(2, "Hello There")
self.deckList.item(0).setSelected(True)
self.deckList.itemSelectionChanged.connect(self.show_List)
print([x.row() for x in self.deckList.selectedIndexes()])
#Create The Select Deck Button
self.selectDeck = QtWidgets.QPushButton(self)
self.selectDeck.setText("Choose")
hboxCreateBottomButtons = QtWidgets.QHBoxLayout()
hboxCreateBottomButtons.addStretch()
hboxCreateBottomButtons.addWidget(self.selectDeck)
#Create The Main VBox
vboxMain = QtWidgets.QVBoxLayout()
vboxMain.addWidget(self.deckList)
vboxMain.addLayout(hboxCreateBottomButtons)
widAddToDeckWindow.setLayout(vboxMain)
def show_List(self):
print(repr(self.deckList.selectedItems()[0].text()))
def window():
app = QtWidgets.QApplication(sys.argv)
win = Add()
win.show()
sys.exit(app.exec_())
window()
I've tried using global variables, but it didn't work.
First of all, I recommend you improve your style when naming variables as they make reading easier, for example that the class name are nouns and not a verb.
Getting to the bottom of the problem, never use (or try to use) global variables as they cause silent bugs if there is a better option and you don't understand how it works. In the case that you want a window where you ask the user to provide information on how to select an option that will then be used in the main window then it is advisable to use a QDialog. In the following example, this is done and the "Choose" button is linked to the accept slot so that it closes the window, and that information can be used to know that the "x" button of the window was not closed. Also I have created a property that has the selected text.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
self.setGeometry(1050, 500, 400, 50)
self.setWindowTitle("Add")
def initUI(self):
central = QtWidgets.QWidget(self)
self.setCentralWidget(central)
self.deckButton = QtWidgets.QPushButton()
self.deckButton.setText("Choose")
self.deckButton.clicked.connect(self.open_deck_browser)
box = QtWidgets.QVBoxLayout(central)
box.addWidget(self.deckButton)
self.label = QtWidgets.QLabel()
box.addWidget(self.label)
self.label.hide()
def open_deck_browser(self):
dialog = DeckDialog()
if dialog.exec_() == QtWidgets.QDialog.Accepted:
self.label.show()
self.label.setText(dialog.selected_text)
class DeckDialog(QtWidgets.QDialog):
def __init__(self):
super(DeckDialog, self).__init__()
self.initUI()
self.setGeometry(200, 200, 800, 640)
self.setWindowTitle("Choose Deck")
def initUI(self):
self.deckList = QtWidgets.QListWidget()
self.deckList.insertItem(0, "Hello")
self.deckList.insertItem(1, "Hi")
self.deckList.insertItem(2, "Hello There")
self.deckList.item(0).setSelected(True)
self.selectDeck = QtWidgets.QPushButton(self)
self.selectDeck.setText("Choose")
hboxCreateBottomButtons = QtWidgets.QHBoxLayout()
hboxCreateBottomButtons.addStretch()
hboxCreateBottomButtons.addWidget(self.selectDeck)
vboxMain = QtWidgets.QVBoxLayout(self)
vboxMain.addWidget(self.deckList)
vboxMain.addLayout(hboxCreateBottomButtons)
self.selectDeck.clicked.connect(self.accept)
#property
def selected_text(self):
items = self.deckList.selectedItems()
if items:
return items[0].text()
return ""
def main():
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Click a button to change a GIF

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

Python PyQt4 change image pressing button

I am trying to generate a visualizer where each time you press a button the image in a window change. The image have to be in the same window where the button is and it has to replace the previous image.
So for I am able to show the button and the first image. But I cannot connect the click button with the image updating process.
This is my code so far:
author__ = 'lpp'
#!/usr/bin/python
import os,sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
QtGui.QToolTip.setFont(QtGui.QFont('Test', 10))
self.setToolTip('This is a <b>QWidget</b> widget')
# Show image
pic = QtGui.QLabel(self)
pic.setGeometry(10, 10, 800, 800)
pic.setPixmap(QtGui.QPixmap( "/home/lpp/Desktop/Image1.png"))
# Show button
btn = QtGui.QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.resize(btn.sizeHint())
btn.clicked.connect(self.fun)
btn.move(50, 50)
self.setGeometry(300, 300, 2000, 1500)
self.setWindowTitle('Tooltips')
self.show()
# Connect button to image updating
def fun(self):
#print("Test!!!")
pic = QtGui.QLabel(self)
pic.setGeometry(100, 10, 800, 800)
pic.setPixmap(QtGui.QPixmap( "/home/lpp/Desktop/image2.png"))
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
All but the "def fun" works.
I also tried these functions but it did not work:
def fun(self):
pic = QtGui.QLabel(self)
pic.setGeometry(100, 10, 800, 800)
pic.setPixmap(QtGui.QPixmap( "/home/lpp/Desktop/image2.png"))
return (pic)
def fun(self):
#print("Test!!!")
pic = QtGui.QLabel(self)
pic.setGeometry(100, 10, 800, 800)
pic.setPixmap(QtGui.QPixmap( "/home/lpp/Desktop/image2.png"))
return self.show()
If you want the previous image you should not create a new QLabel, but just update the QPixmap.
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
QtGui.QToolTip.setFont(QtGui.QFont('Test', 10))
self.setToolTip('This is a <b>QWidget</b> widget')
# Show image
self.pic = QtGui.QLabel(self)
self.pic.setGeometry(10, 10, 800, 800)
self.pic.setPixmap(QtGui.QPixmap("/home/lpp/Desktop/image1.png"))
# Show button
btn = QtGui.QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.resize(btn.sizeHint())
btn.clicked.connect(self.fun)
btn.move(50, 50)
self.setGeometry(300, 300, 2000, 1500)
self.setWindowTitle('Tooltips')
self.show()
# Connect button to image updating
def fun(self):
self.pic.setPixmap(QtGui.QPixmap( "/home/lpp/Desktop/image2.png"))
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

How to add a second pixmap to an abstract button when pushed in PySide/PyQt

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.

Overlay text over a specific widget (transparent labels) in pyqt4

Consider the modification of an answer from #ekhumoro as shown below.
There is a mplayer embedded in a QWidget. Now I want overlay some text over the video. But my approach below doesn't work (the background of the label is not transparent such that one sees only the video and the text). Any idea to fix it?
More generally: How can I make transparent labels positioned over custom widgets (in my case the mplayer-widget)?
If it is not possible to achieve exactly what I want, it would be sufficient to have something which just shows freezes the last frame of the video (or a predefined frame) and displays some text over it.
Note that at a later stage I want that the text which overlays the video changes with time, so the solution should have this in mind already.
For transparency things it may be important to note that I use a linux environment and that is should especially work under xmonad.
import mpylayer
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.container = QtGui.QWidget(self)
#self.container.setStyleSheet('background: black')
self.button = QtGui.QPushButton('Open', self)
self.button.clicked.connect(self.handleButton)
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.button)
self.layout.addWidget(self.container)
self.mplayer = mpylayer.MPlayerControl(
'mplayer', ['-wid', str(self.container.winId())])
self.label = QtGui.QLabel('Some text\n and more',self)
self.label.move(100,100)
self.label.setGeometry(200,200,900,300)
#This doesn't work
self.label.setAttribute(QtCore.Qt.WA_TranslucentBackground)
#opacity doesn't work
self.label.setStyleSheet("QLabel {font-size: 100px; opacity:0.5}")
def handleButton(self):
path = QtGui.QFileDialog.getOpenFileName()
if not path.isEmpty():
self.mplayer.loadfile(unicode(path))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
Here is a screenshot how it my non-working approach looks like:
Here is what I want faked with gimp (maybe I should have used a red font color, but that should be just simple css):
Edit
Here is how I tried to adapt X.Jacobs answer to my example. However it doesn't work. Only if I resize the window the overlayed text/lines appear for just a millisecond over the video and then disappears again (in both cases, if the video is running and if it is pausing).
import mpylayer
from PyQt4 import QtGui, QtCore
class overlayLabel(QtGui.QLabel):
def __init__(self, parent=None):
super(overlayLabel, self).__init__(parent)
self.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
self.setText("OVERLAY TEXT")
self.setStyleSheet("QLabel {font-size: 100px;}")
self.setGeometry(200,200,900,300)
class overlay(QtGui.QWidget):
def __init__(self, parent=None):
super(overlay, self).__init__(parent)
palette = QtGui.QPalette(self.palette())
palette.setColor(palette.Background, QtCore.Qt.transparent)
self.setPalette(palette)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), QtGui.QBrush(QtGui.QColor(255, 255, 255, 27)))
painter.drawLine(self.width()/8, self.height()/8, 7*self.width()/8, 7*self.height()/8)
painter.drawLine(self.width()/8, 7*self.height()/8, 7*self.width()/8, self.height()/8)
painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.container = QtGui.QWidget(self)
#self.container.setStyleSheet('background: black')
self.button = QtGui.QPushButton('Open', self)
self.button.clicked.connect(self.handleButton)
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.button)
self.layout.addWidget(self.container)
self.mplayer = mpylayer.MPlayerControl(
'mplayer', ['-wid', str(self.container.winId())])
## Both versions don't work:
#self.label = overlay(self.container)
self.label = overlayLabel(self.container)
def handleButton(self):
path = QtGui.QFileDialog.getOpenFileName()
if not path.isEmpty():
self.mplayer.loadfile(unicode(path))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
Checkout this example overlay widget that you can adapt to your needs:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class overlay(QWidget):
def __init__(self, parent=None):
super(overlay, self).__init__(parent)
palette = QPalette(self.palette())
palette.setColor(palette.Background, Qt.transparent)
self.setPalette(palette)
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillRect(event.rect(), QBrush(QColor(255, 255, 255, 127)))
painter.drawLine(self.width()/8, self.height()/8, 7*self.width()/8, 7*self.height()/8)
painter.drawLine(self.width()/8, 7*self.height()/8, 7*self.width()/8, self.height()/8)
painter.setPen(QPen(Qt.NoPen))
class windowOverlay(QWidget):
def __init__(self, parent=None):
super(windowOverlay, self).__init__(parent)
self.editor = QTextEdit()
self.editor.setPlainText("OVERLAY"*100)
self.button = QPushButton("Toggle Overlay")
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.addWidget(self.editor)
self.verticalLayout.addWidget(self.button)
self.overlay = overlay(self.editor)
self.overlay.hide()
self.button.clicked.connect(lambda: self.overlay.setVisible(False) if self.overlay.isVisible() else self.overlay.setVisible(True))
def resizeEvent(self, event):
self.overlay.resize(event.size())
event.accept()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
main = windowOverlay()
main.show()
sys.exit(app.exec_())
To overlay text use something like this:
class overlayLabel(QLabel):
def __init__(self, parent=None):
super(overlayLabel, self).__init__(parent)
self.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
self.setText("OVERLAY TEXT")

Categories

Resources