问题
One can write a simple python script to embed an xterm
into a tk
frame:
from Tkinter import *
import subprocess
root = Tk()
termf = Frame(root, height=800, width=1000)
termf.pack(fill=BOTH, expand=YES)
wid = termf.winfo_id()
After the window is established
proc = subprocess.Popen('xterm -into %d -sb ' % wid,shell=True)
root.mainloop()
On my computer it looks like
How can I make the embedded xterm be dynamically sized to the size of the termf
frame even when resizing the frame(by dragging the corner)?
Response to answer by @tinmarino
回答1:
As was pointed out in the comments above you can use .bind()
on the Tk()
window in order to get a call back every time the window is configured.
from tkinter import *
root = Tk()
def callback(event):
print(event.width, event.height)
root.bind("<Configure>", callback)
root.mainloop()
I don't have the ability to test how you can use this to resize the xterm window on Windows 10. So I'll leave this answer here for anyone who wants to edit it or use this answer to build their own.
回答2:
Implementation of @EthanField solution. 3 functions:
- main create gui, xterm and plug the pipes
- on_resize is called when the frame containing the terminal is resized
- get_xterm_pts is parsing the output for the pts to feed stdin to xterm
import tkinter as tk
import subprocess as sp
from re import match
from threading import Thread
from queue import Queue
def main():
# Init
root = tk.Tk()
queue = Queue()
# Pack main frame
termf = tk.Frame(root, width=800, height=800)
termf.pack(fill=tk.BOTH, expand=tk.YES, padx=0, pady=0)
wid = termf.winfo_id()
# Allow window resize
sp.Popen("""echo '*VT100.allowWindowOps: true' | xrdb -merge""", shell=True)
# Craft command
cmd = (
# Create into me
f'xterm -into {wid} -geometry 100x50 '
# Log to stdout
r'-sb -l -lc -lf /dev/stdout '
# Launch `ps` command: output, tty, = for remove header
"""-e /bin/bash -c "ps -o tt=;bash" """
r'| tee'
)
print('Launching:', cmd)
# Spawn Xterm
process = sp.Popen(
cmd, shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
print('Xterm pid:', process.pid)
# Get pts
thread = Thread(target=lambda: get_xterm_pts(termf, process, queue))
thread.start()
# Set resize callback
termf.bind("<Configure>", lambda event: on_resize(event, queue))
# Start
root.mainloop()
def on_resize(event, queue):
"""On resize: send escape sequence to pts"""
# Magic && Check
magic_x, magic_y = 6.1, 13
print('Resize (w, h):', event.width, event.height)
if not queue.queue: return
# Calculate
width = int(event.width / magic_x)
height = int(event.height / magic_y)
print('To (lin,col):', height, width)
ctl = f"\u001b[8;{height};{width}t"
# Send to pts
with open(queue.queue[0], 'w') as f:
f.write(ctl)
def get_xterm_pts(parent, process, queue):
"""Retrieve pts(`process`) -> `queue`"""
while True:
out = process.stdout.readline().decode()
print('Xterm out' + out)
match_pts = match(r'pts/\d+', out)
if match_pts:
pts = '/dev/' + match_pts.group(0)
print('-----------> pts:', pts)
queue.put(pts)
break
if out == b'' and process.poll() is not None:
break
# Resize now
fake_event = tk.Event()
fake_event.width = parent.winfo_width()
fake_event.height = parent.winfo_height()
on_resize(fake_event, queue)
if __name__ == '__main__':
main()
The search of the pts of the new shell in a new thread seems a lot, but we want the pts of the interactive shell and not the sh
which spawn it. I actually tried pip -> pts with some Popen ps, and it was less resilient.
11844 pts/1 00:00:00 sh <- pid returned to Popen
11847 pts/1 00:00:00 xterm <- then ...
11848 pts/1 00:00:00 tee <- that is how a pipe work, first plug, then spawn (apparently) (seems logical)
11854 pts/35 00:00:00 bash <- then favorite shell is Michel
来源:https://stackoverflow.com/questions/40351862/how-can-the-size-of-the-tk-embedded-xterm-be-dynamic