diff --git a/README.md b/README.md
index ba6613d..5c88391 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,8 @@ and then run it by typing:
 pygpsclient
 ```
 
+**NB** If you get `error: externally-managed-environment`, refer to the longer installation guidelines for **virtual environments** using [pip](#pip) or [pipx](#pipx) below.
+
 ## The Longer Version
 
 In the following, `python3` & `pip` refer to the Python 3 executables. You may need to substitute `python` for `python3`, depending on your particular environment (*on Windows it's generally `python`*). 
@@ -135,33 +137,50 @@ To access the serial port on most Linux platforms, you will need to be a member
 usermod -a -G tty myuser
 ```
 
-### Install using pip
+### <a name="pip">Install using pip</a>
 
 ![Python version](https://img.shields.io/pypi/pyversions/PyGPSClient.svg?style=flat)
 [![PyPI version](https://img.shields.io/pypi/v/PyGPSClient.svg?style=flat)](https://pypi.org/project/PyGPSClient/)
 ![PyPI downloads](https://img.shields.io/pypi/dm/PyGPSClient.svg?style=flat)
 
-The easiest way to install the latest version of `PyGPSClient` is with [pip](http://pypi.python.org/pypi/pip/):
+The recommended way to install the latest version of `PyGPSClient` is with [pip](http://pypi.python.org/pypi/pip/):
 
 ```shell
 python3 -m pip install --upgrade pygpsclient
 ```
 
-If required, `PyGPSClient` can also be installed into a virtual environment, e.g.:
-
+If required, `PyGPSClient` can also be installed and run in a [virtual environment](https://www.geeksforgeeks.org/python-virtual-environment/) - this may be necessary if you have an `externally-managed-environment`, e.g.:
 ```shell
 python3 -m venv env
 source env/bin/activate # (or env\Scripts\activate on Windows)
 python3 -m pip install --upgrade pygpsclient
+pygpsclient
 ```
 
-The pip installation process places an executable file `pygpsclient` in the Python binaries folder (`../bin` on Linux & MacOS, `..\Scripts` on Windows). The PyGPSClient application may be started by double-clicking on this executable file from your file manager or, if the binaries folder is in your PATH, by opening a terminal and typing (all lowercase):
+To deactivate the virtual environment:
 
 ```shell
+deactivate
+```
+
+To reactivate and run from the virtual environment:
+```shell
+source env/bin/activate # (or env\Scripts\activate on Windows)
 pygpsclient
 ```
 
-`pygpsclient` also accepts optional command line arguments for a variety of configurable parameters. These will override any saved configuration file settings. Type the following for help:
+To upgrade PyGPSClient to the latest version from the virtual environment:
+```shell
+source env/bin/activate # (or env\Scripts\activate on Windows)
+python3 -m pip install --upgrade pygpsclient
+```
+
+The pip installation process places an executable file `pygpsclient` in the Python binaries folder (`../bin` on Linux & MacOS, `..\Scripts` on Windows). The PyGPSClient application may be started by double-clicking on this executable file from your file manager or, if the binaries folder is in your PATH, by opening a terminal and typing (all lowercase):
+```shell
+pygpsclient
+````
+
+`pygpsclient` accepts optional command line arguments for a variety of configurable parameters. These will override any saved configuration file settings. Type the following for help:
 ```shell
 pygpsclient -h
 ```
@@ -185,10 +204,20 @@ Typically:
 1. Windows: `C:\Users\myuser\AppData\Roaming\Python\Python3**\Scripts\pygpsclient.exe`
 2. MacOS: `/Library/Frameworks/Python.framework/Versions/3.**/bin/pygpsclient`
 3. Linux: `/home/myuser/.local/bin/pygpsclient`
-4. Virtual Env: `env/bin/pygpsclient` (or `env\Scripts\pygpsclient.exe` on Windows)
+4. Virtual Env: `$ENV/bin/pygpsclient` (or `$ENV\Scripts\pygpsclient.exe` on Windows), where `$ENV` is the full path to your virtual environment.
 
 where `**` signifies the Python version e.g. `3.12`.
 
+### <a name="pipx">Install using pipx</a>
+
+You can also use [pipx](https://pipx.pypa.io/latest/installation/) (_if available_) to install `pygpsclient` into a virtual environment - use the `pipx ensurepath` command to add the relevant Python binaries folder to your PATH.
+
+```shell
+pipx ensurepath
+pipx install pygpsclient
+```
+
+`pipx` will typically create a virtual environment in the user's local shared folder e.g. `/home/user/.local/share/pipx/venvs/pygpsclient`.
 
 ### Creating A Desktop Application Launcher
 
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index c03befd..dbfa620 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,9 @@
 # PyGPSClient Release Notes
 
+### RELEASE 1.5.4
+
+1. Fix issue with GUI update facility not working for virtual environments.
+
 ### RELEASE 1.5.3
 
 1. Fix issue with displaying final content of file in console after EOF condition.
diff --git a/src/pygpsclient/_version.py b/src/pygpsclient/_version.py
index c92ec02..41a6226 100644
--- a/src/pygpsclient/_version.py
+++ b/src/pygpsclient/_version.py
@@ -8,4 +8,4 @@
 :license: BSD 3-Clause
 """
 
-__version__ = "1.5.3"
+__version__ = "1.5.4"
diff --git a/src/pygpsclient/about_dialog.py b/src/pygpsclient/about_dialog.py
index 4c7932a..52cefd7 100644
--- a/src/pygpsclient/about_dialog.py
+++ b/src/pygpsclient/about_dialog.py
@@ -10,9 +10,12 @@
 :license: BSD 3-Clause
 """
 
+import logging
+from inspect import currentframe, getfile
+from os import path
 from platform import python_version
 from subprocess import CalledProcessError, run
-from sys import platform
+from sys import executable
 from tkinter import Button, Checkbutton, E, Frame, IntVar, Label, Tcl, Toplevel, W
 from webbrowser import open_new_tab
 
@@ -50,7 +53,7 @@ class AboutDialog:
     About dialog box class
     """
 
-    def __init__(self, app, **kwargs):
+    def __init__(self, app, **kwargs):  # pylint: disable=unused-argument
         """
         Initialise Toplevel dialog
 
@@ -59,6 +62,7 @@ def __init__(self, app, **kwargs):
 
         self.__app = app  # Reference to main application class
         self.__master = self.__app.appmaster  # Reference to root class (Tk)
+        self.logger = logging.getLogger(__name__)
         self._dialog = Toplevel()
         self._dialog.title = DLGABOUT
         self._dialog.geometry(
@@ -258,26 +262,30 @@ def _do_update(self, *args, **kwargs):  # pylint: disable=unused-argument
 
         self._btn_checkupdate.config(text="UPDATING...", fg="blue")
         self._dialog.update_idletasks()
-        pyc = "python" if platform == "win32" else "python3"
-        cmd = [
-            pyc,
-            "-m",
-            "pip",
-            "install",
-            "--upgrade",
-            "--user",
-            "--force-reinstall",
-        ]
-        for pkg in self._updates:
-            cmd.append(pkg)
-
+        pth = path.dirname(path.abspath(getfile(currentframe())))
+        if "pipx" in pth:  # installed into venv using pipx
+            cmd = [
+                "pipx",
+                "upgrade",
+                "pygpsclient",
+            ]
+        else:  # installed using pip
+            cmd = [
+                executable,  # i.e. python3 or python
+                "-m",
+                "pip",
+                "install",
+                "--upgrade",
+            ]
+            for pkg in self._updates:
+                cmd.append(pkg)
+
+        result = None
         try:
-            run(
-                cmd,
-                check=True,
-                capture_output=True,
-            )
+            result = run(cmd, check=True, capture_output=True)
+            self.logger.debug(result.stdout)
         except CalledProcessError:
+            self.logger.error(result.stdout)
             self._btn_checkupdate.config(text="UPDATE FAILED", fg="red")
             self._btn_checkupdate.bind("<Button>", self._check_for_update)
             return