about dialog, toolbar, plot saving, many bugfixes

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

120
forms.py
View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import sys
import wx
import wx.gizmos
import wx.grid
@ -29,6 +30,10 @@ ID_ADD_MARKERS = wx.NewId()
ID_ABOUT = wx.NewId()
ID_EXPORT_CSV = wx.NewId()
ID_SAVE_PLOT = wx.NewId()
class TreeListCtrl(wx.gizmos.TreeListCtrl):
def __iter__(self):
return TreeListCtrlIterator(self)
@ -137,8 +142,7 @@ class MainFrame(wx.Frame):
self.BuildContextMenu()
# tbar = self.BuildToolBar()
# self.SetToolBar(tbar)
self.BuildToolBar()
self.auimgr.Update()
@ -171,7 +175,7 @@ class MainFrame(wx.Frame):
menu.Append(ID_ADD_MODEL_SELECTED, 'Append model to selected')
menu.AppendSeparator()
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.AppendSeparator()
menu.Append(ID_TEST, "&Test\tCtrl+T")
@ -211,11 +215,41 @@ class MainFrame(wx.Frame):
self.m_plots.Bind(wx.EVT_CONTEXT_MENU,
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):
tbar = wx.ToolBar(self, -1)
tbar.AddLabelTool(ID_SHOW_PLOT, 'Plot', wx.Bitmap('share/show-plot.png'))
tbar.Realize()
return tbar
tb1 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
agwStyle = aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_VERTICAL)
tb1.SetToolBitmapSize(wx.Size(16, 16))
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):
def __init__(self, parent):
@ -259,8 +293,8 @@ class ResultFrame(wx.Frame):
menubar = wx.MenuBar()
menu = wx.Menu()
menu.Append(wx.NewId(), 'CSV\tCtrl+E')
menu.Append(wx.NewId(), 'TeX')
menu.Append(ID_EXPORT_CSV, 'CSV\tCtrl+E')
#menu.Append(wx.NewId(), 'TeX')
menubar.Append(menu, 'Export to')
return menubar
@ -287,6 +321,37 @@ class LineSelectDialog(wx.Dialog):
self.Layout()
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):
def __init__(self, parent, title):
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.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)

119
opal.py
View File

@ -33,7 +33,7 @@ class ModelData:
# если мы создаем набор данных из другого набора данных
elif isinstance(model, ModelData):
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:
self.mdef = None
self.jid = None
@ -133,6 +133,9 @@ class MainFrame(forms.MainFrame):
self.Bind(wx.EVT_MENU, self.OnAddMarkers,
id = forms.ID_ADD_MARKERS)
self.Bind(wx.EVT_MENU, self.OnAbout,
id = forms.ID_ABOUT)
# События приложения
self.Bind(wx.EVT_CLOSE, self.OnClose)
@ -158,6 +161,11 @@ class MainFrame(forms.MainFrame):
self.server.Stop()
self.Destroy()
def OnAbout(self, event):
self.do_nothing = True
forms.AboutDialog(self).ShowModal()
self.do_nothing = False
def OnIdle(self, event):
pass
@ -226,6 +234,23 @@ class MainFrame(forms.MainFrame):
except Exception, 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):
@ -319,7 +344,7 @@ class MainFrame(forms.MainFrame):
Добавляет пользовательскую модель или спецификацию
в корень дерева моделей.
"""
# строим список моделей, которые будут добавлены
ms = []
while model:
ms.append(model)
@ -342,6 +367,8 @@ class MainFrame(forms.MainFrame):
um.SetPyData(item, data)
if root:
um.Expand(root)
um.SelectItem(item)
um.SetFocus()
def OnAddModelToRoot(self, event):
model = self.GetSelectedData(self.m_specs)
@ -364,7 +391,9 @@ class MainFrame(forms.MainFrame):
new_data = ModelData(self.server, model, pmdef)
um.SetPyData(child, new_data)
um.SetItemImage(child, self.icons.mready)
um.SetFocus()
um.Expand(item)
um.SelectItem(child)
else:
wx.MessageBox('It\'s impossible to append model', 'Error')
@ -429,17 +458,37 @@ class MainFrame(forms.MainFrame):
pass
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()
if not prop:
return
value = prop.GetValue()
param = prop.GetClientData()
item, data = self.GetSelectedItemData(self.m_user_models)
item, data = self.GetSelectedItemData(um)
data.mdef[param] = value
self.m_user_models.SetItemImage(item, self.icons.mready)
Walk(item)
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
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):
"""
Обработчик события "дублирование модели"
@ -474,17 +532,29 @@ class MainFrame(forms.MainFrame):
Результаты модели-оригинала не копируются.
"""
um = self.m_user_models
item, data = self.GetSelectedItemData(self.m_user_models)
title = um.GetItemText(item)
parent = um.GetItemParent(item)
child = um.AppendItem(parent, self.GenerateName(title))
new_data = ModelData(self.server, data)
um.SetPyData(child, new_data)
um.SetItemImage(child, self.icons.mready)
self.SetStatusText('Copy for "{}" created'.format(title), 0)
item_src = self.GetSelectedItem(um)
parent = um.GetItemParent(item_src)
item_dst = um.AppendItem(parent, 'new-item')
self.Duplicate(item_src, item_dst)
# self.SetStatusText('Copy for "{}" created'.format(title), 0)
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:
self.m_plots.SetItemImage(child, self.icons.pline)
@item_protector
def OnAddCurves(self, event):
self.AddLines(LINE_CURVE)
@ -749,7 +820,10 @@ class PlotFrame(forms.PlotFrame):
def __init__(self, parent, title, lines):
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 = []
for i, line in enumerate(lines):
attr = {}
@ -766,6 +840,23 @@ class PlotFrame(forms.PlotFrame):
graph = wxplot.PlotGraphics(plot_lines)
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
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):
return len(self.jobs)
#def CheckJID(self, func):
# def
def GetJobState(self, jid):
job = self.jobs.get(jid)
if job != None:
if job:
return job.GetState()
def IsJobChanged(self, jid):
job = self.jobs.get(jid)
if job != None:
return job.IsChanged()
else:
False
return job.IsChanged() if job else False
def GetJobResult(self, jid):
job = self.jobs.get(jid)
if job != None:
return job.GetResult()
return job.GetResult() if job else None
def GetJobTID(self, jid):
job = self.jobs.get(jid)
if job != None:
return job.tid
return job.tid if job else None
def LaunchJob(self, jid, data_def):
job = self.jobs.get(jid)
if job != None:
if job:
tid = data_def.DD.tid
datadump = data_def.PackParams()
job.Launch(tid, datadump)
@ -165,12 +157,12 @@ class LocalServer:
def StopJob(self, jid):
job = self.jobs.get(jid)
if job != None:
if job:
job.Stop()
def DeleteJob(self, jid):
job = self.jobs.get(jid)
if job != None:
if job:
job.Stop()
del self.jobs[jid]
@ -317,8 +309,8 @@ class Job:
self.ChangeState()
def Stop(self):
WriteToLog('Try to kill')
if self.proc and self.proc.poll() == None:
WriteToLog('Try to kill')
self.proc.kill()
self.ChangeState()
WriteToLog('Job killed')

BIN
share/app-about.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

BIN
share/model-add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

BIN
share/model-delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

BIN
share/model-dup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

BIN
share/model-go.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

BIN
share/opal_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
share/report-show.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B