about dialog, toolbar, plot saving, many bugfixes

This commit is contained in:
anwinged 2012-05-04 12:32:34 +00:00
parent 08b0d2f964
commit c2c22b3a4e
11 changed files with 224 additions and 39 deletions

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
import wx import wx
import wx.gizmos import wx.gizmos
import wx.grid import wx.grid
@ -29,6 +30,10 @@ ID_ADD_MARKERS = wx.NewId()
ID_ABOUT = wx.NewId() ID_ABOUT = wx.NewId()
ID_EXPORT_CSV = wx.NewId()
ID_SAVE_PLOT = wx.NewId()
class TreeListCtrl(wx.gizmos.TreeListCtrl): class TreeListCtrl(wx.gizmos.TreeListCtrl):
def __iter__(self): def __iter__(self):
return TreeListCtrlIterator(self) return TreeListCtrlIterator(self)
@ -137,8 +142,7 @@ class MainFrame(wx.Frame):
self.BuildContextMenu() self.BuildContextMenu()
# tbar = self.BuildToolBar() self.BuildToolBar()
# self.SetToolBar(tbar)
self.auimgr.Update() self.auimgr.Update()
@ -171,7 +175,7 @@ class MainFrame(wx.Frame):
menu.Append(ID_ADD_MODEL_SELECTED, 'Append model to selected') menu.Append(ID_ADD_MODEL_SELECTED, 'Append model to selected')
menu.AppendSeparator() menu.AppendSeparator()
menu.Append(ID_DUPLICATE_MODEL, "&Duplicate\tCtrl+D") menu.Append(ID_DUPLICATE_MODEL, "&Duplicate\tCtrl+D")
#menu.Append(ID_DUPLICATE_TREE, "&Duplicate with subitems\tCtrl+Shift+D") menu.Append(ID_DUPLICATE_TREE, "&Duplicate with subitems\tCtrl+Shift+D")
menu.Append(ID_DELETE_MODEL, 'Delete\tCtrl+E') menu.Append(ID_DELETE_MODEL, 'Delete\tCtrl+E')
menu.AppendSeparator() menu.AppendSeparator()
menu.Append(ID_TEST, "&Test\tCtrl+T") menu.Append(ID_TEST, "&Test\tCtrl+T")
@ -211,11 +215,41 @@ class MainFrame(wx.Frame):
self.m_plots.Bind(wx.EVT_CONTEXT_MENU, self.m_plots.Bind(wx.EVT_CONTEXT_MENU,
lambda x: self.m_plots.PopupMenu(menu1)) lambda x: self.m_plots.PopupMenu(menu1))
menu2 = wx.Menu()
menu2.Append(ID_SHOW_RESULT, 'Show report')
menu2.AppendSeparator()
menu2.Append(ID_ADD_CURVES, 'Add curves')
menu2.Append(ID_ADD_MARKERS, 'Add markers')
self.m_user_models.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,
lambda x: self.m_user_models.PopupMenu(menu2))
def BuildToolBar(self): def BuildToolBar(self):
tbar = wx.ToolBar(self, -1) tb1 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
tbar.AddLabelTool(ID_SHOW_PLOT, 'Plot', wx.Bitmap('share/show-plot.png')) agwStyle = aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_VERTICAL)
tbar.Realize() tb1.SetToolBitmapSize(wx.Size(16, 16))
return tbar
tb1.AddSimpleTool(ID_ADD_MODEL_SELECTED, "model-new", wx.Bitmap('share/model-add.png'),
'Add spacification to selected model')
tb1.AddSeparator()
tb1.AddSimpleTool(ID_DUPLICATE_MODEL, "model-dup", wx.Bitmap('share/model-dup.png'),
'Duplicate selected model')
tb1.AddSimpleTool(ID_DELETE_MODEL, "model-del", wx.Bitmap('share/model-delete.png'),
'Delete selected model')
tb1.AddSeparator()
tb1.AddSimpleTool(ID_PROCESS_MODEL, "model-go", wx.Bitmap('share/model-go.png'),
'Start process selected model')
tb1.AddSeparator()
tb1.AddSimpleTool(ID_SHOW_PLOT, "plot-quick", wx.Bitmap('share/plot-line.png'),
'Show quick plot for selected model')
tb1.AddSimpleTool(ID_SHOW_RESULT, "report-show", wx.Bitmap('share/report-show.png'),
'Show result data and table for selected model')
tb1.AddSeparator()
tb1.AddSimpleTool(ID_ABOUT, "app-about", wx.Bitmap('share/app-about.png'),
'Show infomation about application')
tb1.Realize()
self.auimgr.AddPane(tb1, aui.AuiPaneInfo().Name("tb1").Caption("Toolbar").
ToolbarPane().Left().Floatable(False).Movable(False).Gripper(False))
class SelectModelDialog(wx.Dialog): class SelectModelDialog(wx.Dialog):
def __init__(self, parent): def __init__(self, parent):
@ -259,8 +293,8 @@ class ResultFrame(wx.Frame):
menubar = wx.MenuBar() menubar = wx.MenuBar()
menu = wx.Menu() menu = wx.Menu()
menu.Append(wx.NewId(), 'CSV\tCtrl+E') menu.Append(ID_EXPORT_CSV, 'CSV\tCtrl+E')
menu.Append(wx.NewId(), 'TeX') #menu.Append(wx.NewId(), 'TeX')
menubar.Append(menu, 'Export to') menubar.Append(menu, 'Export to')
return menubar return menubar
@ -287,6 +321,37 @@ class LineSelectDialog(wx.Dialog):
self.Layout() self.Layout()
self.Centre(wx.BOTH) self.Centre(wx.BOTH)
class SizeSelector(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, -1, 'Image size', size = (200, 100))
bSizer = wx.BoxSizer(wx.HORIZONTAL)
self.width = wx.SpinCtrl(self)
self.width.SetRange(1, 5000)
self.width.SetValue(800)
bSizer.Add(self.width, 1, wx.EXPAND | wx.LEFT, 5)
self.height = wx.SpinCtrl(self)
self.height.SetRange(1, 5000)
self.height.SetValue(600)
bSizer.Add(self.height, 1, wx.EXPAND | wx.RIGHT, 5)
buttonsSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.AddStretchSpacer(1)
sizer.Add(bSizer, 0, wx.EXPAND | wx.ALL, 0)
sizer.AddStretchSpacer(1)
sizer.Add(buttonsSizer, 0, wx.EXPAND | wx.ALL, 5)
self.SetSizer(sizer)
self.Layout()
self.Centre(wx.BOTH)
def GetValues(self):
return self.width.GetValue(), self.height.GetValue()
class PlotFrame(wx.Frame): class PlotFrame(wx.Frame):
def __init__(self, parent, title): def __init__(self, parent, title):
wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(600, 400)) wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(600, 400))
@ -299,3 +364,40 @@ class PlotFrame(wx.Frame):
self.plot.SetEnableLegend(True) self.plot.SetEnableLegend(True)
self.Centre(wx.BOTH) self.Centre(wx.BOTH)
menubar = wx.MenuBar()
menu = wx.Menu()
menu.Append(ID_SAVE_PLOT, 'Save to file\tCtrl+S')
menubar.Append(menu, 'Plot')
self.SetMenuBar(menubar)
class AboutDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title = 'About Opal', size = (300, 330))
title = 'Opal System'
version = 'Aurora version'
copyr = '(c) 2012 Anton Vakhrushev'
self.SetBackgroundColour(wx.Colour(42, 42, 40))
img = wx.StaticBitmap(self)
img.SetBitmap(wx.Bitmap('share/opal_logo.png'))
st = wx.StaticText(self, -1, title,
pos = (15, 170), size = (270, 100))
st.SetForegroundColour(wx.Colour(245, 245, 0))
st.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.NORMAL, False, "Verdana"));
st = wx.StaticText(self, -1, version,
pos = (25, 215), size = (250, 20))
st.SetForegroundColour(wx.Colour(240, 240, 240))
st.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, "Verdana"));
st = wx.StaticText(self, -1, copyr,
pos = (25, 255), size = (250, 30))
st.SetForegroundColour(wx.Colour(240, 240, 240))
st.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, False, "Verdana"));
self.Centre(wx.BOTH)

View File

@ -33,7 +33,7 @@ class ModelData:
# если мы создаем набор данных из другого набора данных # если мы создаем набор данных из другого набора данных
elif isinstance(model, ModelData): elif isinstance(model, ModelData):
self.mdef = model.mdef.Copy() self.mdef = model.mdef.Copy()
self.jid = server.CreateJob() if model.jid != None else None self.jid = server.CreateJob() if model.jid else None
else: else:
self.mdef = None self.mdef = None
self.jid = None self.jid = None
@ -133,6 +133,9 @@ class MainFrame(forms.MainFrame):
self.Bind(wx.EVT_MENU, self.OnAddMarkers, self.Bind(wx.EVT_MENU, self.OnAddMarkers,
id = forms.ID_ADD_MARKERS) id = forms.ID_ADD_MARKERS)
self.Bind(wx.EVT_MENU, self.OnAbout,
id = forms.ID_ABOUT)
# События приложения # События приложения
self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_CLOSE, self.OnClose)
@ -158,6 +161,11 @@ class MainFrame(forms.MainFrame):
self.server.Stop() self.server.Stop()
self.Destroy() self.Destroy()
def OnAbout(self, event):
self.do_nothing = True
forms.AboutDialog(self).ShowModal()
self.do_nothing = False
def OnIdle(self, event): def OnIdle(self, event):
pass pass
@ -226,6 +234,23 @@ class MainFrame(forms.MainFrame):
except Exception, e: except Exception, e:
print 'Error in overseer: ', e print 'Error in overseer: ', e
def item_protector(func):
"""
Защитный механизм, который ловит исключения при неправильном
обращении к элементам деревьев (компоненты TreeCtrl, TreeListCtrl)
Возвращает None, если было поймано исключение.
Использование с функциями, которые не являются обработчиками событий
не желательно
"""
def Checker(*args, **kwargs):
try:
return func(*args, **kwargs)
except ItemError:
print 'Oops'
return Checker
# Функции создания модели, сохранения и загрузки # Функции создания модели, сохранения и загрузки
def BuildSpecs(self, model): def BuildSpecs(self, model):
@ -319,7 +344,7 @@ class MainFrame(forms.MainFrame):
Добавляет пользовательскую модель или спецификацию Добавляет пользовательскую модель или спецификацию
в корень дерева моделей. в корень дерева моделей.
""" """
# строим список моделей, которые будут добавлены
ms = [] ms = []
while model: while model:
ms.append(model) ms.append(model)
@ -342,6 +367,8 @@ class MainFrame(forms.MainFrame):
um.SetPyData(item, data) um.SetPyData(item, data)
if root: if root:
um.Expand(root) um.Expand(root)
um.SelectItem(item)
um.SetFocus()
def OnAddModelToRoot(self, event): def OnAddModelToRoot(self, event):
model = self.GetSelectedData(self.m_specs) model = self.GetSelectedData(self.m_specs)
@ -364,7 +391,9 @@ class MainFrame(forms.MainFrame):
new_data = ModelData(self.server, model, pmdef) new_data = ModelData(self.server, model, pmdef)
um.SetPyData(child, new_data) um.SetPyData(child, new_data)
um.SetItemImage(child, self.icons.mready) um.SetItemImage(child, self.icons.mready)
um.SetFocus()
um.Expand(item) um.Expand(item)
um.SelectItem(child)
else: else:
wx.MessageBox('It\'s impossible to append model', 'Error') wx.MessageBox('It\'s impossible to append model', 'Error')
@ -429,17 +458,37 @@ class MainFrame(forms.MainFrame):
pass pass
def OnParamChanged(self, event): def OnParamChanged(self, event):
def Walk(item):
um.SetItemImage(item, self.icons.mready)
child, _ = um.GetFirstChild(item)
while child.IsOk():
Walk(child)
child = um.GetNextSibling(child)
um = self.m_user_models
prop = event.GetProperty() prop = event.GetProperty()
if not prop: if not prop:
return return
value = prop.GetValue() value = prop.GetValue()
param = prop.GetClientData() param = prop.GetClientData()
item, data = self.GetSelectedItemData(self.m_user_models) item, data = self.GetSelectedItemData(um)
data.mdef[param] = value data.mdef[param] = value
self.m_user_models.SetItemImage(item, self.icons.mready) Walk(item)
def OnTest(self, event): def OnTest(self, event):
def Walk(item):
print um.GetItemText(item)
um.SetItemImage(item, self.icons.mready)
child, cookie = um.GetFirstChild(item)
while child.IsOk():
Walk(child)
child = um.GetNextSibling(child)
um = self.m_user_models um = self.m_user_models
Walk(um.GetRootItem())
# Получение данных выбранной модели # Получение данных выбранной модели
@ -465,6 +514,15 @@ class MainFrame(forms.MainFrame):
# Дублирование модели # Дублирование модели
def Duplicate(self, item_src, item_dst):
um = self.m_user_models
data = um.GetPyData(item_src)
title = um.GetItemText(item_src)
new_data = ModelData(self.server, data)
um.SetItemText(item_dst, self.GenerateName(title))
um.SetPyData(item_dst, new_data)
um.SetItemImage(item_dst, self.icons.mready)
def OnDuplicate(self, event): def OnDuplicate(self, event):
""" """
Обработчик события "дублирование модели" Обработчик события "дублирование модели"
@ -474,17 +532,29 @@ class MainFrame(forms.MainFrame):
Результаты модели-оригинала не копируются. Результаты модели-оригинала не копируются.
""" """
um = self.m_user_models um = self.m_user_models
item, data = self.GetSelectedItemData(self.m_user_models) item_src = self.GetSelectedItem(um)
title = um.GetItemText(item) parent = um.GetItemParent(item_src)
parent = um.GetItemParent(item) item_dst = um.AppendItem(parent, 'new-item')
child = um.AppendItem(parent, self.GenerateName(title)) self.Duplicate(item_src, item_dst)
new_data = ModelData(self.server, data) # self.SetStatusText('Copy for "{}" created'.format(title), 0)
um.SetPyData(child, new_data)
um.SetItemImage(child, self.icons.mready)
self.SetStatusText('Copy for "{}" created'.format(title), 0)
def OnDuplicateTree(self, event): def OnDuplicateTree(self, event):
pass
def Walk(item_src, item_dst):
self.Duplicate(item_src, item_dst)
child_src, _ = um.GetFirstChild(item_src)
while child_src.IsOk():
child_dst = um.AppendItem(item_dst, 'new-item')
Walk(child_src, child_dst)
child_src = um.GetNextSibling(child_src)
um = self.m_user_models
item_src = self.GetSelectedItem(um)
parent = um.GetItemParent(item_src)
item_dst = um.AppendItem(parent, 'new-item')
Walk(item_src, item_dst)
um.Expand(item_dst)
# Удаление модели # Удаление модели
@ -579,6 +649,7 @@ class MainFrame(forms.MainFrame):
else: else:
self.m_plots.SetItemImage(child, self.icons.pline) self.m_plots.SetItemImage(child, self.icons.pline)
@item_protector
def OnAddCurves(self, event): def OnAddCurves(self, event):
self.AddLines(LINE_CURVE) self.AddLines(LINE_CURVE)
@ -749,7 +820,10 @@ class PlotFrame(forms.PlotFrame):
def __init__(self, parent, title, lines): def __init__(self, parent, title, lines):
forms.PlotFrame.__init__(self, parent, title) forms.PlotFrame.__init__(self, parent, title)
colours = ['red', 'blue', 'green'] self.Bind(wx.EVT_MENU, self.OnSaveImage,
id = forms.ID_SAVE_PLOT)
colours = ['red', 'blue', 'green', 'magenta', 'purple', 'brown', 'yellow']
plot_lines = [] plot_lines = []
for i, line in enumerate(lines): for i, line in enumerate(lines):
attr = {} attr = {}
@ -766,6 +840,23 @@ class PlotFrame(forms.PlotFrame):
graph = wxplot.PlotGraphics(plot_lines) graph = wxplot.PlotGraphics(plot_lines)
self.plot.Draw(graph) self.plot.Draw(graph)
def OnSaveImage(self, event):
img_file = wx.FileSelector('Save plot',
default_filename = 'plot.png',
default_extension = 'png',
wildcard = 'PNG files (*.png)|*.png',
flags = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
size_sel = forms.SizeSelector(self)
if img_file and size_sel.ShowModal() == wx.ID_OK:
self.plot.Freeze()
w, h = size_sel.GetValues()
old_size = self.plot.GetSize()
self.plot.SetSize((w, h))
self.plot.SaveFile(img_file)
self.plot.SetSize(old_size)
self.plot.Thaw()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Приложение # Приложение
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------

BIN
trunk/plot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -130,34 +130,26 @@ class LocalServer:
def GetJobsCount(self): def GetJobsCount(self):
return len(self.jobs) return len(self.jobs)
#def CheckJID(self, func):
# def
def GetJobState(self, jid): def GetJobState(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: if job:
return job.GetState() return job.GetState()
def IsJobChanged(self, jid): def IsJobChanged(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: return job.IsChanged() if job else False
return job.IsChanged()
else:
False
def GetJobResult(self, jid): def GetJobResult(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: return job.GetResult() if job else None
return job.GetResult()
def GetJobTID(self, jid): def GetJobTID(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: return job.tid if job else None
return job.tid
def LaunchJob(self, jid, data_def): def LaunchJob(self, jid, data_def):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: if job:
tid = data_def.DD.tid tid = data_def.DD.tid
datadump = data_def.PackParams() datadump = data_def.PackParams()
job.Launch(tid, datadump) job.Launch(tid, datadump)
@ -165,12 +157,12 @@ class LocalServer:
def StopJob(self, jid): def StopJob(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: if job:
job.Stop() job.Stop()
def DeleteJob(self, jid): def DeleteJob(self, jid):
job = self.jobs.get(jid) job = self.jobs.get(jid)
if job != None: if job:
job.Stop() job.Stop()
del self.jobs[jid] del self.jobs[jid]
@ -317,8 +309,8 @@ class Job:
self.ChangeState() self.ChangeState()
def Stop(self): def Stop(self):
WriteToLog('Try to kill')
if self.proc and self.proc.poll() == None: if self.proc and self.proc.poll() == None:
WriteToLog('Try to kill')
self.proc.kill() self.proc.kill()
self.ChangeState() self.ChangeState()
WriteToLog('Job killed') WriteToLog('Job killed')

BIN
trunk/share/app-about.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

BIN
trunk/share/model-add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

BIN
trunk/share/model-dup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

BIN
trunk/share/model-go.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

BIN
trunk/share/opal_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
trunk/share/report-show.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B