'Use PyQt5 to display multiple images choosed from file but failed

I want to select multiple images from a file and display them, but when I click my select button, the images are not displayed.

I used the scrollarea component in PyQt5 to do this, but it failed. How can I solve this problem?

This is a class I designed, in which the height of QWdiget needs to be calculated before scrolling

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QVBoxLayout, QGridLayout, QScrollArea, QApplication, QPushButton,
                             QFileDialog)
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import (Qt, QSize)

class Picture(QWidget):
    
    def __init__(self, parent=None, pwidth=980, pheight=350):
        super().__init__(parent)
        self.mywidth = pwidth
        self.myheight = pheight
        self.rowheight = 230  # the height of one row
        self.labelwidth = 180  # 
        self.labelheight = 200  # 
        self.row_picnum = 5  #  the number of picture displayed per row
        
        self.setFixedSize(pwidth, pheight)
        layout = QGridLayout()
        self.setLayout(layout)

        # init the display area
        self.sc = QScrollArea(self)
        self.qw = QWidget(self)
        self.sc.setWidget(self.qw)
        self.qw.setMinimumSize(self.mywidth, self.myheight)
        self.sc.setMinimumSize(self.mywidth, self.myheight)

        btn = QPushButton(self)
        btn.clicked.connect(self.showimage)

     def showimage(self):
        imgName, imgType = QFileDialog.getOpenFileNames(self)
        print(imgName)

        image_address = imgName
        # get the number of image
        if image_address is not None:
            total = len(image_address)
        else:
            total = 0
        
        #  calculate the row number needed
        print(total)
        if total % self.row_picnum == 0:
            rows = int(total / self.row_picnum)
        else:
            rows = int(total / self.row_picnum) + 1

        # display the image one by one
        for i in range(total):
            # set the image
            per_picture = image_address[i]
            photo = QPixmap(per_picture)
            width = photo.width()
            height = photo.height()
            tmp_image = photo.toImage()
            size = QSize(width, height)
            photo.convertFromImage(tmp_image.scaled(size, Qt.IgnoreAspectRatio))

            #  init the widget used by image
            tmp = QWidget(self.qw)
            vl = QVBoxLayout()

            # use the label to display image
            label = QLabel()
            label.setFixedSize(self.labelwidth, self.labelheight)
            label.setStyleSheet("border:1px solid gray")  # 设置每个标签的样式
            label.setPixmap(photo)
            label.setScaledContents(True)
        
            vl.addWidget(label)

            tmp.setLayout(vl)
            tmp.move(190 * (i % self.row_picnum), self.rowheight * int(i / self.row_picnum))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    pic = Picture()
    pic.show()
    sys.exit(app.exec_())


Solution 1:[1]

There are a few problems with your UI. First there is no layout, you initialize one but you never add anything to it so all your widgets are just floating up to the top left corner of the screen. Second you setting the Main QWidget, the scroll area and the inner scroll area all to be the same height and width, which is impossible since they are each nested within one another. Lastly when you create your image labels. you create an layout and widget for them but that's it so they are either overwritten on the next loop or they are just floating too.

Below is an example of what you could do with the layouts to at least make the images appear in the widget. It should at least point you in the right direction.

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QVBoxLayout, QGridLayout, QScrollArea, QApplication, QPushButton, QHBoxLayout,
                             QFileDialog)
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import (Qt, QSize)

class Picture(QWidget):

    def __init__(self, parent=None, pwidth=980, pheight=350):
        super().__init__(parent)
        self.mywidth = pwidth
        self.myheight = pheight
        self.rowheight = 230  # the height of one row
        self.labelwidth = 180  #
        self.labelheight = 200  #
        self.row_picnum = 5  #  the number of picture displayed per row

        self.setFixedSize(pwidth, pheight)
        layout = QGridLayout()
        self.setLayout(layout)

        # init the display area
        self.sc = QScrollArea(self)
        self.sc_layout = QHBoxLayout()
        self.sc.setLayout(self.sc_layout)
        # self.sc.setMinimumSize(self.mywidth, self.myheight)
        btn = QPushButton(self)
        btn.clicked.connect(self.showimage)
        layout.addWidget(self.sc, 0, 0)
        layout.addWidget(btn, 1, 0)

    def showimage(self):
        imgName, imgType = QFileDialog.getOpenFileNames(self)
        print(imgName)

        image_address = imgName
        # get the number of image
        if image_address is not None:
            total = len(image_address)
        else:
            total = 0

        #  calculate the row number needed
        print(total)
        if total % self.row_picnum == 0:
            rows = int(total / self.row_picnum)
        else:
            rows = int(total / self.row_picnum) + 1

        # display the image one by one
        for i in range(total):
            # set the image
            per_picture = image_address[i]
            photo = QPixmap(per_picture)
            width = photo.width()
            height = photo.height()
            tmp_image = photo.toImage()
            size = QSize(width, height)
            photo.convertFromImage(tmp_image.scaled(size, Qt.IgnoreAspectRatio))
            tmp = QWidget(self)
            tmp_layout = QVBoxLayout()
            tmp.setLayout(tmp_layout)
            # use the label to display image
            label = QLabel()
            label.setFixedSize(self.labelwidth, self.labelheight)
            label.setStyleSheet("border:1px solid gray")  # ?????????
            label.setPixmap(photo)
            label.setScaledContents(True)
            self.sc_layout.addWidget(tmp)
            tmp_layout.addWidget(label)
            tmp.move(190 * (i % self.row_picnum), self.rowheight * int(i / self.row_picnum))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    pic = Picture()
    pic.show()
    sys.exit(app.exec_())


Solution 2:[2]

A nested Start-Process should work. Lasse V. Karlsen suggestion would be the recommended way to go.

Start-Process powershell -Verb RunAs -ArgumentList @'
    Start-Process 'C:\test\test.bat'
    Start-Process 'C:\test1\test.bat'
    Start-Process 'C:\test2\test.bat'
'@ -Wait

Or with a loop:

Start-Process powershell -Verb RunAs -ArgumentList @'
    'C:\test\test.bat','C:\test1\test.bat','C:\test2\test.bat' |
    ForEach-Object { Start-Process $_ }
'@ -Wait

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 alexpdev
Solution 2