Package Gnumed :: Package wxpython :: Module gmKeywordExpansionWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmKeywordExpansionWidgets

  1  # -*- coding: utf8 -*- 
  2  """GNUmed keyword expansion widgets.""" 
  3  #================================================================ 
  4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
  5  __license__ = "GPL v2 or later" 
  6   
  7  import logging 
  8  import sys 
  9  import re as regex 
 10  import os.path 
 11   
 12   
 13  import wx 
 14   
 15   
 16  if __name__ == '__main__': 
 17          sys.path.insert(0, '../../') 
 18  from Gnumed.pycommon import gmDispatcher 
 19  from Gnumed.pycommon import gmPG2 
 20  from Gnumed.pycommon import gmTools 
 21  from Gnumed.business import gmKeywordExpansion 
 22  from Gnumed.wxpython import gmEditArea 
 23  from Gnumed.wxpython import gmListWidgets 
 24   
 25   
 26  _log = logging.getLogger('gm.ui') 
 27   
 28  _text_expansion_fillin_regex = r'\$\[.*\]\$' 
 29   
 30  #============================================================ 
31 -class cKeywordExpansion_TextCtrlMixin():
32
33 - def __init__(self):
34 if not isinstance(self, wx.TextCtrl): 35 raise TypeError('[%s]: can only be applied to wx.TextCtrl, not [%s]' % (cKeywordExpansion_TextCtrlMixin, self.__class__.__name__))
36 #--------------------------------------------------------
38 self.__keyword_separators = regex.compile("[!?'\".,:;)}\]\r\n\s\t]+") 39 self.Bind(wx.EVT_CHAR, self.__on_char_in_keyword_expansion_mixin)
40 #--------------------------------------------------------
42 self.Unbind(wx.EVT_CHAR)
43 #-------------------------------------------------------- 44 # event handling 45 #--------------------------------------------------------
47 evt.Skip() 48 49 # empty ? 50 if self.LastPosition == 1: 51 return 52 53 char = unichr(evt.GetUnicodeKey()) 54 55 explicit_expansion = False 56 if evt.GetModifiers() == (wx.MOD_CMD | wx.MOD_ALT): # portable CTRL-ALT-... 57 if evt.GetKeyCode() == wx.WXK_RETURN: # CTRL-ALT-ENTER 58 explicit_expansion = True 59 elif evt.GetKeyCode() == 20: # CTRL-ALT-T 60 explicit_expansion = True 61 else: 62 return 63 64 if not explicit_expansion: 65 # user did not press CTRL-ALT-ENTER, 66 # however, did they last enter a 67 # "keyword sepearator", active character ? 68 if self.__keyword_separators.match(char) is None: 69 return 70 71 caret_pos, line_no = self.PositionToXY(self.InsertionPoint) 72 line = self.GetLineText(line_no) 73 keyword = self.__keyword_separators.split(line[:caret_pos])[-1] 74 75 if ( 76 (not explicit_expansion) 77 and 78 (keyword != u'$$steffi') # Easter Egg ;-) 79 and 80 (keyword not in [ r[0] for r in gmKeywordExpansion.get_textual_expansion_keywords() ]) 81 ): 82 return 83 84 start = self.InsertionPoint - len(keyword) 85 wx.CallAfter(self.__replace_keyword_with_expansion, keyword, start, explicit_expansion) 86 87 return
88 #-------------------------------------------------------- 89 # internal helpers 90 #--------------------------------------------------------
91 - def __replace_keyword_with_expansion(self, keyword=None, position=None, show_list=False):
92 93 expansion = expand_keyword(parent = self, keyword = keyword, show_list = show_list) 94 95 if expansion is None: 96 return 97 98 if expansion == u'': 99 return 100 101 if not self.IsMultiLine(): 102 expansion_lines = gmTools.strip_leading_empty_lines ( 103 lines = gmTools.strip_trailing_empty_lines ( 104 text = expansion, 105 return_list = True 106 ), 107 return_list = True 108 ) 109 if len(expansion_lines) == 0: 110 return 111 if len(expansion_lines) == 1: 112 expansion = expansion_lines[0] 113 else: 114 msg = _( 115 'The fragment <%s> expands to multiple lines !\n' 116 '\n' 117 'This text field can hold one line only, hwoever.\n' 118 '\n' 119 'Please select the line you want to insert:' 120 ) % keyword 121 expansion = gmListWidgets.get_choices_from_list ( 122 parent = self, 123 msg = msg, 124 caption = _('Adapting multi-line expansion to single-line text field'), 125 choices = expansion_lines, 126 selections = [0], 127 columns = [_('Keyword expansion lines')], 128 single_selection = True, 129 can_return_empty = False 130 ) 131 if expansion is None: 132 return 133 134 self.Replace ( 135 position, 136 position + len(keyword), 137 expansion 138 ) 139 140 self.SetInsertionPoint(position + len(expansion) + 1) 141 self.ShowPosition(position + len(expansion) + 1) 142 143 return
144 145 #============================================================ 146 from Gnumed.wxGladeWidgets import wxgTextExpansionEditAreaPnl 147
148 -class cTextExpansionEditAreaPnl(wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
149
150 - def __init__(self, *args, **kwds):
151 152 try: 153 data = kwds['expansion'] 154 del kwds['expansion'] 155 except KeyError: 156 data = None 157 158 wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl.__init__(self, *args, **kwds) 159 gmEditArea.cGenericEditAreaMixin.__init__(self) 160 161 self.mode = 'new' 162 self.data = data 163 if data is not None: 164 self.mode = 'edit' 165 166 # self.__init_ui() 167 self.__register_interests() 168 169 self.__data_filename = None
170 #-------------------------------------------------------- 171 # def __init_ui(self, expansion=None): 172 # self._BTN_select_data_file.Enable(False) 173 #---------------------------------------------------------------- 174 # generic Edit Area mixin API 175 #----------------------------------------------------------------
176 - def _valid_for_save(self):
177 validity = True 178 179 has_expansion = ( 180 (self._TCTRL_expansion.GetValue().strip() != u'') 181 or 182 (self.__data_filename is not None) 183 or 184 ((self.data is not None) and (self.data['is_textual'] is False)) 185 ) 186 187 if has_expansion: 188 self.display_tctrl_as_valid(tctrl = self._TCTRL_expansion, valid = True) 189 self.display_tctrl_as_valid(tctrl = self._TCTRL_data_file, valid = True) 190 else: 191 validity = False 192 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save keyword expansion without text or data expansion.'), beep = True) 193 self.display_tctrl_as_valid(tctrl = self._TCTRL_expansion, valid = False) 194 self.display_tctrl_as_valid(tctrl = self._TCTRL_data_file, valid = False) 195 if self.data is None: 196 self._TCTRL_expansion.SetFocus() 197 else: 198 if self.data['is_textual']: 199 self._TCTRL_expansion.SetFocus() 200 else: 201 self._BTN_select_data_file.SetFocus() 202 203 if self._TCTRL_keyword.GetValue().strip() == u'': 204 validity = False 205 self.display_tctrl_as_valid(tctrl = self._TCTRL_keyword, valid = False) 206 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save keyword expansion without keyword.'), beep = True) 207 self._TCTRL_keyword.SetFocus() 208 else: 209 self.display_tctrl_as_valid(tctrl = self._TCTRL_keyword, valid = True) 210 211 return validity
212 #----------------------------------------------------------------
213 - def _save_as_new(self):
214 expansion = gmKeywordExpansion.create_keyword_expansion ( 215 keyword = self._TCTRL_keyword.GetValue().strip(), 216 text = self._TCTRL_expansion.GetValue(), 217 data_file = self.__data_filename, 218 public = self._RBTN_public.GetValue() 219 ) 220 221 if expansion is None: 222 return False 223 224 expansion['is_encrypted'] = self._CHBOX_is_encrypted.IsChecked() 225 expansion.save() 226 227 self.data = expansion 228 return True
229 #----------------------------------------------------------------
230 - def _save_as_update(self):
231 232 self.data['expansion'] = self._TCTRL_expansion.GetValue().strip() 233 self.data['is_encrypted'] = self._CHBOX_is_encrypted.IsChecked() 234 self.data.save() 235 236 if self.__data_filename is not None: 237 self.data.update_data_from_file(filename = self.__data_filename) 238 239 return True
240 #---------------------------------------------------------------- 241 #----------------------------------------------------------------
242 - def _refresh_as_new(self):
243 self.__data_filename = None 244 245 self._TCTRL_keyword.SetValue(u'') 246 self._TCTRL_keyword.Enable(True) 247 248 self._LBL_data.Enable(False) 249 self._BTN_select_data_file.Enable(False) 250 self._TCTRL_data_file.SetValue(u'') 251 self._CHBOX_is_encrypted.SetValue(False) 252 self._CHBOX_is_encrypted.Enable(False) 253 254 self._LBL_text.Enable(False) 255 self._TCTRL_expansion.SetValue(u'') 256 self._TCTRL_expansion.Enable(False) 257 258 self._RBTN_public.Enable(False) 259 self._RBTN_private.Enable(False) 260 self._RBTN_public.SetValue(1) 261 262 self._TCTRL_keyword.SetFocus()
263 #----------------------------------------------------------------
265 self._refresh_from_existing() 266 267 self._TCTRL_keyword.SetValue(u'%s%s' % (self.data, _(u'___copy'))) 268 self._TCTRL_keyword.Enable(True) 269 270 self._RBTN_public.Enable(True) 271 self._RBTN_private.Enable(True) 272 273 self._TCTRL_keyword.SetFocus()
274 #----------------------------------------------------------------
275 - def _refresh_from_existing(self):
276 self.__data_filename = None 277 278 self._TCTRL_keyword.SetValue(self.data['keyword']) 279 self._TCTRL_keyword.Enable(False) 280 281 if self.data['is_textual']: 282 self._LBL_text.Enable(True) 283 self._TCTRL_expansion.SetValue(gmTools.coalesce(self.data['expansion'], u'')) 284 285 self._LBL_data.Enable(False) 286 self._BTN_select_data_file.Enable(False) 287 self._TCTRL_data_file.SetValue(u'') 288 self._CHBOX_is_encrypted.SetValue(False) 289 self._CHBOX_is_encrypted.Enable(False) 290 else: 291 self._LBL_text.Enable(False) 292 self._TCTRL_expansion.SetValue(u'') 293 294 self._LBL_data.Enable(True) 295 self._BTN_select_data_file.Enable(True) 296 self._TCTRL_data_file.SetValue(_('Size: %s') % gmTools.size2str(self.data['data_size'])) 297 self._CHBOX_is_encrypted.SetValue(self.data['is_encrypted']) 298 self._CHBOX_is_encrypted.Enable(True) 299 300 self._RBTN_public.Enable(False) 301 self._RBTN_private.Enable(False) 302 if self.data['public_expansion']: 303 self._RBTN_public.SetValue(1) 304 else: 305 self._RBTN_private.SetValue(1) 306 307 if self.data['is_textual']: 308 self._TCTRL_expansion.SetFocus() 309 else: 310 self._BTN_select_data_file.SetFocus()
311 #---------------------------------------------------------------- 312 # event handling 313 #----------------------------------------------------------------
314 - def __register_interests(self):
315 self._TCTRL_keyword.Bind(wx.EVT_TEXT, self._on_keyword_modified) 316 self._TCTRL_expansion.Bind(wx.EVT_TEXT, self._on_expansion_modified)
317 #----------------------------------------------------------------
318 - def _on_keyword_modified(self, evt):
319 if self._TCTRL_keyword.GetValue().strip() == u'': 320 self._LBL_text.Enable(False) 321 self._TCTRL_expansion.Enable(False) 322 self._LBL_data.Enable(False) 323 self._BTN_select_data_file.Enable(False) 324 self._CHBOX_is_encrypted.Enable(False) 325 self._RBTN_public.Enable(False) 326 self._RBTN_private.Enable(False) 327 return 328 329 # keyword is not empty 330 # mode must be new(_from_existing) or else 331 # we cannot modify the keyword in the first place 332 self._LBL_text.Enable(True) 333 self._TCTRL_expansion.Enable(True) 334 self._LBL_data.Enable(True) 335 self._BTN_select_data_file.Enable(True) 336 self._RBTN_public.Enable(True) 337 self._RBTN_private.Enable(True)
338 #----------------------------------------------------------------
339 - def _on_expansion_modified(self, evt):
340 if self._TCTRL_expansion.GetValue().strip() == u'': 341 self._LBL_data.Enable(True) 342 self._BTN_select_data_file.Enable(True) 343 return 344 345 self.__data_filename = None 346 self._LBL_data.Enable(False) 347 self._BTN_select_data_file.Enable(False) 348 self._TCTRL_data_file.SetValue(u'') 349 self._CHBOX_is_encrypted.Enable(False)
350 #----------------------------------------------------------------
351 - def _on_select_data_file_button_pressed(self, event):
352 wildcards = [ 353 u"%s (*)|*" % _('all files'), 354 u"%s (*.*)|*.*" % _('all files (Windows)') 355 ] 356 357 dlg = wx.FileDialog ( 358 parent = self, 359 message = _('Choose the file containing the data snippet'), 360 wildcard = '|'.join(wildcards), 361 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST 362 ) 363 result = dlg.ShowModal() 364 if result != wx.ID_CANCEL: 365 self.__data_filename = dlg.GetPath() 366 self._TCTRL_data_file.SetValue(self.__data_filename) 367 self._CHBOX_is_encrypted.SetValue(False) 368 self._CHBOX_is_encrypted.Enable(True) 369 370 dlg.Destroy()
371 372 #============================================================
373 -def configure_keyword_text_expansion(parent=None):
374 375 if parent is None: 376 parent = wx.GetApp().GetTopWindow() 377 378 #---------------------- 379 def delete(expansion=None): 380 gmKeywordExpansion.delete_keyword_expansion(pk = expansion['pk_expansion']) 381 return True
382 #---------------------- 383 def edit(expansion=None): 384 ea = cTextExpansionEditAreaPnl(parent, -1, expansion = expansion) 385 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea) 386 if expansion is None: 387 title = _('Adding keyword expansion') 388 else: 389 title = _('Editing keyword expansion "%s"') % expansion['keyword'] 390 dlg.SetTitle(title) 391 if dlg.ShowModal() == wx.ID_OK: 392 return True 393 394 return False 395 #---------------------- 396 def tooltip(expansion): 397 return expansion.format() 398 #---------------------- 399 def refresh(lctrl=None): 400 expansions = gmKeywordExpansion.get_keyword_expansions(order_by = u'is_textual DESC, keyword, public_expansion', force_reload = True) 401 items = [[ 402 e['keyword'], 403 gmTools.bool2subst(e['is_textual'], _('text'), _('data')), 404 gmTools.bool2subst(e['public_expansion'], _('public'), _('private')) 405 ] for e in expansions 406 ] 407 lctrl.set_string_items(items) 408 lctrl.set_data(expansions) 409 #---------------------- 410 411 gmListWidgets.get_choices_from_list ( 412 parent = parent, 413 msg = _('\nSelect the keyword you want to edit !\n'), 414 caption = _('Editing keyword-based expansions ...'), 415 columns = [_('Keyword'), _('Type'), _('Scope')], 416 single_selection = True, 417 edit_callback = edit, 418 new_callback = edit, 419 delete_callback = delete, 420 refresh_callback = refresh, 421 list_tooltip_callback = tooltip 422 ) 423 #============================================================ 424 from Gnumed.wxGladeWidgets import wxgTextExpansionFillInDlg 425
426 -class cTextExpansionFillInDlg(wxgTextExpansionFillInDlg.wxgTextExpansionFillInDlg):
427
428 - def __init__(self, *args, **kwds):
429 wxgTextExpansionFillInDlg.wxgTextExpansionFillInDlg.__init__(self, *args, **kwds) 430 431 self.__expansion = None 432 self.__init_ui()
433 #---------------------------------------------
434 - def __init_ui(self):
435 self._LBL_top_part.SetLabel(u'') 436 font = self._LBL_left_part.GetFont() 437 font.SetPointSize(pointSize = font.GetPointSize() + 1) 438 self._LBL_left_part.SetFont(font) 439 self._LBL_left_part.SetLabel(u'') 440 self._LBL_left_part.Hide() 441 font = self._TCTRL_fillin.GetFont() 442 font.SetPointSize(pointSize = font.GetPointSize() + 1) 443 self._TCTRL_fillin.SetFont(font) 444 self._TCTRL_fillin.SetValue(u'') 445 self._TCTRL_fillin.SetBackgroundColour('yellow') 446 self._TCTRL_fillin.Disable() 447 self._TCTRL_fillin.Hide() 448 font = self._LBL_right_part.GetFont() 449 font.SetPointSize(pointSize = font.GetPointSize() + 1) 450 self._LBL_right_part.SetFont(font) 451 self._LBL_right_part.SetLabel(u'') 452 self._LBL_right_part.Hide() 453 self._LBL_bottom_part.SetLabel(u'') 454 self._BTN_OK.Disable() 455 self._BTN_forward.Disable() 456 self._BTN_cancel.SetFocus() 457 self._LBL_hint.SetLabel(u'')
458 #---------------------------------------------
459 - def __goto_next_fillin(self):
460 if self.__expansion is None: 461 return 462 463 if self.__new_expansion: 464 self.__filled_in = self.__expansion 465 self.__new_expansion = False 466 else: 467 self.__filled_in = ( 468 self._LBL_top_part.GetLabel() + 469 self.__left_splitter + 470 self._LBL_left_part.GetLabel() + 471 self._TCTRL_fillin.GetValue().strip() + 472 self._LBL_right_part.GetLabel() + 473 self.__right_splitter + 474 self._LBL_bottom_part.GetLabel() 475 ) 476 477 # anything to fill in ? 478 if regex.search(_text_expansion_fillin_regex, self.__filled_in) is None: 479 # no 480 self._LBL_top_part.SetLabel(self.__filled_in) 481 self._LBL_left_part.SetLabel(u'') 482 self._LBL_left_part.Hide() 483 self._TCTRL_fillin.SetValue(u'') 484 self._TCTRL_fillin.Disable() 485 self._TCTRL_fillin.Hide() 486 self._LBL_right_part.SetLabel(u'') 487 self._LBL_right_part.Hide() 488 self._LBL_bottom_part.SetLabel(u'') 489 self._BTN_OK.Enable() 490 self._BTN_forward.Disable() 491 self._BTN_OK.SetDefault() 492 return 493 494 # yes 495 top, fillin, bottom = regex.split(r'(' + _text_expansion_fillin_regex + r')', self.__filled_in, maxsplit = 1) 496 top_parts = top.rsplit(u'\n', 1) 497 top_part = top_parts[0] 498 if len(top_parts) == 1: 499 self.__left_splitter = u'' 500 left_part = u'' 501 else: 502 self.__left_splitter = u'\n' 503 left_part = top_parts[1] 504 bottom_parts = bottom.split(u'\n', 1) 505 if len(bottom_parts) == 1: 506 parts = bottom_parts[0].split(u' ', 1) 507 right_part = parts[0] 508 if len(parts) == 1: 509 self.__right_splitter = u'' 510 bottom_part = u'' 511 else: 512 self.__right_splitter = u' ' 513 bottom_part = parts[1] 514 else: 515 self.__right_splitter = u'\n' 516 right_part = bottom_parts[0] 517 bottom_part = bottom_parts[1] 518 hint = fillin.strip('$').strip('[').strip(']').strip() 519 self._LBL_top_part.SetLabel(top_part) 520 self._LBL_left_part.SetLabel(left_part) 521 self._LBL_left_part.Show() 522 self._TCTRL_fillin.Enable() 523 self._TCTRL_fillin.SetValue(u'') 524 self._TCTRL_fillin.Show() 525 self._LBL_right_part.SetLabel(right_part) 526 self._LBL_right_part.Show() 527 self._LBL_bottom_part.SetLabel(bottom_part) 528 self._BTN_OK.Disable() 529 self._BTN_forward.Enable() 530 self._BTN_forward.SetDefault() 531 self._LBL_hint.SetLabel(hint) 532 self._TCTRL_fillin.SetFocus() 533 534 self.Layout() 535 self.Fit()
536 #--------------------------------------------- 537 # properties 538 #---------------------------------------------
539 - def _get_expansion(self):
540 return self.__expansion
541
542 - def _set_expansion(self, expansion):
543 self.__expansion = expansion 544 self.__new_expansion = True 545 self.__goto_next_fillin() 546 return
547 548 expansion = property(_get_expansion, _set_expansion) 549 #---------------------------------------------
550 - def _get_filled_in(self):
551 return self.__filled_in
552 553 filled_in_expansion = property(_get_filled_in, lambda x:x) 554 #---------------------------------------------
555 - def _set_keyword(self, keyword):
556 self.SetTitle(_('Expanding <%s>') % keyword)
557 558 keyword = property(lambda x:x, _set_keyword) 559 #--------------------------------------------- 560 # event handlers 561 #---------------------------------------------
562 - def _on_forward_button_pressed(self, event):
563 self.__goto_next_fillin()
564 #============================================================
565 -def expand_keyword(parent=None, keyword=None, show_list=False):
566 """Expand keyword and replace inside it. 567 568 Returns: 569 None: aborted or no expansion available 570 u'': empty expansion 571 u'<text>' the expansion 572 """ 573 if keyword is None: 574 return None 575 576 if parent is None: 577 parent = wx.GetApp().GetTopWindow() 578 579 if show_list: 580 candidates = gmKeywordExpansion.get_matching_textual_keywords(fragment = keyword) 581 if len(candidates) == 0: 582 return None 583 if len(candidates) == 1: 584 keyword = candidates[0] 585 else: 586 keyword = gmListWidgets.get_choices_from_list ( 587 parent = parent, 588 msg = _( 589 'Several macro keywords match the fragment [%s].\n' 590 '\n' 591 'Please select the expansion you want to happen.' 592 ) % keyword, 593 caption = _('Selecting text macro'), 594 choices = candidates, 595 columns = [_('Keyword')], 596 single_selection = True, 597 can_return_empty = False 598 ) 599 if keyword is None: 600 return None 601 602 expansion = gmKeywordExpansion.expand_keyword(keyword = keyword) 603 604 # not found 605 if expansion is None: 606 return None 607 608 # no replacement necessary: 609 if expansion.strip() == u'': 610 return expansion 611 612 if regex.search(_text_expansion_fillin_regex, expansion) is not None: 613 dlg = cTextExpansionFillInDlg(None, -1) 614 dlg.keyword = keyword 615 dlg.expansion = expansion 616 button = dlg.ShowModal() 617 if button == wx.ID_OK: 618 expansion = dlg.filled_in_expansion 619 dlg.Destroy() 620 621 return expansion
622 623 #============================================================ 624 # main 625 #------------------------------------------------------------ 626 if __name__ == '__main__': 627 628 if len(sys.argv) < 2: 629 sys.exit() 630 631 if sys.argv[1] != 'test': 632 sys.exit() 633 634 from Gnumed.pycommon import gmI18N 635 gmI18N.activate_locale() 636 gmI18N.install_domain(domain = 'gnumed') 637 638 #----------------------------------------
639 - def test_fillin():
640 expansion = u"""HEMORR²HAGES: Blutungsrisiko unter OAK 641 -------------------------------------- 642 Am Heart J. 2006 Mar;151(3):713-9. 643 644 $[1 oder 0 eingeben]$ H epatische oder Nierenerkrankung 645 $[1 oder 0 eingeben]$ E thanolabusus 646 $[1 oder 0 eingeben]$ M alignom 647 $[1 oder 0 eingeben]$ O ld patient (> 75 Jahre) 648 $[1 oder 0 eingeben]$ R eduzierte Thrombozytenzahl/-funktion 649 $[2 oder 0 eingeben]$ R²ekurrente (frühere) große Blutung 650 $[1 oder 0 eingeben]$ H ypertonie (unkontrolliert) 651 $[1 oder 0 eingeben]$ A nämie 652 $[1 oder 0 eingeben]$ G enetische Faktoren 653 $[1 oder 0 eingeben]$ E xzessives Sturzrisiko 654 $[1 oder 0 eingeben]$ S Schlaganfall in der Anamnese 655 -------------------------------------- 656 Summe Rate großer Blutungen 657 pro 100 Patientenjahre 658 0 1.9 659 1 2.5 660 2 5.3 661 3 8.4 662 4 10.4 663 >4 12.3 664 665 Bewertung: Summe = $[Summe ausrechnen und bewerten]$""" 666 667 app = wx.PyWidgetTester(size = (600, 600)) 668 dlg = cTextExpansionFillInDlg(None, -1) 669 dlg.expansion = expansion 670 dlg.ShowModal()
671 #app.MainLoop() 672 #---------------------------------------- 673 test_fillin() 674