python gui界面启动脚本、点击按钮执行脚本_如何在启动Tkinter应用程序时隐藏控制台窗口,但在按下GUI按钮运行python脚本时重新打开它?...

一般来说,隐藏现有的控制台窗口不是一个好主意。它是一个共享资源,如果你的应用程序在窗口隐藏的情况下死机,那么它基本上会使附加到控制台的其他应用程序变得毫无用处。在

您可以通过pythonw.exe,它不会自动分配或附加到控制台。然后按需分配您自己的控制台,切换到全屏模式(如果支持),设置窗口标题,并将sys.std*重新绑定到控制台设备文件“CONIN$”和“CONOUT$”。你拥有这个窗口的唯一所有权,所以你有权隐藏它。在

例如:import os

import sys

import time

import ctypes

import platform

try:

import Tkinter as tk

except ImportError:

import tkinter as tk

from ctypes import wintypes

user32 = ctypes.WinDLL('user32', use_last_error=True)

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

_windows_version = tuple(map(int, platform.version().split('.')))

kernel32.GetConsoleWindow.restype = wintypes.HWND

user32.SendMessageW.argtypes = (wintypes.HWND, wintypes.UINT,

wintypes.WPARAM, wintypes.LPARAM)

user32.ShowWindow.argtypes = (wintypes.HWND, ctypes.c_int)

SW_HIDE = 0

SW_MAXIMIZE = 3

SW_SHOW = 5

WM_SYSKEYDOWN = 0x0104

VK_RETURN = 0x0D

def toggle_fullscreen(hwnd=None):

if _windows_version < (10, 0, 14393):

return

if hwnd is None:

hwnd = kernel32.GetConsoleWindow()

lparm = (user32.MapVirtualKeyW(VK_RETURN, 0) << 16) | 0x20000001

user32.SendMessageW(hwnd, WM_SYSKEYDOWN, VK_RETURN, lparm)

def printf(s):

for c in s:

sys.stdout.write('%s' % c)

sys.stdout.flush()

time.sleep(0.15)

def input(s):

sys.stdout.write(s)

sys.stdout.flush()

return sys.stdin.readline().rstrip('\n')

def hello():

kernel32.SetConsoleTitleW(u"Hello, World!")

printf('Hello, World!')

input('\nPress enter to continue...')

class App(object):

allocated_console = None

def __init__(self):

if self.allocated_console is None:

# one-time set up for all instances

allocated = bool(kernel32.AllocConsole())

App.allocated_console = allocated

if allocated:

hwnd = kernel32.GetConsoleWindow()

user32.ShowWindow(hwnd, SW_HIDE)

toggle_fullscreen(hwnd)

self.root = root = tk.Tk()

nvar = tk.StringVar(root)

en = tk.Entry(textvariable=nvar)

en.pack()

btn = tk.Button(text="Shell", command=self.runshell)

btn.pack()

def mainloop(self):

self.root.mainloop()

def runshell(self):

hwnd = kernel32.GetConsoleWindow()

user32.ShowWindow(hwnd, SW_SHOW)

try:

old_title = ctypes.create_unicode_buffer(512)

n = kernel32.GetConsoleTitleW(old_title, 512)

if n > 512:

old_title = ctypes.create_unicode_buffer(n)

kernel32.GetConsoleTitleW(old_title, n)

old_stdin = sys.stdin

old_stderr = sys.stderr

old_stdout = sys.stdout

try:

with open('CONIN$', 'r') as sys.stdin,\

open('CONOUT$', 'w') as sys.stdout,\

open('CONOUT$', 'w', buffering=1) as sys.stderr:

self.root.destroy()

hello()

finally:

kernel32.SetConsoleTitleW(old_title)

sys.stderr = old_stderr

sys.stdout = old_stdout

sys.stdin = old_stdin

finally:

if self.allocated_console:

user32.ShowWindow(hwnd, SW_HIDE)

if __name__ == '__main__':

for i in range(3):

app = App()

app.mainloop()

在Python.exe通常与.pyw文件扩展名相关联。您还可以配置py2exe等工具来创建非控制台可执行文件。在

我不得不编写一个input函数,因为raw_input将其提示符写入stderrFILE流。我宁愿避免从Python重新绑定C标准I/O。在

它通过使用WM_SYSKEYDOW消息将组合键Alt+Enter发送到控制台窗口来切换Windows 10中分配的控制台的全屏模式。Windows Vista到Windows 8不支持全屏模式。在这种情况下,您可以最大化窗口并调整屏幕缓冲区的大小。在

请注意,我只隐藏了分配的控制台窗口。避免调用FreeConsole。C运行时的conio API(例如kbhit,getch)将一个句柄缓存到“CONIN$”,但是它没有提供动态导出和支持的方法来重置这个缓存的句柄。这些CRT函数的设计并不是为了支持在多个控制台上循环。假设一个进程在其生命周期内最多连接到一个控制台。至少在Windows10中,这个缓存句柄还可以防止未使用的控制台主机进程破坏其窗口并在进程退出之前退出。在

如果用户在连接应用程序时关闭控制台,控制台将终止应用程序。这是无法阻止的。您最多可以设置一个控件处理程序来通知进程即将被终止。在

检查是否可以隐藏控制台窗口的另一种方法是调用GetConsoleProcessList来获取附加进程的列表。如果您的进程是唯一的,您有权隐藏窗口。如果附加了两个进程,那么如果另一个进程是python3安装的py[w].exe启动器,则隐藏窗口似乎是合理的。检查后者需要通过OpenProcess打开进程的句柄,通过GetModuleBaseName获得图像名。在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值