Trouble shooting of running PyQt5 in Windows subsystem ubuntu 18.04 (WSL)
===
This is what I created with PyQt5, it's a practice inspired by a [funny video](https://www.instagram.com/p/CHwWTzshr28/).
https://github.com/KennyTzeng/Resignation-Letter

## Environment
At first create a Python virtual environment and activate it.
```
# apt-get install python3-venv
# python3 -m venv venv
# source venv/bin/activate
```
And then upgrade my pip and install the `PyQt5` module.
Install `pyqt5-tools` also for Qt designer `pyqt5designer`.
```
(venv)# pip install --upgrade pip
(venv)# pip install PyQt5
(venv)# pip install pyqt5-tools
```
Then I create a python script with minimum Qt content.
```python=
from PyQt5.QtWidgets import QApplication, QLabel
app = QApplication([])
label = QLabel("Hello World!")
label.show()
app.exec_()
```
Try to run it, but the program aborted and there are some error messages.
Type this line in bash, the error message will be more detailed.
```
export QT_DEBUG_PLUGINS=1
```
```
Got keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "/usr/bin/platforms" ...
Cannot load library /root/workspace/Resignation-Letter/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxcb-icccm.so.4: cannot open shared object file: No such file or directory)
QLibraryPrivate::loadPlugin failed on "/root/workspace/Resignation-Letter/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so" : "Cannot load library /root/workspace/Resignation-Letter/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxcb-icccm.so.4: cannot open shared object file: No such file or directory)"
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.
Aborted (core dumped)
```
What's it said is basically it can not find the dependent shared libraries of `libxcb.so`.
Let's see what's the dependency and try to get it.
```
(venv)# ldd /root/workspace/Resignation-Letter/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so | grep "not found"
libxcb-icccm.so.4 => not found
libxcb-image.so.0 => not found
libxcb-keysyms.so.1 => not found
libxcb-randr.so.0 => not found
libxcb-render-util.so.0 => not found
libxcb-render.so.0 => not found
libxcb-xfixes.so.0 => not found
libxcb-xinerama.so.0 => not found
libxcb-xkb.so.1 => not found
libxkbcommon-x11.so.0 => not found
libxkbcommon.so.0 => not found
libxcb-icccm.so.4 => not found
libxcb-image.so.0 => not found
libxcb-keysyms.so.1 => not found
libxcb-randr.so.0 => not found
libxcb-render-util.so.0 => not found
libxcb-render.so.0 => not found
libxcb-xfixes.so.0 => not found
libxcb-xinerama.so.0 => not found
libxcb-xkb.so.1 => not found
libxkbcommon-x11.so.0 => not found
libxkbcommon.so.0 => not found
```
Then we use `apt-cache` to search for these shared libraries.
```
(venv)# apt-cache search libxcb
libxcb-icccm4 - utility libraries for X C Binding -- icccm
libxcb-icccm4-dev - utility libraries for X C Binding -- icccm, development files
libxcb-image0 - utility libraries for X C Binding -- image
libxcb-image0-dev - utility libraries for X C Binding -- image, development files
libxcb-keysyms1 - utility libraries for X C Binding -- keysyms
libxcb-keysyms1-dev - utility libraries for X C Binding -- keysyms, development files
libxcb-present-dev - X C Binding, present extension, development files
libxcb-present0 - X C Binding, present extension
libxcb-randr0 - X C Binding, randr extension
libxcb-randr0-dev - X C Binding, randr extension, development files
...
```
Use `apt-get install` to install them.
```
(venv)# apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 libxkbcommon0
```
Run the script again, now we got another problem.
```
Got keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "/usr/bin/platforms" ...
loaded library "/root/workspace/Resignation-Letter/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so"
qt.qpa.xcb: could not connect to display
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.
```
It looks like a display issue, I guess it's because I run it in WSL terminal. Try to find some way to forward the GUI window.
I launch Mobaxterm for its X11 forwarding mechanism.
Type this line in bash or you can add it into your `.bashrc`
```
(venv)# export DISPLAY=:0
```
At the end I got my helloworld.

## GUI Design
Use `pyqt5designer` to build the GUI layouts quickly.
```
(venv)# venv/bin/pyqt5designer
```

It will save the file as xxx.ui, you can use `pyuic5` to transform it to python code.
```
(venv)# pyuic5 -x main.ui -o main.py
```
## How did I test the sub-component
My project layout is like this: GUI related put in the gui folder, logic part I put inside src folder.
```
.
+-- main.py
+-- test.py
+-- gui/
| +-- nowayDialog.ui
| +-- nowayDialog.py
+-- src/
| +-- nowayDialog.py
+-- images/
+-- lib/
```
When I wants to test my customized component, I create a python code like this at the root directory, import the necessary module and run it.
```python=
# test.py
import sys
from PyQt5 import QtWidgets
from src.nowayDialog import NowayDialog
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
nowayDialog = NowayDialog()
nowayDialog.show()
sys.exit(app.exec_())
```
Since in the logic code I import the gui like this, if I want to run main function of it I will need to change the import path.
```python=
# src/nowayDialog.py
import gui.nowayDialog as ui
...
```
## References
+ Teach me to install virtual environment and PyQt5, it's the beginning of this project.
+ https://build-system.fman.io/pyqt5-tutorial
+ Help me to search and install the necessary shared libraries.
+ https://unix.stackexchange.com/questions/338519/how-to-install-libxcb
+ Solve my display issue, use MobaXterm for X11 forwarding
+ https://youtu.be/SZpg5g5O_eY
+ Talk about Qt Designer
+ https://zhung.com.tw/article/pyqt%E5%85%A5%E9%96%80%E7%94%A8python%E5%AF%AB%E7%AC%AC%E4%B8%80%E6%94%AFgui/
+ Qt for Python Documentation (for Qt objects and its attribute, function)
+ https://doc.qt.io/qt-5/qtwidgets-module.html
+ a lot of [stackoverflow](https://stackoverflow.com/) pages
+ Python inheritance
+ https://realpython.com/python-super/