【问题标题】:Show terminal status in a Tkinter widget在 Tkinter 小部件中显示终端状态
【发布时间】:2017-08-25 18:17:32
【问题描述】:

我在 MacOs Sierra 上使用 python2.7.10,并通过 ssh 与我的 raspberrypi 连接创建了 rsync。想法是将我的本地文件夹与树莓派上的远程文件夹同步。

我的函数 syncroFolder() 工作正常,但如何在我的 tkinter 窗口上显示实时状态?有什么简单的解决方案吗?我无法理解发布的问题:“将命令行结果重定向到 tkinter GUI”

def syncroFolder():
    os.system("rsync -avz -e \"ssh -p port\" /source/path /folder/to/rcync ")

感谢您的帮助


2017-09-05: 我设法用“| tee”将结果写入文件,我的命令现在看起来像这样

os.system("rsync -avzr -P --info=progress2 -e \"ssh -p %s\" %s %s | tee %s & "  %(port,dossier,destination,exampleOutputTxtAdd))

我在 TKinter 中创建了一个显示文件最后一行的文本框

status, lastLineInFile = commands.getstatusoutput("tail -n 1 "+ exampleOutputTxtAdd)
T.insert(END,'Transfering: \n'+lastLineInFile)

输出文件如下所示:

sending incremental file list
folder/

          0   0%    0.00kB/s    0:00:00 (xfr#0, to-chk=397/410)
folder/Bigfile.avi

     32,768   0%    0.00kB/s    0:00:00  
  2,555,904   0%    2.39MB/s    0:07:18  
  3,112,960   0%    1.41MB/s    0:12:23  
  3,637,248   0%    1.11MB/s    0:15:44

但文本框显示所有这些行

  Transfering

      3,776   0%    0.00kB/s    0:00:00 

 16,567,040   1%   13.69MB/s    0:01:15  

并继续添加行,即使我读取了输出文件的 -n = 1 行。

我一直在尝试使用 --out-format=\"%t %o %f %b\",但是我只有在传输后才有状态(如果是大文件)...我尝试了很多选项,但没有一个对我有用......我不明白为什么它不只显示输出文件的最后一行。 你有什么建议吗?

【问题讨论】:

  • 您应该能够通过定时循环将数据逐行写入文本框。这应该很简单。
  • 但是当程序运行命令 rsync 时,结果出现在终端并且程序(Tkinter 窗口)冻结,直到同步完成。我读了线程不是 Tkinter 的好主意。在我的情况下,定时循环仅在之前有效(但它不会运行 rsync)。我会继续努力......无论如何,谢谢
  • /所以你将数据同步到一个文件,然后有一个定时循环以只读模式读取该文件并使用它来保持你的 tkinter 文本框使用当前数据更新。这应该可以防止您遇到任何问题。如果您需要分离同步命令,那么您可能需要使用 tkinter 研究多处理。

标签: python tkinter


【解决方案1】:

这是一个使用 python3 的示例(因为这就是我所拥有的)。本质就像在参考示例中使用线程将管道逐行读取到队列中,然后使用后事件读取队列。增强功能将是每次从队列中读取所有项目,并在子进程停止后停止后续事件序列。使用python3 tkinter_rsync.py rsync://servername/sharename 或类似的东西进行测试。

import sys
import tkinter as tk
import tkinter.ttk as ttk
from subprocess import Popen, PIPE
from threading import Thread
from queue import Queue, Empty

def read_pipe(widget, queue):
    interval = 1
    try:
        line = queue.get_nowait()
    except Empty:
        interval = 5
        pass
    else:
        widget.insert('end', line)
    widget.after(interval, lambda: read_pipe(widget, queue))

def queue_line(pipe, queue):
    for line in iter(pipe.readline, b''):
        queue.put(line)
    pipe.close()

def main(argv):
    root = tk.Tk()
    text = tk.Text(root)
    vs = ttk.Scrollbar(root, orient='vertical', command=text.yview)
    text.configure(yscrollcommand=vs.set)
    text.grid(row=0, column=0, sticky='news')
    vs.grid(row=0, column=1, sticky='ns')
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    process = Popen(['rsync', '--list-only', argv[1]], stdout=PIPE)
    queue = Queue()
    tid = Thread(target=queue_line, args=(process.stdout, queue))
    tid.daemon = True
    tid.start()

    root.after(0, lambda: read_pipe(text, queue))
    root.mainloop()

if __name__ == '__main__':
    main(sys.argv)

【讨论】:

  • 为什么不widget.after(interval, lambda: read_pipe(widget, queue)) => widget.after(interval, read_pipe, widget, queue)
猜你喜欢
  • 2022-01-06
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 2019-04-23
  • 2016-06-27
  • 2023-03-03
  • 2020-08-31
  • 1970-01-01
相关资源
最近更新 更多