Hamid_Rezaie | 2020-06-17 13:47:19 UTC | #1
Hey guys, I have the following MUC, which produces the following GUI (see Fig: left GUI).
Depending on how many images are selected, TextBoxes appear dynamically. The name of the image appears in these text boxes (see Fig: middle GUI).
Now everything is finde but i want to extend the GUI so that it extracts important parameters from the imagename and prints them right next to the TextBox containing the name in two more TextBoxes (because there are two parameters (height and width)). I know how to extract the parameters, it works. But I do not know how to dynamically add two more TextBoxes horizontally. Then i use the Parameter to calculate the area. But I can't change the MUC so that it dynamically adds the desired TextBox's. It should look like the next image. At first three TextBox's in horizontal position. And if i select for example 3 Images, then in the next two rows should appear the same three TextBox's with particular imagename and parameters (see Fig 3: right GUI).
Here you can see the MUC:
from PyQt5.QtGui import QFont, QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QStyleFactory, QMainWindow, QWidget
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QPushButton
from PyQt5.QtWidgets import QFileDialog, QLineEdit, QTextEdit
from PyQt5.QtWidgets import QGridLayout
from PyQt5.QtWidgets import QListView
from os import path as osPath
# Note this would most likely need a means to either re-size
# the window or better yet have a Scroll Area added to it
class OutWithLineEdits(QWidget):
def __init__(self, parent):
QWidget.__init__(self)
self.Parent = parent
self.LneEdts = {}
self.LneEdts[0] = QLineEdit()
self.PrimrSet = False
self.LstIndx = 0
self.EditBox = QVBoxLayout()
self.EditBox.addWidget(self.LneEdts[0])
self.setLayout(self.EditBox)
def SetImage(self, Text, Indx):
print('Setting Image ', Indx, ')', Text)
if Indx not in self.LneEdts.keys():
self.LneEdts[Indx] = QLineEdit()
self.EditBox.addWidget(self.LneEdts[Indx])
self.LneEdts[Indx].setText(Text)
# So here is how to make that (or any) GUI using straight Python-Qt
class LoadUI(QWidget):
def __init__(self, parent):
QWidget.__init__(self)
self.Parent = parent
self.FileNameLst = []
self.btnOpnImg = QPushButton('Open Image')
self.btnOpnImg.clicked.connect(self.LoadImage)
HBox1 = QHBoxLayout()
HBox1.addWidget(self.btnOpnImg)
HBox1.addStretch(1)
Font = QFont()
Font.setPointSize(16)
Font.setBold(True)
lblSelectd = QLabel('Your Selected Images:')
lblSelectd.setFont(Font)
HBox2 = QHBoxLayout()
HBox2.addWidget(lblSelectd)
HBox2.addStretch(1)
# Comment-Out what you do not want to use and Uncomment-Out what you do
# they have been made to be interchangable so you can see what each one
# would look like
# Now displaying the list of selected images could actually be done
# several ways
# 1) Your method of using QLineEdits
self.OutPut = OutWithLineEdits(self)
# 2) Using QLabels instead
#self.OutPut = OutWithLabels(self)
# 3) Using a QTextEdit instead
#self.OutPut = OutWithTextEdit(self)
# 4) Using a QListView instead
#self.OutPut = OutWithListView(self)
VBox = QVBoxLayout()
VBox.addLayout(HBox1)
VBox.addLayout(HBox2)
VBox.addWidget(self.OutPut)
VBox.addStretch(1)
self.setLayout(VBox)
# This is just a simple redirect or pass through method used for
# ease of reading as well as implementation as modifying is very
# easy later on
@pyqtSlot()
def LoadImage(self):
FileData, NotUsed = QFileDialog.getOpenFileNames(self, 'Select Multi File', 'default', 'All Files (*)')
if len(FileData) > 0:
# Enumeration was unnecessary, especially since it was not used
for FileItem in FileData:
# Extract the File Name
BaseName = osPath.basename(FileItem)
self.FileNameLst.append(BaseName)
if not self.OutPut.PrimrSet:
self.OutPut.PrimrSet = True
Indx = 0
else:
self.OutPut.LstIndx += 1
Indx = self.OutPut.LstIndx
self.OutPut.SetImage(BaseName, Indx)
# Keep your Main Window simple let it handle those things that are outside your
# actual Graphic User Interface such MenuToolBar, StatusBar, and Dockable Windows
# if you use any of these
class Fenster(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('Image Selector')
WinLeft = 550;
WinTop = 150;
WinWidth = 350;
WinHigh = 300
self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh)
# The Center Pane is your actual Main Graphic User Interface
self.CenterPane = LoadUI(self)
self.setCentralWidget(self.CenterPane)
self.StatBar = self.statusBar()
def DsplyStatMsg(self, MsgTxt):
self.StatBar.showMessage(MsgTxt)
######MAIN####################
if __name__ == "__main__":
# Unless you plan to do something with Command Line arguments no need
# to include this and if you are you are better off using argparse
# library as it handles Command Line arguments much more cleanly
# app = QApplication(sys.argv)
MainEventThred = QApplication([])
MainApplication = Fenster()
MainApplication.show()
# This is the Qt4 method of doing this
# sys.exit(app.exec_())
# While this is the Qt5 method for doing this
MainEventThred.exec() ```
Luca | 2020-06-17 15:36:16 UTC | #2
Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!
I wrote an example using a QGridLayout:
from PyQt5.QtWidgets import *
import sys
import os
class ImageInfo():
def __init__(self, index, filename, width, height, parent):
self.parent = parent
self.lineEditName = self.addLineEdit(filename, index, 0)
self.lineEditWidth = self.addLineEdit(0, index, 1)
self.lineEditHeight = self.addLineEdit(0, index, 2)
def addLineEdit(self, text, row, col):
lineEdit = QLineEdit(parent=self.parent)
lineEdit.setText(str(text))
self.parent.layout().addWidget(lineEdit, row, col)
return lineEdit
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QGridLayout()
self.widget.setLayout(self.layout)
self.imagesInfo = []
paths, _ = QFileDialog.getOpenFileNames(self, 'Select Multi File', 'default', 'All Files (*)')
for index, path in enumerate(paths):
filename, width, height = self.getImageInfo(path)
self.imagesInfo = ImageInfo(index, filename, width, height, parent=self.widget)
def getImageInfo(self, path):
filename = os.path.basename(path)
width, height = self.getImageSize(path)
return filename, width, height
def getImageSize(self, path):
width, height = (0, 0) # Add your function
return width, height
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
sys.exit(app.exec_())
An alternative could be: Change the layout into a QVBoxLayout Set ImageInfo class as a subclass of QWidget * Add the QLineEdits to a QHBoxLayout inside the ImageInfo class
Or another one using a QViewTable where each row is an image.
There are multiple solutions, that could be better, this was just a simple example to show you the concept.
PyQt6 Crash Course — a new tutorial in your Inbox every day
Beginner-focused crash course explaining the basics with hands-on examples.