Итак, я создаю браузер галереи изображений в PYQT5. Я могу выбрать каталог и загрузить значки файлов изображений в виджет с возможностью прокрутки следующим образом:
Если в папке меньше 20 изображений или около того каталог, он работает нормально. Однако, когда их больше, метки изображений по какой-то причине не отображаются:
Если я возьму несколько изображений, которые не показывать и помещать их в новую папку самостоятельно, затем попробуйте загрузить только эти изображения, это работает, только если приложение еще не пыталось загрузить их заранее и не удалось, в противном случае снова появится пустой квадрат.
Так мне кажется, это какое-то ограничение фреймворка / памяти? Может кто-нибудь пролить некоторый свет на это? Вот мой код:
# MainWindow Set-Up : Creating Widgets and Layouts
class ClassUi(object):
def setup(self, MainW):
MainW.setObjectName("MainW")
MainW.resize(400,500)
self.mainlayout = QtWidgets.QVBoxLayout()
self.centralwidget = QtWidgets.QWidget(MainW)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy)
self.centralwidget.setLayout(self.mainlayout)
MainW.setCentralWidget(self.centralwidget)
#direcwidget is a container widget for the top part of the program where a directory is chosen
self.direcwidget = QtWidgets.QWidget()
self.direclayout = QtWidgets.QGridLayout()
self.direcwidget.setLayout(self.direclayout)
self.mainlayout.addWidget(self.direcwidget)
self.opdirbut = QtWidgets.QPushButton() #Button that opens directory dialog when pressed
self.opdirbut.setText("Choose")
self.opdirbut.setFixedSize(50,50)
self.linepath = QtWidgets.QLineEdit() #Line Edit that displays current directory
self.linepath.setText(os.getcwd())
self.backpath = QtWidgets.QPushButton() #Button that changes directory to parent directory of the current one
self.backpath.setFixedSize(20,20)
self.backpath.setText("^")
#Positioning of widgets inside widget container direcwidget
self.direclayout.addWidget(self.opdirbut, 0,0, 2, 1)
self.direclayout.addWidget(self.linepath, 0,2, 1, 3)
self.direclayout.addWidget(self.backpath, 1,4, 1, 1)
#Scrollwidget is the area wherein a container widget widgetforscroll holds all image icons in a grid
self.scrollwidget = QtWidgets.QScrollArea()
self.mainlayout.addWidget(self.scrollwidget)
self.scrollwidget.setWidgetResizable(True)
self.scrollwidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollgrid = QtWidgets.QGridLayout()
self.widgetforscroll = QtWidgets.QWidget()
self.widgetforscroll.setLayout(self.scrollgrid)
self.scrollwidget.setWidget(self.widgetforscroll)
#Contains logic of program
class MainWindow(QtWidgets.QMainWindow, ClassUi):
def __init__(self):
super().__init__()
self.setup(self)
#Counter variables for keeping track of where to layout items
self.picturerow = 0
self.picturecolumn = 0
self.howmany = 0
#Assigns class methods to directory buttons
self.opdirbut.clicked.connect(self.opdial)
self.backpath.clicked.connect(self.uppath)
# Each time this function is called, a new widget called newwidget is created containing "pic" in a pixmap label and a text label and layed out
# on the widgetforscroll widget through its scrollgrid layout. Each time the function is called, picture column increments by one at the end of the function
# when all the columns in a row are filled, picture column is reset to 0 and and picture row is incremented. Picture row and picture column are used in positioning
# the newwidgets in the scrollgrid.
def addpicture(self, pic):
if self.picturecolumn == 3:
self.picturecolumn = 0
self.picturerow += 1
self.howmany += 1
#newwidget is object of picwidg class containing pixmap and text label
newwidget = picwidg(self.howmany, pic)
#This function was not required to be created, it was only created for the purpose of the Qtimer singleshot implementation.
#The newwidget is being positioned on the scrollgrid layout here.
def addnewone(lyout,nw,rw,cl):
lyout.addWidget(nw, rw, cl)
QtCore.QTimer.singleShot(
self.howmany*500,
lambda sc=self.scrollgrid, nr = newwidget, ow = self.picturerow, mn=self.picturecolumn : addnewone(sc,nr,ow,mn)
)
#Incrementing column by 1 for the next time function is called
self.picturecolumn += 1
#This is the function connected to the choose dialog button. It opens a QFileDialog window which allows you to only choose a directory folder.
#When the folder is chosen:
# 1: The linepath text is set the to the new directory
# 2: Any previous picwidg objects are cleared from the scrollgrid layout
# 3: Picture column and picture row variables are reset for positioning
# 4: A for loop scans the new directory for files with .jpg or .png extensions
# 5: The addpicture method is called with the filename as the argument
def opdial(self):
dialogbox = dialog()
try:
os.chdir(dialogbox.getExistingDirectory(options=QtWidgets.QFileDialog.DontUseNativeDialog))
self.linepath.setText(os.getcwd())
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn =0
self.picturerow =0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
except:
pass
#This is the function for reaching the parent directory. It works very similar to the above function, the only difference
#being that instead of grabbing a new directory from a QFileDialog, the directory processed is taken from the current linepath text
#and goes to the parent directory instead, then removes widgets from the scrolllayout and adds new pictures to the scrolllayout
def uppath(self):
newpath = os.path.dirname(self.linepath.text())
os.chdir(newpath)
self.linepath.setText(newpath)
for i in reversed(range(self.scrollgrid.count())):
widgetToRemove = self.scrollgrid.itemAt(i).widget()
# remove it from the layout list
self.scrollgrid.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
self.picturecolumn = 0
self.picturerow = 0
self.howmany = 0
for a, b, c in os.walk(os.getcwd()):
for i in c:
# print(i[-4:].lower())
if i[-4:].lower() == ".png" or i[-4:].lower() == ".jpg":
self.addpicture(i)
# This is the class where newwidget instances are created
# Here 2 labels are created, one for the image, one for the text and packed in a vertical layout
class picwidg(QtWidgets.QWidget):
whoshover = None
picwidglist =[]
def __init__(self, numb, pic):
super().__init__()
self.setMouseTracking(True)
self.numb = numb
self.pic = pic
picwidg.picwidglist.append(self)
SizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
newwidgetlayout = QtWidgets.QVBoxLayout()
self.setLayout(newwidgetlayout)
self.setSizePolicy(SizePolicy)
self.setMinimumSize(QtCore.QSize(115, 140))
self.setMaximumSize(QtCore.QSize(115, 140))
#Pic Label
self.newpic = QtWidgets.QLabel()
QtCore.QTimer.singleShot(self.numb*500, self.addingnewpic)
self.newpic.setScaledContents(True)
self.newpic.setSizePolicy(SizePolicy)
self.newpic.setGeometry(0, 0, 100, 100)
self.newpic.setStyleSheet("border:1px solid gray")
#Picture text label
self.newtext = QtWidgets.QLabel()
font_metrics = QtGui.QFontMetrics(self.font())
self.newtext.setAlignment(QtCore.Qt.AlignCenter)
elided_text = font_metrics.elidedText(pic, QtCore.Qt.ElideRight, 100)
self.newtext.setText(elided_text)
newwidgetlayout.addWidget(self.newpic)
newwidgetlayout.addWidget(self.newtext)
def addingnewpic(self):
self.newpic.setPixmap(QtGui.QPixmap(self.pic))
#Class for QFileDialog for selecting only directories
class dialog(QtWidgets.QFileDialog):
def __init__(self):
super().__init__()
self.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
self.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
self.setOption(QtWidgets.QFileDialog.ShowDirsOnly, False)
if __name__ == "__main__" :
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())