Search code examples
pythonpyqtpyqt4qlistwidgetqlistwidgetitem

How do I put a QLabel onto on another in a custom QListWidget?


I got this code from here and wanted to modify it for my project. The difference is that my project needs the icon to be on top on another QLabel. This couldn't be achieved using Layouts so i decided to put the 3 QLabels (one for the icon or picture, another for the name and the last for the message) on top on a QWidget but i get an empty window. This is my code. Please don't mind about the sizes used because i just wanted to see the widgets displayed and the edit the sizes.

import sys
from PyQt4 import QtGui, QtCore
from PIL import Image, ImageOps
from PIL.ImageQt import ImageQt


class QCustomQWidget (QtGui.QWidget):
    def __init__ (self, parent = None):
        super(QCustomQWidget, self).__init__(parent)
        # self.textQVBoxLayout = QtGui.QVBoxLayout()
        self.widget = QtGui.QWidget()
        self.widget.setMinimumSize(151, 231)
        self.chatMessage = QtGui.QLabel(self.widget)
        # self.chatMessage.setGeometry(QtCore.QRect(50, 80, 411, 161))
        font = QtGui.QFont()
        font.setFamily('Comic Sans MS')
        font.setPointSize(11)
        self.chatMessage.setFont(font)
        self.chatMessage.setMinimumHeight(40)
        self.chatMessage.setStyleSheet('''
                color: rgb(255, 0, 0);
                border: 1px solid #0089ff;
                border-top-right-radius: 20px;
                border-bottom-right-radius: 20px;
                border-bottom-left-radius: 20px;
                padding-left: 60px;
                padding-top: 3px
            ''')
        self.userName = QtGui.QLabel(self.widget)
        font = QtGui.QFont()
        font.setFamily('Arial Narrow')
        font.setBold(True)
        font.setPointSize(11)
        self.userName.setFont(font)
        self.userName.setFixedHeight(30)
        self.userName.setAlignment(QtCore.Qt.AlignTop)
        self.userName.setStyleSheet('''
                color: rgb(255, 255, 255);
                background-color: #0089ff;
                border: 1px solid #0089ff;
                border-bottom: 0px;
                border-top-right-radius: 20px;
                border-top-left-radius: 20px;
                padding-left: 60px;
            ''')
        # self.textQVBoxLayout.addWidget(self.userName)
        # self.textQVBoxLayout.addWidget(self.chatMessage)
        # self.allQHBoxLayout  = QtGui.QHBoxLayout()
        self.iconQLabel      = QtGui.QLabel(self.widget)
        #self.allQHBoxLayout.setSpacing(0)
        #self.allQHBoxLayout.addWidget(self.iconQLabel, 0)
        #self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1)
        #self.setLayout(self.allQHBoxLayout)
        # self.iconQLabel.setFixedSize(60, 60)
        self.userName.setFixedWidth(190)
    def chat_messages (self, text):
        self.chatMessage.setText(text)

    def setTextUp (self, text):
        self.userName.setText(text)

    def setIcon (self, imagePath):
        mask = Image.open('Images\\Mask.png').convert('L')
        image = Image.open('Images\\pro.jpg')
        output = ImageOps.fit(image, mask.size, centering=(0.5, 0.5))
        output.putalpha(mask)
        output.save('pic.png')
        im = Image.open('pic.png')
        size =60, 60
        im.thumbnail(size, Image.LANCZOS)
        im = im.convert('RGBA')
        image1 = ImageQt(im)
        image2 = QtGui.QImage(image1)
        pixmap = QtGui.QPixmap.fromImage(image2)
        self.iconQLabel.setPixmap(QtGui.QPixmap(pixmap))

class exampleQMainWindow (QtGui.QMainWindow):
    def __init__ (self):
        super(exampleQMainWindow, self).__init__()
        self.showMaximized()
        self.myQListWidget = QtGui.QListWidget(self)
        for icon, name, message in [
            ('pic.png', 'Name', 'Message'),
            (pic.png', 'Name', 'Message')]:
            myQCustomQWidget = QCustomQWidget()
            myQCustomQWidget.setTextUp(name)
            myQCustomQWidget.chat_messages(message)
            myQCustomQWidget.setIcon(icon)
            myQListWidgetItem = QtGui.QListWidgetItem(self.myQListWidget)
            myQListWidgetItem.setSizeHint(myQCustomQWidget.sizeHint())
            self.myQListWidget.addItem(myQListWidgetItem)
            self.myQListWidget.setCurrentRow(-1)
            self.myQListWidget.setItemWidget(myQListWidgetItem, myQCustomQWidget)
            self.myQListWidget.scrollToBottom()
            self.myQListWidget.setAutoScrollMargin(15)
            self.myQListWidget.setSelectionRectVisible(False)
            self.myQListWidget.setUniformItemSizes(False)
        self.setCentralWidget(self.myQListWidget)
        self.setMinimumSize(660, 500)

app = QtGui.QApplication([])
window = exampleQMainWindow()
window.show()
sys.exit(app.exec_())

something like this but in different colors it was designed from Qt designer


Solution

  • Your code has 2 errors:

    1. The widgets are located with respect to the parent, if they do not have a parent they will not be shown unless they are the topLevel, such as exampleQMainWindow, the others to be shown must have a parent. in the case of your QCustomQWidget all labels have as their parent a self.widget, and self.widget does not have a parent so it is not displayed and the children are not shown either. The simple solution would be to pass him as a parent of self.widget to self, but checking his code is not necessary to use self.widget so the solution is to eliminate it and pass as a parent to all QLabel to self.

    2. when not using the layouts then sizeHint() returns a value QSize(-1, -1) so it will not show any, it is your duty to set a suitable sizeHint(), in my solution I will place a value that you should change.


    class QCustomQWidget (QtGui.QWidget):
        def __init__ (self, parent = None):
            super(QCustomQWidget, self).__init__(parent)
            # self.textQVBoxLayout = QtGui.QVBoxLayout()
            self.setMinimumSize(151, 231)
            self.chatMessage = QtGui.QLabel(self)
            # self.chatMessage.setGeometry(QtCore.QRect(50, 80, 411, 161))
            font = QtGui.QFont()
            font.setFamily('Comic Sans MS')
            font.setPointSize(11)
            self.chatMessage.setFont(font)
            self.chatMessage.setMinimumHeight(40)
            self.chatMessage.setStyleSheet('''
                    color: rgb(255, 0, 0);
                    border: 1px solid #0089ff;
                    border-top-right-radius: 20px;
                    border-bottom-right-radius: 20px;
                    border-bottom-left-radius: 20px;
                    padding-left: 60px;
                    padding-top: 3px
                ''')
            self.userName = QtGui.QLabel(self)
            font = QtGui.QFont()
            font.setFamily('Arial Narrow')
            font.setBold(True)
            font.setPointSize(11)
            self.userName.setFont(font)
            self.userName.setFixedHeight(30)
            self.userName.setAlignment(QtCore.Qt.AlignTop)
            self.userName.setStyleSheet('''
                    color: rgb(255, 255, 255);
                    background-color: #0089ff;
                    border: 1px solid #0089ff;
                    border-bottom: 0px;
                    border-top-right-radius: 20px;
                    border-top-left-radius: 20px;
                    padding-left: 60px;
                ''')
            # self.textQVBoxLayout.addWidget(self.userName)
            # self.textQVBoxLayout.addWidget(self.chatMessage)
            # self.allQHBoxLayout  = QtGui.QHBoxLayout()
            self.iconQLabel      = QtGui.QLabel(self)
            #self.allQHBoxLayout.setSpacing(0)
            #self.allQHBoxLayout.addWidget(self.iconQLabel, 0)
            #self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1)
            #self.setLayout(self.allQHBoxLayout)
            # self.iconQLabel.setFixedSize(60, 60)
            self.userName.setFixedWidth(190)
        def chat_messages (self, text):
            self.chatMessage.setText(text)
    
        def setTextUp (self, text):
            self.userName.setText(text)
    
        def setIcon (self, imagePath):
            mask = Image.open('Images\\Mask.png').convert('L')
            image = Image.open('Images\\pro.jpg')
            output = ImageOps.fit(image, mask.size, centering=(0.5, 0.5))
            output.putalpha(mask)
            output.save('pic.png')
            im = Image.open('pic.png')
            size =60, 60
            im.thumbnail(size, Image.LANCZOS)
            im = im.convert('RGBA')
            image1 = ImageQt(im)
            image2 = QtGui.QImage(image1)
            pixmap = QtGui.QPixmap.fromImage(image2)
            self.iconQLabel.setPixmap(QtGui.QPixmap(pixmap))
    
        def sizeHint(self):
            return QtCore.QSize(60, 60)