source: sasview/calculatorview/src/sans/perspectives/calculator/density_panel.py @ 986da97

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 986da97 was 0efca36, checked in by Jae Cho <jhjcho@…>, 13 years ago

cleaned up some stuffs

  • Property mode set to 100644
File size: 14.4 KB
Line 
1"""
2This module provide GUI for the mass density calculator
3
4"""
5import wx
6import sys
7from sans.guiframe.panel_base import PanelBase
8from wx.lib.scrolledpanel import ScrolledPanel
9from sans.guiframe.utils import check_float
10from sans.guiframe.events import StatusEvent 
11from periodictable import formula as Formula
12       
13AVOGADRO =  6.02214129e23
14_INPUTS = ['Mass Density', 'Molar Volume']
15_UNITS = ['g/cm^(3)     ', 'cm^(3)/mol ']
16#Density panel size
17if sys.platform.count("win32") > 0:
18    _STATICBOX_WIDTH = 410
19    _BOX_WIDTH = 200
20    PANEL_SIZE = 440
21    FONT_VARIANT = 0
22else:
23    _STATICBOX_WIDTH = 430
24    _BOX_WIDTH = 200
25    PANEL_SIZE = 460
26    FONT_VARIANT = 1
27   
28class DensityPanel(ScrolledPanel, PanelBase):
29    """
30    Provides the mass density calculator GUI.
31    """
32    ## Internal nickname for the window, used by the AUI manager
33    window_name = "Mass Density Calculator"
34    ## Name to appear on the window title bar
35    window_caption = "Mass Density Calculator"
36    ## Flag to tell the AUI manager to put this panel in the center pane
37    CENTER_PANE = True
38   
39    def __init__(self, parent, base=None, *args, **kwds):
40        """
41        """
42        ScrolledPanel.__init__(self, parent, *args, **kwds)
43        PanelBase.__init__(self)
44        self.SetupScrolling()
45        #Font size
46        self.SetWindowVariant(variant=FONT_VARIANT)
47        # Object that receive status event
48        self.base = base
49        # chemeical formula, string
50        self.compound = ''
51        # value of the density/volume, float
52        self.input = None
53        # text controls
54        self.compound_ctl = None
55        self.input_ctl = None
56        self.molar_mass_ctl = None
57        self.output_ctl = None
58        self.ctr_color = self.GetBackgroundColour()
59        # button
60        self.button_calculate = None
61        # list
62        self._input_list = _INPUTS
63        self._input = self._input_list[1]
64        self._output = self._input_list[0]
65        self._unit_list = _UNITS
66        #Draw the panel
67        self._do_layout()
68        self.SetAutoLayout(True)
69        self.Layout()
70       
71    def _do_layout(self):
72        """
73        Draw window content
74        """
75        # units
76        unit_density = self._unit_list[0]
77        unit_volume = self._unit_list[1]
78       
79        # sizers
80        sizer_input = wx.GridBagSizer(5, 5)
81        sizer_output = wx.GridBagSizer(5, 5)
82        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
83        self.sizer1 = wx.BoxSizer(wx.HORIZONTAL)
84        self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
85        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
86        vbox  = wx.BoxSizer(wx.VERTICAL)
87       
88        # inputs
89        inputbox = wx.StaticBox(self, -1, "Inputs")
90        boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
91        boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
92        compound_txt = wx.StaticText(self, -1, 'Molecular Formula ')
93        self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
94        self.compound_eg1 = wx.StaticText(self, -1, '     e.g., H2O')
95        self.compound_eg2 = wx.StaticText(self, -1, 'e.g., D2O')
96        self.input_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
97        wx.EVT_COMBOBOX(self.input_cb, -1, self.on_select_input) 
98        hint_input_name_txt = 'Mass or volume.'
99        self.input_cb.SetToolTipString(hint_input_name_txt) 
100        unit_density1 = "     " + unit_density
101        self.input_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
102        self.unit_input_density = wx.StaticText(self, -1, unit_density1)
103        self.unit_input_volume = wx.StaticText(self, -1, unit_volume)
104        iy = 0
105        ix = 0
106        sizer_input.Add(compound_txt, (iy, ix), (1, 1),
107                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
108        ix += 1
109        sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
110                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
111        ix += 1
112        sizer_input.Add(self.compound_eg1, (iy, ix), (1, 1),
113                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
114       
115        ix += 1
116        sizer_input.Add(self.compound_eg2, (iy, ix), (1, 1),
117                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
118        self.compound_eg1.Show(False)
119        iy += 1
120        ix = 0
121        sizer_input.Add(self.input_cb, (iy, ix), (1, 1),
122                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
123        ix += 1
124        sizer_input.Add(self.input_ctl, (iy, ix), (1, 1),
125                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
126        ix +=1
127        sizer_input.Add(self.unit_input_density,(iy, ix), (1, 1),
128                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
129        ix +=1
130        self.unit_input_density.Show(False)
131        sizer_input.Add(self.unit_input_volume,(iy, ix), (1, 1),
132                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
133        boxsizer1.Add(sizer_input)
134        self.sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
135       
136        # outputs
137        outputbox = wx.StaticBox(self, -1, "Outputs")
138        boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
139        boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
140       
141        molar_mass_txt = wx.StaticText(self, -1, 'Molar Mass ')
142        self.molar_mass_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
143        self.molar_mass_ctl.SetEditable(False)
144        self.molar_mass_ctl.SetBackgroundColour(self.ctr_color)
145        self.molar_mass_unit1 = wx.StaticText(self, -1, '     g/mol')
146        self.molar_mass_unit2 = wx.StaticText(self, -1, 'g/mol')
147       
148        self.output_cb = wx.ComboBox(self, -1, style=wx.CB_READONLY)
149        wx.EVT_COMBOBOX(self.output_cb, -1, self.on_select_output) 
150        hint_output_name_txt = 'Mass or volume.'
151        self.output_cb.SetToolTipString(hint_output_name_txt) 
152        list = []
153        for item in self._input_list:
154            name = str(item)
155            list.append(name)
156        list.sort()
157        for idx in range(len(list)):
158            self.input_cb.Append(list[idx],idx)
159            self.output_cb.Append(list[idx],idx)
160        self.input_cb.SetStringSelection("Molar Volume") 
161        self.output_cb.SetStringSelection("Mass Density") 
162        unit_volume = "     " + unit_volume
163        self.output_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
164        self.output_ctl.SetEditable(False)
165        self.output_ctl.SetBackgroundColour(self.ctr_color)
166        self.unit_output_density = wx.StaticText(self, -1, unit_density)
167        self.unit_output_volume = wx.StaticText(self, -1, unit_volume)
168        iy = 0
169        ix = 0
170        sizer_output.Add(molar_mass_txt, (iy, ix), (1, 1),
171                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
172        ix += 1
173        sizer_output.Add(self.molar_mass_ctl, (iy, ix), (1, 1),
174                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
175        ix += 1
176        sizer_output.Add(self.molar_mass_unit1, (iy, ix), (1, 1),
177                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
178        ix += 1
179        sizer_output.Add(self.molar_mass_unit2, (iy, ix), (1, 1),
180                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
181        self.molar_mass_unit1.Show(False)
182        iy += 1
183        ix = 0
184        sizer_output.Add(self.output_cb, (iy, ix), (1, 1),
185                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
186        ix += 1
187        sizer_output.Add(self.output_ctl, (iy, ix), (1, 1),
188                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
189        ix +=1
190        sizer_output.Add(self.unit_output_volume,
191                         (iy, ix), (1, 1), wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
192        ix += 1
193        sizer_output.Add(self.unit_output_density,
194                         (iy, ix), (1, 1), wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
195       
196        self.unit_output_volume.Show(False)
197        boxsizer2.Add(sizer_output)
198        self.sizer2.Add(boxsizer2, 0, wx.EXPAND|wx.ALL, 10)
199       
200        # buttons
201        id = wx.NewId()
202        self.button_calculate = wx.Button(self, id, "Calculate")
203        self.button_calculate.SetToolTipString("Calculate.")
204        self.Bind(wx.EVT_BUTTON, self.calculate, id=id)   
205       
206        sizer_button.Add((250, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
207        sizer_button.Add(self.button_calculate, 0, 
208                                        wx.RIGHT|wx.ADJUST_MINSIZE, 20)
209        sizer3.Add(sizer_button)
210       
211        # layout
212        vbox.Add(self.sizer1)
213        vbox.Add(self.sizer2)
214        vbox.Add(sizer3)
215        vbox.Fit(self) 
216        self.SetSizer(vbox)
217   
218    def on_select_input(self, event):
219        """
220        On selection of input combobox,
221        update units and output combobox
222        """
223        if event == None:
224            return
225        event.Skip()
226       
227        combo = event.GetEventObject()
228        self._input = combo.GetValue()
229        for name in self._input_list:
230            if self._input != name:
231                self._output = name
232                break
233
234        self.set_values()
235   
236    def on_select_output(self, event):
237        """
238        On selection of output combobox,
239        update units and input combobox
240        """
241        if event == None:
242            return
243        event.Skip()
244       
245        combo = event.GetEventObject()
246        self._output = combo.GetValue()
247        for name in self._input_list:
248            if self._output != name:
249                self._input = name
250                break
251
252        self.set_values()
253 
254    def set_values(self):
255        """
256        Sets units and combobox values
257        """
258        input, output = self.get_input()
259        if input is None:
260            return
261        # input
262        self.input_cb.SetValue(str(input))
263        # output
264        self.output_cb.SetValue(str(output))
265        # unit
266        if self._input_list.index(input) == 0:
267            self.molar_mass_unit1.Show(True)
268            self.molar_mass_unit2.Show(False)
269            self.compound_eg1.Show(True)
270            self.compound_eg2.Show(False)
271            self.unit_input_density.Show(True)
272            self.unit_output_volume.Show(True)
273            self.unit_input_volume.Show(False)
274            self.unit_output_density.Show(False) 
275        else:
276            self.molar_mass_unit1.Show(False)
277            self.molar_mass_unit2.Show(True)
278            self.compound_eg1.Show(False)
279            self.compound_eg2.Show(True)
280            self.unit_input_volume.Show(True)
281            self.unit_output_density.Show(True)
282            self.unit_input_density.Show(False)
283            self.unit_output_volume.Show(False)
284        # layout   
285        self.clear_outputs()
286        self.sizer1.Layout() 
287        self.sizer2.Layout()   
288       
289    def get_input(self):
290        """
291        Return the current input and output combobox values
292        """
293        return self._input, self._output
294   
295    def check_inputs(self):
296        """
297        Check validity user inputs
298        """
299        flag = True
300        msg = ""
301        if check_float(self.input_ctl):
302            self.input = float(self.input_ctl.GetValue())
303        else:
304            flag = False
305            input_type = str(self.input_cb.GetValue())
306            msg += "Error for %s value :expect float"% input_type
307               
308        self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
309        if self.compound != "":
310            try :
311                Formula(self.compound)
312                self.compound_ctl.SetBackgroundColour(wx.WHITE)
313                self.compound_ctl.Refresh()
314            except:
315                self.compound_ctl.SetBackgroundColour("pink")
316                self.compound_ctl.Refresh()
317                flag = False
318                msg += "Enter correct formula"
319        else:
320            self.compound_ctl.SetBackgroundColour("pink")
321            self.compound_ctl.Refresh()
322            flag = False
323            msg += "Enter Formula"
324        return flag, msg
325       
326
327    def calculate(self, event):
328        """
329        Calculate the mass Density/molar Volume of the molecules
330        """
331        self.clear_outputs()
332        try:
333            #Check validity user inputs
334            flag, msg = self.check_inputs()
335            if self.base is not None and msg.lstrip().rstrip() != "":
336                msg = "Density/Volume Calculator: %s" % str(msg)
337                wx.PostEvent(self.base, StatusEvent(status=msg))
338            if not flag:
339               return 
340            #get ready to compute
341            mol_formula = Formula(self.compound)
342            molar_mass = float(mol_formula.molecular_mass) * AVOGADRO
343            output = self._format_number(molar_mass / self.input)
344            self.molar_mass_ctl.SetValue(str(self._format_number(molar_mass)))
345            self.output_ctl.SetValue(str(output))
346        except:
347            if self.base is not None:
348                msg = "Density/Volume Calculator: %s"%(sys.exc_value)
349                wx.PostEvent(self.base, StatusEvent(status=msg))
350        if event is not None:
351            event.Skip()
352           
353    def clear_outputs(self):
354        """
355        Clear the outputs textctrl
356        """
357        self.molar_mass_ctl.SetValue("")
358        self.output_ctl.SetValue("")
359       
360    def _format_number(self, value=None):
361        """
362        Return a float in a standardized, human-readable formatted string
363        """
364        try: 
365            value = float(value)
366        except:
367            output = ''
368            return output
369
370        output = "%-12.5f" % value
371        return output.lstrip().rstrip() 
372       
373class DensityWindow(wx.Frame):
374    """
375    """
376    def __init__(self, parent=None, title="Density/Volume Calculator",
377                  base=None, size=(PANEL_SIZE, PANEL_SIZE/1.7), *args, **kwds):
378        """
379        """
380        kwds['title'] = title
381        kwds['size'] = size
382        wx.Frame.__init__(self, parent, *args, **kwds)
383        """
384        """
385        self.panel = DensityPanel(self, base=base)
386        self.Centre()
387        self.Show(True)
388       
389class ViewApp(wx.App):
390    """
391    """
392    def OnInit(self):
393        """
394        """
395        frame = DensityWindow(None, title="Density/Volume Calculator")   
396        frame.Show(True)
397        self.SetTopWindow(frame)
398        return True
399       
400
401if __name__ == "__main__": 
402    app = ViewApp(0)
403    app.MainLoop()     
Note: See TracBrowser for help on using the repository browser.