Резюме
У меня есть wxPython GUI, который позволяет пользователю открывать файлы для просмотра. В настоящее время я делаю это с помощью os.startfile()
. Тем не менее, я пришел, чтобы узнать, что это не лучший метод, поэтому я хочу улучшить. Главный недостаток startfile()
заключается в том, что я не могу контролировать файл после его запуска. Это означает, что пользователь может оставить файл открытым, чтобы он не был доступен другому пользователю.
Что я ищу
В моем графическом интерфейсе возможно иметь дочерние окна. Я отслеживаю все это, сохраняя объекты GUI в списке, а затем, когда родитель закрыт, я просто просматриваю список и закрываю все дочерние элементы. Я хотел бы сделать то же самое с любым файлом, который пользователь выбирает. Как запустить файл и сохранить объект python, чтобы я мог закрыть его командой? Спасибо заранее
Мои мечты о решении
- Запустите файл таким образом, чтобы существовал объект Python, который я могу передать между функциями
- Некоторый способ запустить файл в своей программе по умолчанию и вернуть PID
- Способ получения PID с именем файла
Достижение прогресса
Вот кадр, который я планирую использовать. Важными битами являются функции run()
и end()
класса FileThread
, так как это решение будет идти.
import wx
from wx.lib.scrolledpanel import ScrolledPanel
import threading
import os
class GUI(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Hey, a GUI!', size=(300,300))
self.panel = ScrolledPanel(parent=self, id=-1)
self.panel.SetupScrolling()
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.openFiles = []
self.openBtn = wx.Button(self.panel, -1, "Open a File")
self.pollBtn = wx.Button(self.panel, -1, "Poll")
self.Bind(wx.EVT_BUTTON, self.OnOpen, self.openBtn)
self.Bind(wx.EVT_BUTTON, self.OnPoll, self.pollBtn)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add((20,20), 1)
vbox.Add(self.openBtn)
vbox.Add((20,20), 1)
vbox.Add(self.pollBtn)
vbox.Add((20,20), 1)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(vbox, flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, border = 10)
self.panel.SetSizer(hbox)
self.panel.Layout()
def OnOpen(self, event):
fileName = "AFileIWantToOpenWithTheFullPath.txt"
self.openFiles.append(FileThread(fileName))
def OnPoll(self, event):
self.openFiles[0].Poll()
def OnClose(self, event):
for file in self.openFiles:
file.end()
self.openFiles.remove(file)
self.Destroy()
class FileThread(threading.Thread):
def __init__(self, file):
threading.Thread.__init__(self)
self.file = file
self.start()
def run(self):
doc = subprocess.Popen(["start", " /MAX", "/WAIT", self.file], shell=True)
return doc
def Poll(self):
print "polling"
print self.doc.poll()
print self.doc.pid
def end(self):
try:
print "killing file {}".format(self.file)
except:
print "file has already been killed"
def main():
app = wx.PySimpleApp()
gui = GUI()
gui.Show()
app.MainLoop()
if __name__ == "__main__": main()
Некоторые дополнительные заметки
- Меня не интересует переносимость, это будет работать только на нескольких управляемых компьютерах в офисе.
- Я не думаю, что это имеет значение, но я запускаю исполняемый файл
pythonw
через пакетный файл
Обновление
Я немного поиграл с subprocess.Popen()
, но столкнулся с той же проблемой. Я могу создать объект Popen
, используя
doc = subprocess.Popen(["start", "Full\\Path\\to\\File.txt"], shell=True)
но когда я poll()
объект, он всегда возвращает 0
. Документы говорят, что A None value indicates that the process hasn’t terminated yet
, поэтому 0
означает, что мой процесс завершен. Таким образом, попытка kill()
ничего не делает.
Я подозреваю, что это происходит потому, что процесс завершается, когда команда start
заканчивается и файл запускается. Я хочу что-то, что будет продолжаться даже после запуска файла, можно ли это сделать с помощью Popen()
?