How can I create a GUI application that also provides a CLI without having a popup shell using PyInstaller?
For example, if I create the following application with pyinstaller argparse_gui.py --noconsole
, stdout isn't displayed in the shell:
C:\projects\argparse_gui\dist\argparse_gui>argparse_gui.exe -V
C:\projects\argparse_gui\dist\argparse_gui>
I can redirect stdout/stderr to a file with argparse_gui.exe -V > log.txt 2>&1
, but that's not exactly user-friendly. I can see stdout if built without --noconsole
, but then there's a nagging separate shell window.
# argparse_gui.py
import sys
import argparse
from PyQt5 import QtCore, QtWidgets, QtGui
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Hello, world!')
def init_layout(self):
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label)
centralWidget = QtWidgets.QWidget()
centralWidget.setLayout(layout)
self.setCentralWidget(centralWidget)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="display application information", action='store_true')
args = parser.parse_args()
if args.version:
print('Version 123', flush=True)
else:
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
EDIT: I found a roundabout way to do it, but the console window appears until the GUI loads up. I placed the following code at the top of my main script and ran Pyinstaller without --windowed. This hides the console window if the script isn't run from an existing console.
import ctypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
process_array = (ctypes.c_uint8 * 1)()
num_processes = kernel32.GetConsoleProcessList(process_array, 1)
if num_processes < 3: ctypes.WinDLL('user32').ShowWindow(kernel32.GetConsoleWindow(), 0)
Otherwise, I'm going to conclude that there isn't a way using PyInstaller. The EXE is bundled with pythonw
if --noconsole/--windowed. PythonW doesn't have a console attached, even if launched from the console.
Command line arguments are still passed, however. You can still use sys.argv or argparser to access them.
When running in --noconsole
, sys.stdout
is a NullWriter
object and sys.__stdout__
is None
. Using open()
on 1 raises an exception, CON and CONOUT$ fail to do anything. Redirecting the console to >&1 throws an error.
Note: Under some conditions stdin, stdout and stderr as well as the original values stdin , stdout and stderr can be None. It > is usually the case for Windows GUI apps that aren't connected to a console and Python apps started with pythonw. https://docs.python.org/3/library/sys.html#sys.__stderr __
Pyinstaller explicitly uses PythonW.exe if the EXE is built with --noconsole. I wasn't able to find a way around this, such as loading the console bootloader if called from the cli but pythonw otherwise.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.