简体   繁体   English

使用 PyInstaller noconsole 显示标准输出

[英]Show stdout with PyInstaller noconsole

How can I create a GUI application that also provides a CLI without having a popup shell using PyInstaller?如何使用 PyInstaller 创建一个也提供 CLI 的 GUI 应用程序,而不会弹出shell?

For example, if I create the following application with pyinstaller argparse_gui.py --noconsole , stdout isn't displayed in the shell:例如,如果我使用pyinstaller argparse_gui.py --noconsole创建以下应用程序,则标准输出不会显示在 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.我可以使用argparse_gui.exe -V > log.txt 2>&1将 stdout/stderr 重定向到一个文件,但这并不完全是用户友好的。 I can see stdout if built without --noconsole , but then there's a nagging separate shell window.如果在没有--noconsole的情况下构建,我可以看到标准输出,但是还有一个令人讨厌的单独 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.编辑:我找到了一种迂回的方法,但控制台 window 会出现,直到 GUI 加载。 I placed the following code at the top of my main script and ran Pyinstaller without --windowed.我将以下代码放在主脚本的顶部,并在没有 --windowed 的情况下运行 Pyinstaller。 This hides the console window if the script isn't run from an existing console.如果脚本不是从现有控制台运行的,这将隐藏控制台 window。

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.否则,我将得出结论,没有办法使用 PyInstaller。 The EXE is bundled with pythonw if --noconsole/--windowed.如果 --noconsole/--windowed,则 EXE 与pythonw捆绑在一起。 PythonW doesn't have a console attached, even if launched from the console. PythonW 没有附加控制台,即使从控制台启动。

Command line arguments are still passed, however.然而,命令行 arguments 仍然通过。 You can still use sys.argv or argparser to access them.您仍然可以使用 sys.argv 或 argparser 来访问它们。

When running in --noconsole , sys.stdout is a NullWriter object and sys.__stdout__ is None .--noconsole中运行时, sys.stdoutNullWriter object 并且sys.__stdout__None Using open() on 1 raises an exception, CON and CONOUT$ fail to do anything.在 1 上使用open()会引发异常,CON 和 CONOUT$ 无法执行任何操作。 Redirecting the console to >&1 throws an error.将控制台重定向到 >&1 会引发错误。

Note: Under some conditions stdin, stdout and stderr as well as the original values stdin , stdout and stderr can be None.注意:在某些情况下,stdin、stdout 和 stderr 以及原始值stdinstdoutstderr可以为 None。 It > is usually the case for Windows GUI apps that aren't connected to a console and Python apps started with pythonw.对于未连接到控制台的 Windows GUI 应用程序和使用 pythonw 启动的 Python 应用程序通常是这种情况。 https://docs.python.org/3/library/sys.html#sys.__stderr __ https://docs.python.org/3/library/sys.html#sys.__stderr __

Pyinstaller explicitly uses PythonW.exe if the EXE is built with --noconsole.如果 EXE 是使用 --noconsole 构建的,那么 Pyinstaller 会显式使用 PythonW.exe。 I wasn't able to find a way around this, such as loading the console bootloader if called from the cli but pythonw otherwise.我无法找到解决此问题的方法,例如如果从 cli 调用,则加载控制台引导加载程序,否则加载 pythonw。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM