4

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:

non working approach

Here is what I want faked with gimp (maybe I should have used a red font color, but that should be just simple css):

gimp fake

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_())
Community
  • 1
  • 1
student
  • 1,636
  • 3
  • 29
  • 53

1 Answers1

3

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")
  • Thanks, but I don't really understand what it does/how to apply. To me it seems only to make the text gray... The point is that I want to see only the (black) text and the video in the background but not the background of the label which hides some part of the video... – student Dec 26 '12 at 21:21
  • @student see my [updated answer](http://stackoverflow.com/a/14046011/1006989), I modified it to make the overlay more obvious –  Dec 26 '12 at 21:38
  • Thanks. If I understand you correctly the `overlay` class replaces the label in the example from my post and the `QTextEdit` corresponds to my `mplayer` container? If so, how can I just write text within your `overlay` class (instead of drawing some lines)? – student Dec 26 '12 at 21:48
  • @student checkout my [re-updated answer](http://stackoverflow.com/a/14046011/1006989), I added an `overlayLabel` that displays text on top of a `QWidget` –  Dec 26 '12 at 21:56
  • Your solution seems not to work with the mplayer widget from my post. But both (`overlay` and `overlayLabel`) work well with your `QTextEdit` example. – student Dec 26 '12 at 22:07
  • @student Could you update your post with how you adapted the example code? –  Dec 26 '12 at 22:20
  • @student Your code looks fine, it probably has something to do with the video player, sorry can't help you with that, maybe try calling `overlayLabel(self)` instead of `overlayLabel(self.container)`... –  Dec 27 '12 at 01:07
  • If I do `overlayLabel(self)` it looks exactly as in my first screenshot above. – student Dec 27 '12 at 11:09
  • 1
    I don't know how pyQt works for sure, but you may want to look into the autoFillBackground setting for QWidgets, and make sure it is false for your overlay. You may also want to look into some of the related window hints (mentioned in the documentation of the autoFillBackground setting). – Caleb Huitt - cjhuitt Mar 27 '13 at 16:21
  • But how to adjust the size of the label layout according to its text content? – kuanyui Aug 04 '14 at 02:18