Linux Format - UK (2020-03)

(Antfer) #1
90 LXF260 March 2020 http://www.linuxformat.com

CODING ACADEMY Python & Qt5


been added to listWidgetRepo, populateDialog()
then alphabetises listWidgetRepo.
self.listWidgetRepo.setSortingEnabled(True)
self.listWidgetRepo.sortItems()
It then repaints the foreground colour of all of the items
in listWidgetRepo.
for i in range(nRepoCount):
item = self.listWidgetRepo.item(i)
item.setForeground(QColor(item.data(Qt.UserRole)))
Finally, populateDialog() sets the QTextEdit widget
RepoNumFound to the number of git repositories found.
Currently every time an item in listWidgetRepo is
selected, it paints the text in black. We need to fix that,
by setting a style sheet for listWidgetRepo’s selected
items at the beginning of repoSelectionChanged().
Every time an item is selected, listWidgetRepo emits a
signal to tell any interested parties that the selection
has changed. We set up a slot to capture that signal, so
that every time listWidgetRepo’s selection is changed,
the class function repoSelectionChanged() is called.
The first thing we do in repoSelectionChanged() is to
populate listWidgetRepo’s selected item style sheet:
self.listWidgetRepo.setStyleSheet(“””
QListWidget::item:selected { color: ““” +
self.listWidgetRepo.currentItem().data(Qt.UserRole) +
““”; }
QListWidget::item:selected { background-color: white;
}
QListWidget::item:selected { border: 2px solid red; }
““”)
ListWidgetRepo was created in single selection
mode, so you can’t select more than one item at a time.
The style sheet tells listWidgetRepo that when a new
selection is made the item’s background colour is white,
a red border is painted around the selected item and the
item’s text is painted in the colour saved in the data field
of the current item.
We also need to clear and populate listWidgetStatus.
We must do this every time listWidgetRepo’s selection is
changed, so we do it after setting listWidgetRepo’s
selected style sheet in repoSelectionChanged().
# use git status --porcelain to interrogate selected
repository
p = Popen([“git”,“status”,“--porcelain”],
cwd = self.listWidgetRepo.currentItem().text(), stdout =
PIPE)
p.wait()
out = p.communicate()[0]
strArray = out.splitlines()
self.listWidgetStatus.clear()
This invokes the command git status --porcelain in
the repository’s working directory. The command git
status produces verbose output, which is good for
humans; gitStatus --porcelain is more machine friendly.
It produces an \n terminated line of output for each
issue found in the git repository. All the lines are read
into the string out , this is then split into the string array,
strArray. Each element of strArray contains an issue
found in the repository. If strArray is empty then we
write the single entry ‘working directory clean’ and paint
it green.
The first two bytes of strArray[i] are the characters X
and Y. They are followed by a space and the name of the
file relative to the repository’s working directory. X
indicates changes ready for commit, and Y indicates

reasonable assumptions about your environment. The
purpose of parseConfigFile() is to construct a list of
start directories where you want to search for git
repositories. If you haven’t already created gitStatus.ini,
the list of start directories (startDirs) is populated with
a single value: your home directory. The method
parseConfigFile() is also responsible for creating a list
of git repositories we want to ignore (exceptDirs).
All of our development takes place in /home/js/
Development, so our gitStatus.ini looks like this:
[startDirs]
/home/js/Development
[exceptDirs]
github.com
golang.org
When you invoke gitStatus.py with the --verbose
option, you will see the output of parseConfigFile() on
the console. The remainder of main looks like this:
if not ui.parseConfigFile(): # read the .ini file
sys.exit(1)
ui.populateDialog() # populate the dialog’s
widgets
GitStatus.show() # make the dialog visible
sys.exit(app.exec_()) # handle all messages until
exit
Before populateDialog() is called from main,
parseConfigFile() has been executed. This populates
the QStringLists startDirs and exceptDirs from
gitStatus.ini in the program’s directory.
First, populateDialog() gets the date and time and
populates the DateTimeEdit QTextEdit control.
Next, starting at startDirs[0] and continuing with any
other startDirs, it walks the directory tree and searches
for directories that contain the hidden directory .git.
Inside the directory walk, populateDialog() does a list
comprehension, which is a way of pruning a list in place.
dirs[:] = [d for d in dirs if d not in self.exceptDirs].
This removes any directories from dirs[] that were in
exceptDirs. For each path that’s left in dirs[] we check if
it contains a hidden directory .git.
To display a git repository’s working directory,
populateDialog() creates a QListWidgetItem object and
populates it with the working directory’s path. It then
calls quickCheckPriority(dir) to determine the colour
with which to paint the QListWidgetItem. It sets the
data property of the QListWidgetItem to the text of
the colour that we want to use the paint the
QListWidgetItem. It then adds the item to
listWidgetRepo, the list of working directories.
When all the qualified git repository directories have

Figure 3: Editing
the GitStatus
Dialog Box in Qt 5
Designer. In this
figure, all widgets
have been added.

Your package
manager
probably has
PyQt5 available.
It may show
up as the
installation
pattern Qt5. To
build a PyQt5
application you
need to install
python3-qt5
and python3-
qt5-devel.
Naturally, you’ll
need Python 3
as well.

90 LXF260March 2020 888March 20disuMe0i


CODING ACADEMY Python & Qt5


been added to listWidgetRepo, populateDialog()
then alphabetises listWidgetRepo.
self.listWidgetRepo.setSortingEnabled(True)
self.listWidgetRepo.sortItems()
It then repaints the foreground colour of all of the items
in listWidgetRepo.
for i in range(nRepoCount):
item = self.listWidgetRepo.item(i)
item.setForeground(QColor(item.data(Qt.UserRole)))
Finally, populateDialog() sets the QTextEdit widget
RepoNumFound to the number of git repositories found.
Currently every time an item in listWidgetRepo is
selected, it paints the text in black. We need to fix that,
by setting a style sheet for listWidgetRepo’s selected
items at the beginning of repoSelectionChanged().
Every time an item is selected, listWidgetRepo emits a
signal to tell any interested parties that the selection
has changed. We set up a slot to capture that signal, so
that every time listWidgetRepo’s selection is changed,
the class function repoSelectionChanged() is called.
The first thing we do in repoSelectionChanged() is to
populate listWidgetRepo’s selected item style sheet:
self.listWidgetRepo.setStyleSheet(“””
QListWidget::item:selected { color: ““” +
self.listWidgetRepo.currentItem().data(Qt.UserRole) +
““”; }
QListWidget::item:selected { background-color: white;
}
QListWidget::item:selected { border: 2px solid red; }
““”)
ListWidgetRepo was created in single selection
mode, so you can’t select more than one item at a time.
The style sheet tells listWidgetRepo that when a new
selection is made the item’s background colour is white,
a red border is painted around the selected item and the
item’s text is painted in the colour saved in the data field
of the current item.
We also need to clear and populate listWidgetStatus.
We must do this every time listWidgetRepo’s selection is
changed, so we do it after setting listWidgetRepo’s
selected style sheet in repoSelectionChanged().
# use git status --porcelain to interrogate selected
repository
p = Popen([“git”,“status”,“--porcelain”],
cwd = self.listWidgetRepo.currentItem().text(), stdout =
PIPE)
p.wait()
out = p.communicate()[0]
strArray = out.splitlines()
self.listWidgetStatus.clear()
This invokes the command git status --porcelain in
the repository’s working directory. The command git
status produces verbose output, which is good for
humans; gitStatus --porcelain is more machine friendly.
It produces an \n terminated line of output for each
issue found in the git repository. All the lines are read
into the string out , this is then split into the string array,
strArray. Each element of strArray contains an issue
found in the repository. If strArray is empty then we
write the single entry ‘working directory clean’ and paint
it green.
The first two bytes of strArray[i] are the characters X
and Y. They are followed by a space and the name of the
file relative to the repository’s working directory. X
indicates changes ready for commit, and Y indicates

reasonable assumptions about your environment. The
purpose of parseConfigFile() is to construct a list of
start directories where you want to search for git
repositories. If you haven’t already created gitStatus.ini,
the list of start directories (startDirs) is populated with
a single value: your home directory. The method
parseConfigFile() is also responsible for creating a list
of git repositories we want to ignore (exceptDirs).
All of our development takes place in /home/js/
Development, so our gitStatus.ini looks like this:
[startDirs]
/home/js/Development
[exceptDirs]
github.com
golang.org
When you invoke gitStatus.py with the --verbose
option, you will see the output of parseConfigFile() on
theconsole.Theremainderofmainlookslikethis:
ifnotui.parseConfigFile(): #readthe.inifile
sys.exit(1)
ui.populateDialog() #populatethedialog’s
widgets
GitStatus.show() #makethedialogvisible
sys.exit(app.exec_()) # handle all messages until
exit
Before populateDialog() is called from main,
parseConfigFile() has been executed. This populates
the QStringLists startDirs and exceptDirs from
gitStatus.ini in the program’s directory.
First, populateDialog() gets the date and time and
populates the DateTimeEdit QTextEdit control.
Next, starting at startDirs[0] and continuing with any
other startDirs, it walks the directory tree and searches
for directories that contain the hidden directory .git.
Inside the directory walk, populateDialog() does a list
comprehension, which is a way of pruning a list in place.
dirs[:] = [d for d in dirs if d not in self.exceptDirs].
This removes any directories from dirs[] that were in
exceptDirs. For each path that’s left in dirs[] we check if
it contains a hidden directory .git.
To display a git repository’s working directory,
populateDialog() creates a QListWidgetItem object and
populates it with the working directory’s path. It then
calls quickCheckPriority(dir) to determine the colour
with which to paint the QListWidgetItem. It sets the
data property of the QListWidgetItem to the text of
the colour that we want to use the paint the
QListWidgetItem. It then adds the item to
listWidgetRepo, the list of working directories.
When all the qualified git repository directories have

Figure 3: Editing
the GitStatus
Dialog Box in Qt 5
Designer. In this
figure, all widgets
have been added.

Yourpackage
manager
probablyhas
PyQt5available.
It mayshow
upasthe
installation
patternQt5.To
builda PyQt5
applicationyou
needtoinstall
python3-qt5
andpython3-
qt5-devel.
Naturally,you’ll
needPython 3
aswell.
Free download pdf