From 8da3143df38bb38c1029e17e6908c0038d93135b Mon Sep 17 00:00:00 2001 From: anwinged Date: Tue, 17 Apr 2012 10:29:39 +0000 Subject: [PATCH] GUI added --- forms.py | 77 +++++++++++++++++++++++++++++ manual/for_prog.tex | 14 ++---- opal.py | 116 ++++++++++++++++++++++++++++++++++++++------ server.py | 11 +++-- task.py | 10 ++-- tasks/testt.json | 2 + tasks/testt.py | 6 ++- 7 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 forms.py diff --git a/forms.py b/forms.py new file mode 100644 index 0000000..42a4b66 --- /dev/null +++ b/forms.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +import wx +import wx.propgrid as wxpg + +ID_TEST = wx.NewId() +ID_DUPLICATE = wx.NewId() +ID_DUPLICATE_MODEL = wx.NewId() +ID_DELETE_MODEL = wx.NewId() +ID_PROCESS_MODEL = wx.NewId() + +class MainFrame (wx.Frame): + + def __init__(self, parent): + wx.Frame.__init__ (self, parent, title = 'Opal', size = wx.Size(873,594)) + + self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) + + bSizer3 = wx.BoxSizer(wx.HORIZONTAL) + + self.m_specs = wx.TreeCtrl(self, style = wx.TR_DEFAULT_STYLE|wx.TR_HIDE_ROOT) + self.m_specs.SetMinSize(wx.Size(150,-1)) + + bSizer3.Add(self.m_specs, 0, wx.ALL|wx.EXPAND, 1) + + bSizer4 = wx.BoxSizer(wx.VERTICAL) + + self.m_user_models = wx.TreeCtrl(self, + style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.TR_EDIT_LABELS) + self.m_user_models.SetMinSize(wx.Size(-1,200)) + + bSizer4.Add(self.m_user_models, 0, wx.ALL|wx.EXPAND, 1) + + # WARNING: wxPython code generation isn't supported for this widget yet. + self.m_params = wxpg.PropertyGridManager(self, + style = wxpg.PG_TOOLBAR) + bSizer4.Add(self.m_params, 1, wx.EXPAND |wx.ALL, 1) + + bSizer3.Add(bSizer4, 1, wx.EXPAND, 5) + + self.m_job_list = wx.ListCtrl(self, style = wx.LC_LIST) + self.m_job_list.SetMinSize(wx.Size(150,-1)) + + bSizer3.Add(self.m_job_list, 0, wx.ALL|wx.EXPAND, 1) + + sbar = wx.StatusBar(self) + self.SetStatusBar(sbar) + + mbar = self.BuildMenu() + self.SetMenuBar(mbar) + + self.SetSizer(bSizer3) + self.Layout() + + self.Centre(wx.BOTH) + + def __del__(self): + pass + + def BuildMenu(self): + menubar = wx.MenuBar() + + menu = wx.Menu() + menu.Append(1, "&Open\tCtrl+O") + menubar.Append(menu, '&File') + + menu = wx.Menu() + menu.Append(ID_TEST, "&Test\tCtrl+U") + menu.Append(ID_DUPLICATE, "&Duplicate\tCtrl+D") + menubar.Append(menu, '&Model') + + menu = wx.Menu() + menu.Append(3, "&Log In\tCtrl+L") + menu.Append(2, "&Options\tCtrl+P") + menubar.Append(menu, '&Help') + + return menubar diff --git a/manual/for_prog.tex b/manual/for_prog.tex index 8c1c1c5..6408469 100644 --- a/manual/for_prog.tex +++ b/manual/for_prog.tex @@ -112,7 +112,7 @@ ok Перед тем как перейти к описанию структуры, описывающей зачаду и ее модели, следует рассказать о типах данных, которые применяются в “Opal”. Далее будем говорить только о тех полях, которые встречаются в задачах, моделях и методах. -Тип — очень важная часть описания данных. Хотя без него можно было бы обойтись, предоставив пользователям полный контроль над передаваемыми данными, этого лучше избежать. Все дело в том, что тип является мощным инструментом контроля целостности передаваемых данных, не позволяя использовать, скажем, строку там, где должно быть целое число. +Тип --- очень важная часть описания данных. Хотя без него можно было бы обойтись, предоставив пользователям полный контроль над передаваемыми данными, этого лучше избежать. Все дело в том, что тип является мощным инструментом контроля целостности передаваемых данных, не позволяя использовать, скажем, строку там, где должно быть целое число. В описании поля используется следующий синтаксис: “name”: “type [choice list] [default value] [title title] @@ -151,14 +151,12 @@ ok Период [‘0:0:0’, ‘12:0:0’] -\subsection{Логический тип} -bool +\subsection{Логический тип \emph{bool}} Значения: true, false Логический тип один из основополагающих типов данных. Он может принимать всего два значения: истина и ложь. Отлично подходит для создания выключателей (или переключателей) дополнительных опций модели. Присутствует в JSON. -\subsection{Целочисленный тип} -int +\subsection{Целочисленный тип \emph{int}} Значения: от -231 до 231-1 (4 байта) Тип данных для хранения целых чисел со знаком. Пожалуй, еще более основной тип, чем логический. Если вы не собираетесь работать с большими целыми числами (к примеру, рассчитывать госдолг США) то представленного диапазона хватит для большинства задач. Присутствует в JSON. @@ -169,8 +167,7 @@ float Тип данных с плавающей точкой предназначен для хранения и обработки действительных чисел. Присутствует в JSON. -\subsection{Строковый тип} -string +\subsection{Строковый тип \emph{string}} Строковый тип служит для хранения символов. Отсутствует разделение на строки и символы как во многих языках программирования. Это сделано для того, чтобы упростить работу с данными. Строки можно использовать в качестве комментариев. В качестве нетривиального примера можно привести использование строк вместе с оператором выбора в качестве перечисляемого типа (аналог enum): string choice [‘a’, ‘b’, ‘c’] При записи строк в определении поля данных нужно быть внимательным с использованием кавычек. Кавычки внутри описания поля нужно экранировать символом обратного слеша \\. Лучше это будет видно на примере: @@ -178,8 +175,7 @@ string Чтобы не запутаться надо просто помнить, что вы описываете строку в строке. Присутствует в JSON. -\subsection{Тип момента времени} -time +\subsection{Тип момента времени \emph{time}} Значения: от "1000-01-01 00:00:00" до "9999-12-31 23:59:59" Является аналогом типа данных timestamp. При описании значений этого типа можно описывать как все поле целиком, так и использовать его части отдельно (время и дату). Отсутствующая часть будет заменена значением по умолчанию. Примеры: “12:10:00” diff --git a/opal.py b/opal.py index c20180f..d30af70 100644 --- a/opal.py +++ b/opal.py @@ -13,23 +13,109 @@ import server import task +import wx +import wx.propgrid as wxpg +import forms -class Project: - pass +#----------------------------------------------------------------------------- +# Главная форма +#----------------------------------------------------------------------------- -def main(): - import pprint - s = server.LocalServer() - s.LoadTasksDescriptions() - ds = s.GetTasksDescriptions() - ms = [] - for d in ds: - ms.extend(d.GetModelsDescriptions()) +class MainFrame(forms.MainFrame): + def __init__(self): + forms.MainFrame.__init__(self, None) - m = ms[0] - pprint.pprint(m.data) + s = server.LocalServer() + s.LoadTasksDescriptions() + ds = s.GetTasksDescriptions() + models = [] + for d in ds: + models.extend(d.GetModelsDescriptions()) - print m.GetSpecifications() + model = models[0] -if __name__ == '__main__': - main() + self.m_user_models.Bind(wx.EVT_TREE_ITEM_ACTIVATED, + self.OnModelActivated) + self.m_params.Bind(wxpg.EVT_PG_CHANGING, + self.OnParamChanging) + + self.Bind(wx.EVT_MENU, self.OnTest, id = forms.ID_TEST) + self.Bind(wx.EVT_MENU, self.OnDuplicate, id = forms.ID_DUPLICATE) + + self.m_params.AddPage('fp') + + self.NewProject(model) + + def NewProject(self, project): + # 1. загрузить спецификации модели + # 2. создать одну модель по умолчанию + model = project + um = self.m_user_models + root = um.AddRoot('') + data = task.DataDefinition(model) + + child = um.AppendItem(root, u'Обычная') + um.SetPyData(child, data) + + def SelectUserModel(self, model_def): + msg = model_def.PackParams() + pg = self.m_params + pg.ClearPage(0) + #pg.Append(wxpg.PropertyCategory('Model properties')) + for k, v in model_def.params.iteritems(): + p = model_def.DD[k] + title = p.GetTitle() or k + pid = pg.Append(wxpg.StringProperty(title, value=str(v))) + pg.SetPropertyClientData(pid, k) + pg.SetPropertyHelpString(pid, p.GetComment()) + + def OnModelActivated(self, event): + item = event.GetItem() + data = self.m_user_models.GetPyData(item) + self.SelectUserModel(data) + + def OnParamChanging(self, event): + value = event.GetValue() + print repr(value) + #wx.MessageBox(value, 'changing') + #event.Veto() + + def OnTest(self, event): + um = self.m_user_models + id = um.GetSelection() + md = um.GetItemPyData(id) + wx.MessageBox(md.PackParams()) + md.Flush() + #wx.MessageBox('test') + + def OnDuplicate(self, event): + um = self.m_user_models + id = um.GetSelection() + title = um.GetItemText(id) + parent = um.GetItemParent(id) + md = um.GetItemPyData(id) + child = um.AppendItem(parent, title + ' Copy') + um.SetPyData(child, md.Copy()) + + + +#----------------------------------------------------------------------------- +# Приложение +#----------------------------------------------------------------------------- + +class ThisApp(wx.App): + + def OnInit(self): + # Создание главного окна + frame = MainFrame() + self.SetTopWindow(frame) + frame.Show(True) + return True + +#----------------------------------------------------------------------------- +# Запуск приложения +#----------------------------------------------------------------------------- + +if __name__ == "__main__": + app = ThisApp(redirect = False) + app.MainLoop() \ No newline at end of file diff --git a/server.py b/server.py index 109a5b4..5178b3c 100644 --- a/server.py +++ b/server.py @@ -196,7 +196,7 @@ class Job: self.result = data['result'] # произошла ошибка elif ans == 'error': - WriteToLog('Error!') + WriteToLog('Error! ' + msg) # недокументированный ответ приложения else: pass @@ -243,17 +243,18 @@ class Job: def IsFinished(self): return self.state == JOB_COMPLETED or self.state == JOB_STOPPED + def IsComplete(self): + return self.GetStatus() == JOB_COMPLETE + def Stop(self): - if self.proc and self.proc.poll() != None: + WriteToLog('Try to kill') + if self.proc and self.proc.poll() == None: self.proc.kill() WriteToLog('Job killed') def GetState(self): return self.state - def IsComplete(self): - return self.GetStatus() == JOB_COMPLETE - def GetResult(self): return self.result diff --git a/task.py b/task.py index 7f17dfb..a027f2c 100644 --- a/task.py +++ b/task.py @@ -174,13 +174,17 @@ def main(): p = mdef2.PackParams() pprint(p) - mdef.Flush() + #mdef.Flush() mdef2.Flush() - time.sleep(3) + time.sleep(1) + mdef2.job.Stop() + + time.sleep(5) + print mdef2.job.GetState() print 'RESULT' - pprint(mdef.job.result) + #pprint(mdef.job.result) pprint(mdef2.job.result) if __name__ == '__main__': diff --git a/tasks/testt.json b/tasks/testt.json index f9d9204..a04be05 100644 --- a/tasks/testt.json +++ b/tasks/testt.json @@ -17,12 +17,14 @@ "r": { "type": "double", "default": 6.28, + "title": "Right edge", "comment": "Right edge" }, "d": { "type": "int", "default": 5, + "title": "Serie deep", "comment": "Number of members in taylor serie" }, diff --git a/tasks/testt.py b/tasks/testt.py index b3469c9..a214875 100644 --- a/tasks/testt.py +++ b/tasks/testt.py @@ -7,6 +7,7 @@ import sys import json +import time def write(msg): sys.stdout.write(str(msg) + '\n') @@ -80,11 +81,12 @@ def main(): res.append([l, y]) write(answer(round(l / r, 2))) l += h + time.sleep(0.5) write(result(res)) - except: - write(error('Fatal error')) + except Exception, e: + write(error('Fatal error: ' + str(e))) sys.exit(1) if __name__ == '__main__':