PySide PyInstaller Packaging

when using pyinstaller to package the pyside application with sqlite dependency, it doesn't copy sqldrivers to destination folder (qt4_plugins). When run the application, I will get error message complaining about SQLite driver is not found.

I need copy them to qt4_plugins directory from Qt directory

My solution is wrting a separate script to copy the sqldrivers files to executable directory after packaging.

But there should be a better method by configuring PyInstaller?

Qt QWidget add menu bar

I want to add menu bar to my window (which is a QWidget instance), I searched on the Google and found that most articles are recommending to use QMainWindow instead of QWidget. Using QMainWindow is a good choice, but in my program the main window is based on QWidget and the code base is huge, so adding menu bar to QWidget is a better choice here.

First we need create a window (QWidget) and set its layout (we use QVBoxLayout here)

Then create a menu bar and add it to the VBox layout.

Now you will see a blank menu bar in your window

Next we need add some menus to our menu bar

addMenu function will take the parameter as menu name and return the menu as return value. We need keep the menu instances because we need add actions (menu items) to them.

In above code we create a QAction (menu item) with title "Exit", and connect its "triggered" signal to exit function (sys.exit), it means when this menu item is clicked, the exit function will be called. Finally add this menu item to the "File" menu.

 

We can also connect QAction's triggered signal to custom defined function

Here we add a "Redo" menu item under "Edit" menu. When user clicks "Redo", a message box will be popped up saying "Redo will be performed"

 

Following is the complete code:

 

remove horizontal header of QTableView

QTableView will show the horizontal header and vertical header by default.

Now I want to use QTableView as a file list to show the files changed recently (I want to list more than one column, so QTableView is a better choice than QListView). we can use following code to remove the horizontal header:

PySide

c++

horizontalHeader() method will return the horizontal header which is an instance of QHeaderView class. Then call the hide method of QHeaderView class to hide the header.

QHeaderView class is inheriting QWidget class, so we can use hide method to make it invisible and use show method to make it visible. You can view the QWidget documentation here

PySide message box

When you want to display a warning message (like "File doesn't exist") to user, using message box is a good choice. Following code is how to create a message box in PySide:

QMessageBox is the message window class, it's defined in PySide.QtGui module. setText method will set the information text, and exec_ method will display the message box and waiting for user's operation.

pyside QTableView disable edit mode

In default the QTableView will enable edit mode if user double clicks a table cell.

Following code will disable the edit mode:

 

In some old versions of Qt, QAbstractView will be used instead of QAbstractItemView. But in all versions of PySide, QAbstractView is not defined so QAbstractItemView need be used.

PySide downloading file with progress bar

In this tutorial, we will download a file by HTTP and display the downloading progress by progress bar. The final screenshot is like this:

pyside_downloading_file_with_progress_bar

 

Downloading File

To display the downloading progress, we need know file size and currently downloaded bytes size.

So how to get the size of file need download? If you're familiar with HTTP, it will go easy. When downloading a file, first client will send a HTTP request to server for the file URL, then the server will send back a HTTP response to client. If requested URL is valid, the response body will be the file content.In the response header, there's a field called "Content-Length", which is used to indicate size of the response body. Since response body here is the file content, so this "Content-Length" is what we're looking for.

First we need use urllib2.urlopen() to open an url, this method returns a response object. Chain method info().get_headers() of response object can fetch the response header.So we can get file size like this:

And next, we need know how many bytes we have downloaded.
the read(n) method of response object will receive n bytes of data from server. Actually read() can be called with no parameter, then it will receive all data sent by server. But calling read() method like that will let urllib2 module to handle the whole transferring progress. we cannot know how many bytes have been downloaded until downloading is finished.

To get currently downloaded bytes size, we need download fixed size of bytes everytime and update the downloaded bytes size after that block of bytes are downloaded. Then continue downloading until all data is received. You got the idea? so lets implement it.

 

Display Progress Bar

Now we need QProgressBar to display our downloading progress. set_value() method of QProgressBar is used to set value of progress bar. The default value range is 0-100. and you can modify them by using setMinimum() and setMaximum() of QProgressBar.
Following code will create a window and put a progress bar in it. a setProgress() method is provided to set the progress bar value, so the downloading thread can set progress bar value by calling this method.

 

Integration

We will need put downloading part in a separate thread, otherwise it will block UI.

So here's the complete source code