Creating dynamic TextBox's
-
Hey guys, I have the following MUC (tanks @Denni-0), which produces the following GUI (see picture).
Depending on how many images are selected, TextBoxes appear dynamically. The name of the image appears in these text boxes.Now I want to extend the GUI so that it extracts important parameters from the name and prints them right next to the TextBox containing the name in two more TextBoxes (because there are two parameters). 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 (see Fig below).
This is the MUC. You can copy it and test it:
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): # One should not use super( ) in Python as it introduces 4 known issues that # then must be handled properly. Further there were still actual bugs within # the usage of super( ) when used in Python as of early this year. So yes # while super( ) works fine within C++ it does not work as seamlessly within # Python due to the major differences between these two languages. Next the # reason it was created was to handle a rather rare issue and unless you are # doing some complicated inheritance you will most likely never run into this # extremely rare issue. However the 4 major issues that get included by using # super( ) are much more likely to occur than that rare issue its meant for to # solve. Of course using the basic explicit method, as follows, does not cause # these issues and is as just as simple as using `super( )` further you do not # actually gain anything useful by using `super( )` in Python that could not be # done in a much safer manner. 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() ```
-
@elias_hh
Please give your widgets (and any other variables) a meaningful name.self.LneEdits
andself.LE
don't help anyone trying to understand the code: something more like, say,leSelectedImages
andleHeights
,leWidths
for the arrays is going to be a lot more helpful for other people, and hopefully you too, to understand what's going on! :)Now that I have got that: your
self.LneEdts[Indx] = QLineEdit() self.LE[Indx] = QLineEdit() self.EditBox.addWidget(self.LneEdts[Indx])
adds the
LneEdts[Indx]
onto theEditBox
widget, but you do nothing at all with theQLineEdit
put intoself.LE[Indx]
. Obviously you must realise that the extra widgets need adding too.Meanwhile, I see
self.EditBox = QVBoxLayout()
, soEditBox
has a vertical layout, onto whichself.LneEdts[Indx]
is added. Hence these line edits will be added vertically, one under the other on a new row. If you just add the Height/Width line edits ontoEditBox
too they will come out under the Selected Images names line edits, which is not what you will want.Your
EditBox
will need its currentQVBoxLayout
to be vertical, but that will now need aQHBoxLayout
added for each row, and it is that onto which you will want to add all yourQLineEdit
s, so that they come horizontally on each row.Hence your adding code will want to look something like:
if index not in self.leSelectedImages.keys(): self.leSelectedImages[index] = QLineEdit() self.leHeights[index] = QLineEdit() self.leWidths[index] = QLineEdit() hBoxLayout = QHBoxLayout() hBoxLayout.addWidget(self.leSelectedImages[index]) hBoxLayout.addWidget(self.leHeights[index]) hBoxLayout.addWidget(self.leWidths[index]) self.editBoxLayout.addLayout(hBoxLayout)
See how we can use
self.editBoxLayout.addLayout(hBoxLayout)
to append a (horizontal) layout onto a (vertical) layout --- you can add other layouts, not just widgets, onto layouts.You might want to change over your vertical + horizontal layouts to use a
QGridLayout
instead, but I have left this usingQ[HV]BoxLayout
.P.S.
BTW, in the code you posted you are missing the very first line, required for your@pyqtSlot
decorator, which should readfrom PyQt5.QtCore import Qt, pyqtSlot
-
Hey @JonB, I must apologize for the confusion with
self.LE[Indx] = QLineEdit()
. Because I forgot to delete them from the code. This has no particular meaning.I looked at your suggested code and understood it. However, if I try to implement your code in mine, it unfortunately does not work. I must be doing something wrong. Maybe I'm putting it in the wrong place. Could you possibly tell me where you would insert your suggestion in my code ?
-
@elias_hh
In yourdef SetImage()
, exactly where you presently haveif Indx not in self.LneEdts.keys():
, since that's where you want it!Note that I (deliberately) did not use the spelling/capitalisation of your current code (because it's non-standard). You are expected to do whatever to change you code or my code to make them correspond as necessary.