У меня, кажется, нет ничего, кроме проблем с wxPython и кроссплатформенной совместимостью: (
У меня есть функция ниже. Она вызывается, когда пользователь нажимает кнопку, она выполняет некоторую работу, которая может занять некоторое время,во время которого индикатор состояния отображается в строке состояния.
def Go(self, event):
progress = 0
self.statbar.setprogress(progress)
self.Update()
# ...
for i in range(1, numwords + 1):
progress = int(((float(i) / float(numwords)) * 100) - 1)
self.wrdlst.Append(words.next())
self.statbar.setprogress(progress)
self.Update()
self.wrdlst.Refresh()
# ...
progress = 100
self.PushStatusText(app.l10n['msc_genwords'] % numwords)
self.statbar.setprogress(progress)
Вызовы self.Update()
, по-видимому, необходимы в Linux, в противном случае датчик не обновляется до тех пор, пока функция не выйдет, что делает его несколько бессмысленным.Похоже, что эти вызовы не действуют в Windows (по крайней мере, Win 7).
Все это прекрасно работает в Linux (с вызовами Update ()), но в Windows 7 индикатор, кажется, останавливается вокруг20-25% отметки, за некоторое время до выхода из функции. Таким образом, она движется, как и должно, пока не достигнет ~ 25%, затем датчик прекращает движение без видимой причины, но функция продолжает работать нормально и выходит с надлежащим выходом.
В попытке выяснить проблему я попытался вставить строку print progress
непосредственно перед обновлением датчика внутри цикла, thInking, возможно, значение progress
не то, что я думал, что должно быть.К моему большому удивлению, датчик теперь работал как надо, но как только я уберу этот print
, он перестанет работать.Я также могу заменить печать вызовом time.sleep(0.001)
, но даже при таком коротком сне процесс по-прежнему почти останавливается, и если я опускаю его еще больше, проблема возвращается, так что это вряд ли очень полезно.
Я не могу понять, что происходит или как это исправить, но я думаю, что как-то в Windows все происходит слишком быстро, так что progress
не обновляется должным образом через некоторое время и просто остается на фиксированном значении(~ 25).Я понятия не имею, почему это было бы, однако, это не имеет смысла для меня.И, конечно же, ни print
, ни sleep
не являются хорошими решениями.Даже если я распечатываю «ничего», Windows все равно открывает другое окно для несуществующего вывода, что раздражает.
Дайте мне знать, если вам нужна дополнительная информация или код.
Edit: Хорошо, вот рабочее приложение, которое (по крайней мере для меня) имеет проблему.Это все еще довольно долго, но я попытался вырезать все, что не связано с проблемой, под рукой.
Он работает в Linux, как и все приложение.Под Windows он либо не работает, либо работает в зависимости от значения numwords
в функции Go.Если я увеличу его значение до 1000000 (1 миллион), проблема исчезнет.Я подозреваю, что это может зависеть от системы, поэтому, если она работает, попробуйте настроить значение numwords
.Это также может быть связано с тем, что я изменил его так, чтобы он Append()
представлял собой статический текст, а не вызывал генератор, как это происходит в исходном коде.
Тем не менее, при текущем значении numwords
(100000) он выполняетОшибка Windows для меня.
import wx
class Wordlist(wx.TextCtrl):
def __init__(self, parent):
super(Wordlist, self).__init__(parent,
style=wx.TE_MULTILINE|wx.TE_READONLY)
self.words = []
self.SetValue("")
def Get(self):
return '\r\n'.join(self.words)
def Refresh(self):
self.SetValue(self.Get())
def Append(self, value):
if isinstance(value, list):
value = '\r\n'.join(value)
self.words.append(unicode(value))
class ProgressStatusBar(wx.StatusBar):
def __init__(self, *args, **kwargs):
super(ProgressStatusBar, self).__init__(*args, **kwargs)
self._changed = False
self.prog = wx.Gauge(self, style=wx.GA_HORIZONTAL)
self.prog.Hide()
self.SetFieldsCount(2)
self.SetStatusWidths([-1, 150])
self.Bind(wx.EVT_IDLE, lambda evt: self.__reposition())
self.Bind(wx.EVT_SIZE, self.onsize)
def __reposition(self):
if self._changed:
lfield = self.GetFieldsCount() - 1
rect = self.GetFieldRect(lfield)
prog_pos = (rect.x + 2, rect.y + 2)
self.prog.SetPosition(prog_pos)
prog_size = (rect.width - 8, rect.height - 4)
self.prog.SetSize(prog_size)
self._changed = False
def onsize(self, evt):
self._changed = True
self.__reposition()
evt.Skip()
def setprogress(self, val):
if not self.prog.IsShown():
self.showprogress(True)
if val == self.prog.GetRange():
self.prog.SetValue(0)
self.showprogress(False)
else:
self.prog.SetValue(val)
def showprogress(self, show=True):
self.__reposition()
self.prog.Show(show)
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(*args, **kwargs)
self.SetupControls()
self.statbar = ProgressStatusBar(self)
self.SetStatusBar(self.statbar)
self.panel.Fit()
self.SetInitialSize()
self.SetupBindings()
def SetupControls(self):
self.panel = wx.Panel(self)
self.gobtn = wx.Button(self.panel, label="Go")
self.wrdlst = Wordlist(self.panel)
wrap = wx.BoxSizer()
wrap.Add(self.gobtn, 0, wx.EXPAND|wx.ALL, 10)
wrap.Add(self.wrdlst, 0, wx.EXPAND|wx.ALL, 10)
self.panel.SetSizer(wrap)
def SetupBindings(self):
self.Bind(wx.EVT_BUTTON, self.Go, self.gobtn)
def Go(self, event):
progress = 0
self.statbar.setprogress(progress)
self.Update()
numwords = 100000
for i in range(1, numwords + 1):
progress = int(((float(i) / float(numwords)) * 100) - 1)
self.wrdlst.Append("test " + str(i))
self.statbar.setprogress(progress)
self.Update()
self.wrdlst.Refresh()
progress = 100
self.statbar.setprogress(progress)
class App(wx.App):
def __init__(self, *args, **kwargs):
super(App, self).__init__(*args, **kwargs)
framestyle = wx.MINIMIZE_BOX|wx.CLOSE_BOX|wx.CAPTION|wx.SYSTEM_MENU|\
wx.CLIP_CHILDREN
self.frame = MainFrame(None, title="test", style=framestyle)
self.SetTopWindow(self.frame)
self.frame.Center()
self.frame.Show()
if __name__ == "__main__":
app = App()
app.MainLoop()
Редактировать 2 : Ниже приведена еще более простая версия кода.Я не думаю, что смогу сделать его намного меньше.У меня все еще есть проблема.Я могу запустить его изнутри IDLE или напрямую, дважды щелкнув по файлу .py в Windows, в любом случае работает одинаково.
Я пробовал с различными значениями numwords
.Кажется, что проблема на самом деле не исчезает, как я впервые сказал, вместо этого, когда я увеличиваю numwords
, датчик просто продвигается все дальше и дальше, прежде чем вызывается print
.При текущем значении 1.000.000 эта более короткая версия достигает примерно 50%.В более длинной версии, приведенной выше, значение 1.000.000 достигает около 90%, значение 100.000 достигает около 25%, а значение 10.000 достигает только около 10%.
В приведенной ниже версии, когда вызывается print
, прогресс продолжается и достигает 99%, даже если цикл должен был закончиться к тому времени. В исходной версии вызов self.wrdlst.Refresh()
, который занимает несколько секунд при высоком значении numwords, должен был вызвать остановку датчика. Поэтому я думаю, что происходит следующее: в контуре датчик достигает определенной точки, когда выход из контура продолжается, функция продолжает работать, пока датчик остается неподвижным, а когда функция выходит, манометр продолжается, пока не достигнет 99%. Поскольку утверждение печати не занимает много времени, в приведенной ниже версии создается впечатление, что датчик плавно перемещается от 0% до 99%, но print
указывает на обратное.
import wx
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(*args, **kwargs)
self.panel = wx.Panel(self)
self.gobtn = wx.Button(self.panel, label="Go")
self.prog = wx.Gauge(self, style=wx.GA_HORIZONTAL)
wrap = wx.BoxSizer()
wrap.Add(self.gobtn, 0, wx.EXPAND|wx.ALL, 10)
wrap.Add(self.prog, 0, wx.EXPAND|wx.ALL, 10)
self.panel.SetSizer(wrap)
self.panel.Fit()
self.SetInitialSize()
self.Bind(wx.EVT_BUTTON, self.Go, self.gobtn)
def Go(self, event):
numwords = 1000000
self.prog.SetValue(0)
for i in range(1, numwords + 1):
progress = int(((float(i) / float(numwords)) * 100) - 1)
self.prog.SetValue(progress)
print "Done"
if __name__ == "__main__":
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()