Как размер встроенного xterm tk может быть динамическим?

Можно написать простой скрипт на Python для встраивания xterm во фрейм tk:

from Tkinter import *
import subprocess

root = Tk()
termf = Frame(root, height=800, width=1000)

termf.pack(fill=BOTH, expand=YES)
wid = termf.winfo_id()

После установки окна

proc = subprocess.Popen('xterm -into %d -sb ' % wid,shell=True)
root.mainloop()

На моем компьютере это выглядит как embedded xterm Как сделать встроенный xterm динамически изменяемым в соответствии с размером кадра termf даже при изменении размера кадра (путем перетаскивания угла)?

Ответ на ответ @tinmarino tk кадр со встроенным xterm, но неправильного размера, не полностью заполняющий кадр


person esmit    schedule 31.10.2016    source источник
comment
Спросите корень, каковы его размеры, и используйте их с настройками в качестве параметров для Frame()?   -  person wallyk    schedule 01.11.2016
comment
Я отредактировал свой вопрос, чтобы отразить, что, хотя я могу создать экземпляр xterm до нужного размера фрейма, как вы предлагаете @wallyk, я хочу знать, как продолжить получать его до размера фрейма, когда размер фрейма изменяется путем перетаскивания его угол.   -  person esmit    schedule 01.11.2016
comment
Вам нужно будет использовать привязку события, чтобы постоянно обновлять размер.   -  person Mike - SMT    schedule 01.11.2017
comment
Хоть он и не динамичен, как я надеялся, размер xterm можно изменить с помощью таких команд, как echo -e '\e[4;600;800t' в самом xterm. См. invisible-island.net/xterm/ctlseqs/ctlseqs.html манипуляции с окнами. .   -  person esmit    schedule 09.01.2018


Ответы (2)


маленький

измененный размер

Реализация решения @EthanField. 3 функции:

  1. главное создать графический интерфейс, xterm и подключить трубы
  2. on_resize вызывается, когда изменяется размер фрейма, содержащего терминал
  3. get_xterm_pts анализирует вывод для pts для передачи stdin в 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()

Поиск точек новой оболочки в новом потоке кажется много, но нам нужны точки интерактивной оболочки, а не sh, которые ее порождают. На самом деле я попробовал pip -> pts с некоторыми Popen ps, и он оказался менее устойчивым.

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 
person Tinmarino    schedule 19.01.2020
comment
Замените fake_event = Namespace() на fake_event = tk.Event() - person stovfl; 19.01.2020
comment
Не совсем. Мое окно по-прежнему не имеет нужного размера, поэтому оно не изменяет размер правильно (хотя оно получает команды изменения размера, что является хорошим началом). Я помещу изображение в исходный вопрос, так как вставить его здесь не представляется возможным. - person esmit; 22.01.2020
comment
Изменяется ли он как-то (т.е. размер xterm меняется)? Я добавил немного магии magic_x, magic_y = 6.1, 13. В вашем случае вы должны увеличить как: magic_x, magic_y = 7, 15 Вы можете изменить это. Надо было поставить в начале, может быть. Спасибо за отзыв. - person Tinmarino; 22.01.2020

Как было указано в комментариях выше, вы можете использовать .bind() в окне Tk(), чтобы получать обратный вызов каждый раз, когда окно настраивается.

from tkinter import *

root = Tk()

def callback(event):
    print(event.width, event.height)

root.bind("<Configure>", callback)

root.mainloop()

У меня нет возможности проверить, как вы можете использовать это для изменения размера окна xterm в Windows 10. Поэтому я оставлю этот ответ здесь для всех, кто хочет его отредактировать или использовать этот ответ для создания своего собственного.

person Ethan Field    schedule 02.11.2017
comment
Я понимаю, как написать обратный вызов. Как этот обратный вызов может взаимодействовать с открытым xterm? - person esmit; 09.11.2017
comment
Обратный вызов дает вам размер виджета. Конечно, вы можете использовать это, чтобы изменить размер xterm? - person Ethan Field; 09.11.2017
comment
Спасибо, это помогло (особенно от кого-то на машине с Windows, вы все равно не поняли бы это правильно)! Я не буду его редактировать, потому что мой рабочий код длиннее (экранированная последовательность, синхронизация, печать). - person Tinmarino; 19.01.2020