2016-11-18 8 views
1

У меня есть графический интерфейс, построенный в Tcl/Tk, который имеет кнопку, которая будет деформировать каталог. Каталог может быть очень большим, поэтому я не хочу блокировать GUI, пока он ждет.Тар файлов в отдельном процессе с использованием open и vwait

Для этого я использую open для командной строки и vwait, однако GUI по-прежнему становится неактуальным во время работы tar. Это мой код:

set ::compress_result 0 
set pipe [open "|$tar_executable -cf $folder_to_tar.tar $folder_to_tar" r+] 
fileevent $pipe readable "set ::compress_result [gets $pipe line]" 

vwait ::compress_result 
set return_value $::compress_result 
unset ::compress_result 
close $pipe 

Почему это до сих пор блокирует цикл событий Tcl и запирать GUI?

+1

Перед тем, как погрузиться внутрь, есть ли причина использовать режим 'r +'? Я бы ожидал здесь 'r' (что фактически не возможно, так как оно по умолчанию). –

+0

Это именно то, что я скопировал с tcl wiki. ха-ха. – TheBat

ответ

2

Основная проблема у вас есть эта линия:

fileevent $pipe readable "set ::compress_result [gets $pipe line]" 

Это читает строку сразу из трубы, потому что [gets …] находится в двойных кавычках. Изменение этого:

fileevent $pipe readable {set ::compress_result [gets $pipe line]} 

Делает вещи работать, так как она откладывает чтение из трубы, пока труба не станет читаемой. Однако для этого он полагается на переменную pipe, являющуюся глобальной. Это на самом деле лучше сделать это:

fileevent $pipe readable [list apply {pipe { 
    global compress_result 
    set compress_result [gets $pipe line] 
}} $pipe] 

Что довольно некрасиво и неудобно для отладки, так что вместо этого мы фактически использовать процедуру помощника:

proc pipedone {pipe} { 
    global compress_result 
    set compress_result [gets $pipe line] 
} 
fileevent $pipe readable [list pipedone $pipe] 

Использование list здесь делает «котировка это как исполняемый скрипт для более позднего », заботясь о любой неожиданной хитрости, которую вы можете иметь в переменной. Он знает, как правильно указывать вещи, поэтому вам не нужно.


В Tcl 8.6 вам лучше использовать сопрограмму.

coroutine piperead apply {{tar folder} { 
    # Open the pipe 
    set pipe [open |[list $tar -cf $folder.tar $folder] "r"] 
    # Wait until readable 
    fileevent $pipe readable [info coroutine] 
    yield 
    # Read and close 
    set return_result [gets $pipe line] 
    close $pipe 
    return $return_result 
}} $tar_executable $folder_to_tar 
+0

Спасибо! Я исправил его, просто избежав [получает ...] -> \\ [получает ... \\] – TheBat

0

Добавление

fconfigure $pipe -blocking false 

после открытия трубы поможет.