У меня есть N-панель, которая содержит поля с настройками параметров подключения к FTP-серверу (хост, порт и т.д).
При клике происходит подключение к серверу. Понятное дело, подключение должно выполняться в потоке.
В андроиде есть удобный класс AsynTask, который имеет методы doInBackground и onPostExecute. В первом мы размещаем код, который работает в потоке, а второй метод запускается при окончании работы потока и туда же пробрасывается результат работы.
Вот мой класс для подключения к ftp-серверу:
class FTPConnector:
DATA_DIRECTORY = r'C:\test'
def __init__(self, file_name):
self.ftp = FTP()
self.file_name = file_name
self.create_data_directory()
self.PATH_TO_DATA = f'{self.DATA_DIRECTORY}\\{file_name}'
def connectQuietly(self, host, port, user, password):
self.tryToConnect(host, port)
self.tryToLogin(user, password)
self.tryToGetFile()
@property
def path_to_data(self):
return self.PATH_TO_DATA
def tryToConnect(self, host, port):
try:
self.ftp.connect(host, port)
except:
return InfoMessages.FTP.CHECK_HOST_AND_PORT
return None
def tryToLogin(self, user, password):
try:
self.ftp.login(user, password)
except:
return InfoMessages.FTP.CHECK_LOGIN_AND_PASSWORD
return None
def tryToGetFile(self):
try:
with open(self.PATH_TO_DATA, 'wb') as f:
self.ftp.retrbinary('RETR ' + self.file_name, f.write)
except:
return InfoMessages.FTP.CHECK_FILE_NAME
return None
def create_data_directory(self):
try:
os.mkdir(self.DATA_DIRECTORY)
print(f"{self.DATA_DIRECTORY} Directory created")
except OSError:
print(f"Failed to create directory {self.DATA_DIRECTORY}")
Код оператора(срабатывает при клике по кнопке):
class FTPConnOperator(bpy.types.Operator):
bl_idname = "object.ftp_conn_op"
bl_label = "FTP Conn Operator"
bl_options = OperatorOptions.REGISTER
def invoke(self, context, event):
self.host = context.scene.HostAddressProperty.host_address_property
self.port = context.scene.PortProperty.port_property
self.user_name = context.scene.UserNameProperty.user_name_property
self.password = context.scene.PasswordProperty.password_property
self.file_name = context.scene.FileNameProperty.file_name_property
return self.execute(context)
def execute(self, context):
error = self.check_fields()
if error is not None:
show_error_message_box(error)
return OperatorOptions.CANCELLED
error = self.check_connection()
if error is not None:
show_error_message_box(error)
return OperatorOptions.CANCELLED
else:
show_ok_message_box("1. Соединение установлено\n" +
"2. Файл с данными найден\n" +
"3. Настройки сохранены")
return OperatorOptions.FINISHED
def check_fields(self):
if self.port < 0:
return InfoMessages.FTP.ENTER_CORRECT_PORT_NUMBER
if not self.file_name.endswith('.xml'):
return InfoMessages.FTP.CHECK_FILE_EXTENSION
return None
def check_connection(self):
connector = FTPConnector(self.file_name)
error = connector.tryToConnect(self.host, self.port)
if error is not None:
return error
error = connector.tryToLogin(self.user_name, self.password)
if error is not None:
return error
error = connector.tryToGetFile()
if error is not None:
return error
return None
Я пробовал сделать в методе execute что-то подобное:
self.thread = Threat(target=self.check_connection)
self.thread.start()
while self.thread.is_alive():
pass
# остальной код
Но такое решение естественно блокирует UI-поток и окно blender просто зависает. Как можно получить уведомление об окончании работы потока и при этом не заблокировать UI-поток? Т.е. чтобы я мог указать, какой метод будет вызван при окончании работы потока и уже в этом методе отобразить результат работы?