Kushal Das4

FOSS and life. Kushal Das talks here.

kushal76uaid62oup5774umh654scnu5dwzh4u2534qxhcbi4wbab3ad.onion

PyQt5 thread example

PyQt is the Python binding for Qt library. To write Qt5 code, we use PyQt5 module. Like many others, my first introduction to GUI application development was using PyQt. Back in foss.in 2005 a talk from Sirtaj introduced me to PyQt, and later fall in love with it.

I tried to help in a GUI application after 8 years (I think), a lot of things have changed in between. But, Qt/PyQt still seems to be super helpful when it comes to ease of development. Qt has one of the best documentation out there for any Open Source project.

Many students start developing GUI tools by replacing one of the command line tool they use. Generally the idea is very simple, take some input in the GUI, and then process it (using a subprocess call) on a button click, and then show the output. The subprocess call happens over a simple method, means the whole GUI gets stuck till the function call finishes. We can fix this issue by using a QThread. In the below example, we will just write a frontend for git clone command and then will do the same using QThread.

Setting up project directory

I have used qt creator to create a simple MainWindow form and saved it as mainwindow.ui in the project directory. Then, used pipenv to create a virtualenv and also installed the pyqt5 module. Next, used the pyuic5 command to create a Python file from UI file.

The code does not have error checks, the subprocess documentation should give you enough details about how to add them.

Doing git clone without any thread

The following code creates a temporary directory, and then git clones any given git repository into that.

#!/usr/bin/python3

import sys
import tempfile
import subprocess
from PyQt5 import QtWidgets

from mainwindow import Ui_MainWindow


class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        # Here we are telling to call git_clone method when
        # someone clicks on the pushButton.
        self.pushButton.clicked.connect(self.git_clone)

    # Here is the actual method which does git clone
    def git_clone(self):
        git_url = self.lineEdit.text()  # Get the git URL
        tmpdir = tempfile.mkdtemp()  # Creates a temporary directory
        cmd = "git clone {0} {1}".format(git_url, tmpdir)
        subprocess.check_output(cmd.split())  # Execute the command
        self.textEdit.setText(tmpdir)  # Show the output to the user


def main():
    app = QtWidgets.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    app.exec_()


if __name__ == '__main__':
    main()

Doing git clone with a thread

In the below example we added a new CloneThread class, it has a run method, which gets called when the thread starts. At the end of the run, we are emitting a signal to inform the main thread that the git clone operation has finished.

#!/usr/bin/python3

import sys
import tempfile
import subprocess
from PyQt5 import QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal

from mainwindow import Ui_MainWindow


class CloneThread(QThread):
    signal = pyqtSignal('PyQt_PyObject')

    def __init__(self):
        QThread.__init__(self)
        self.git_url = ""

    # run method gets called when we start the thread
    def run(self):
        tmpdir = tempfile.mkdtemp()
        cmd = "git clone {0} {1}".format(self.git_url, tmpdir)
        subprocess.check_output(cmd.split())
        # git clone done, now inform the main thread with the output
        self.signal.emit(tmpdir)


class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):
        super(ExampleApp, self).__init__(parent)
        self.setupUi(self)
        self.pushButton.setText("Git clone with Thread")
        # Here we are telling to call git_clone method when
        # someone clicks on the pushButton.
        self.pushButton.clicked.connect(self.git_clone)
        self.git_thread = CloneThread()  # This is the thread object
        # Connect the signal from the thread to the finished method
        self.git_thread.signal.connect(self.finished)

    def git_clone(self):
        self.git_thread.git_url = self.lineEdit.text()  # Get the git URL
        self.pushButton.setEnabled(False)  # Disables the pushButton
        self.textEdit.setText("Started git clone operation.")  # Updates the UI
        self.git_thread.start()  # Finally starts the thread

    def finished(self, result):
        self.textEdit.setText("Cloned at {0}".format(result))  # Show the output to the user
        self.pushButton.setEnabled(True)  # Enable the pushButton


def main():
    app = QtWidgets.QApplication(sys.argv)
    form = ExampleApp()
    form.show()
    app.exec_()


if __name__ == '__main__':
    main()

The example looks like the above GIF. You can find the source code here. You can find a bigger example in the journalist_gui of the SecureDrop project.

pony 0.4 released

I just released Pony 0.4 into the wild. It came out with a 2 days delay :(

Pony is a KDE based image manager. The main feature is to create Collections out of removable devices and watch/search the thumbnails offline (when the media is not attached). New features in this release:

  • shortcut key ‘u’ to get the upload to flickr dialog
  • Hot keys: Now one can assign hotkeys using numeric key board , right now only %f (selected filename) is supported there.

Download the source or you can use this yum repo for Fedora 11.

The post is brought to you by lekhonee v0.7

translation-filter 1.0 released

A massive jump in the release number and now we have translation-filter 1.0 :) Download the source from here. What is translation-filter ? It is a tool to imporve l10n quality by helping in finding different corner cases. This is being developed as a part of aukur.org.in . It is having two GUI(s), one Gnome and one for KDE and a command line version. Couple of the features are only available in the command line version. Different features of translation-filter:

  • It can search for word(s) in a given directory or some selected files. The result will be saved as an HTML file or can also be seen in the command line. By using this features one can check consistency of usage
  • It can create single word based list from the given .po files. It will contain both the term and translated string(s)
  • It can check for any unattached dependent vowel sign. Right now it can find that for the Indic languages. Like ি and া can not sit beside

To know more about different options read here.

The post is brought to you by lekhonee v0.6

Pony v0.3 released

I just released Pony v0.3 , you can download the source from here. Pony is an image manager written in PyKDE4.
If you are using a previous version of pony , you should remove the old db by $rm ~/.pony.db

This release is having many bug fixes and also new features.

Like:

  • One can create media catalog (DVD or removable medias)
  • Search media catalogs based on tags
  • Flickr image uploading is now smoother
  • While in FullScreen image viewing one can use mouse whell to browse through images

Here is a preview of the new catalog options

Pony v0.3

If you are using Fedora 11 , you can add my repo as building and pushing to the Fedora repos may take some time. To do so just drop this in your /etc/yum.repos.d/

The post is brought to you by lekhonee v0.6

New release of lekhonee

I am happy to release lekhonee-0.3.1

New release of lekhonee

lekhonee is a desktop client for Wordpress. The new features of this release are:

  • Add Category
  • Spell Check enable/disable
  • Edit last entry

I never blogged about a few last releases, I moved the codebase to PyKDE4. It is using KWallet service to store the password. If you don’t want to use kwallet (like you are a gnome user), it will ask you to type-in the details every time.

Download tarball, F-10 rpm (pushed to stable), F-11 rpm