Text Finder Example#
Dynamically loading .ui files using
The TextFinder example shows how to load and setup a
.ui file dynamically using the
QUiLoader class that is part of the Qt UI Tools library.
The program allows the user to look up a particular word within the contents of a text. The visual elements and layout of the user interface is loaded at runtime, from a the program resources.
Setting Up The Resource File#
The resources required for the example are:
textfinder.ui- the user interface file created in Qt Designer
input.txt- a text file containing some text to be displayed in a
textfinder.ui contains all the necessary
QWidget objects for the Text Finder. A
QLineEdit is used for the user input, a
QTextEdit is used to display the contents of
QLabel is used to display the text “Keyword”, and a
QPushButton is used for the Find button. Note that all the widgets have sensible
objectName's assigned. These are used in code to identify them.
The screenshot below shows the preview obtained in Qt Designer .
In this example, we store both resources in the applicaton’s executable by including the
textfinder.qrc file. Alternatively, the files could also be loaded at runtime from the file system, or from an external binary resource
.rcc file. For more information on resource files, see The Qt Resource System .
textfinder.qrc file lists all files that should be included as a resource:
<Code snippet "/data/snapshot-qt5full-6.3/qt5/qtbase/textfinder/textfinder.qrc" not found>
To generate a form at run-time, the example is linked against the Qt Ui Tools library. This is done in the
<Code snippet "textfinder/textfinder.pro:0" not found>
TextFinder Class Definition#
TextFinder class contains the main user interface. It declares pointers to the
QLineEdit elements described above. The
QLabel in the user interface is not declared here as we do not need to access it from code.
class TextFinder(QWidget): Q_OBJECT # public TextFinder = explicit(QWidget parent = None) slots: = private() def on_findButton_clicked(): # private ui_findButton = QPushButton() ui_textEdit = QTextEdit() ui_lineEdit = QLineEdit()
on_findButton_clicked() is a slot named according to the Automatic Connection naming convention required by
Loading the Resources#
QFile to load the data from the program resources at runtime. The code for this is in two method methods on top of
loadUiFile function loads the user interface file previously created in Qt Designer . First, the content of the
textfinder.ui file is loaded from the resource system. Then a
QUiLoader instance is created, and the
load() function is called, with the first argument being the open file, and the second argument being the pointer of the widget that should be set as the parent. The created
QWidget is returned.
loadUiFile = QWidget(QWidget parent) file = QFile(":/forms/textfinder.ui") file.open(QIODevice.ReadOnly) loader = QUiLoader() return loader.load(file, parent)
In a similar vein, the
loadTextFile function loads
input.txt from the resources. Data is read using
QTextStream into a
QString with the
readAll() function. We explicitly set the encoding to UTF-8, because
QTextStream by default uses the current system locale. Finally, the loaded text is returned.
loadTextFile = QString() inputFile = QFile(":/forms/input.txt") inputFile.open(QIODevice.ReadOnly) in = QTextStream(inputFile) return in.readAll()
TextFinder Class Implementation#
TextFinder class’s constructor does not instantiate any child widgets directly. Instead, it calls the
loadUiFile() function, and then uses
findChild() to locate the created
QWidget s by object name.
def __init__(self, parent): super().__init__(parent) formWidget = loadUiFile(self) ui_findButton = findChild<QPushButton*>("findButton") ui_textEdit = findChild<QTextEdit*>("textEdit") ui_lineEdit = findChild<QLineEdit*>("lineEdit")
We then use
connectSlotsByName() to enable the automatic calling of the
loadTextFile function is called to get the text to be shown in the
The dynamically loaded user interface in
formWidget is now properly set up. We now embed
formWidget through a
layout = QVBoxLayout() layout.addWidget(formWidget) setLayout(layout)
At the end of the constructor we set a window title.
on_findButton_clicked() function is a slot that is connected to
clicked() signal. The
searchString is extracted from the
ui_lineEdit and the
document is extracted from
ui_textEdit. If there is an empty
QMessageBox is used, requesting the user to enter a word. Otherwise, we traverse through the words in
ui_textEdit, and highlight all ocurrences of the
QTextCursor objects are used: One to traverse through the words in
line and another to keep track of the edit blocks.
def on_findButton_clicked(self): searchString = ui_lineEdit.text() document = ui_textEdit.document() found = False() # undo previous change (if any) document.undo() if searchString.isEmpty(): QMessageBox.information(self, tr("Empty Search Field"), tr("The search field is empty. " "Please enter a word and click Find.")) else: highlightCursor = QTextCursor(document) cursor = QTextCursor(document) cursor.beginEditBlock()
found flag is used to indicate if the
searchString was found within the contents of
ui_textEdit. If it was not found, a
QMessageBox is used to inform the user.
main() function instantiates and shows
if __name__ == "__main__": app = QApplication() textFinder = TextFinder() textFinder.show() sys.exit(app.exec())
There are various approaches to include forms into applications. Using QUILoader is just one of them. See Using a Designer UI File in Your Application for more information on the other approaches available.