| 
  
  
    
      
      
      
        
         Obsah sekce: - Univerzální MessageBox
  
      - Tip na efektivní zálohování (backup) hodnot
  
      - Archivace změn hodnot (journal) pomocí datové sekce
          archive
  
      - Proměnné časování přístroje
  
      - Vícerozměrná pole
  
      - Jak automaticky odhlásit uživatele?
  
      - Jak omezit počet vybraných položek v přístroji multi_switch v
          módu check_box.
  
      - Jak měnit barvy pro jednotlivé stavy v přístroji
          multi_label.
  
      - Převod bitové reprezentace reálného čísla s jednoduchou
          přesností na shortreal
  
      - Jak zapsat hodnotu z přístroje s jedním výstupem (control,
          switch, apod.) na více datových elementů?
  
      - Jak nastavit počítání čísla týdne v roce podle českých
          zvyklostí
  
       
      
      
        Univerzální MessageBox
          
          
            Potřebujete zobrazovat různá hlášení za běhu aplikace, na které
            musí obsluha zareagovat? Příklad MessageBox ukazuje jak na to. 
            
            Download: MessageBox.zip 
          
        
        Tip na efektivní zálohování (backup) hodnot
          
          
            Příklad BackupOnChange.cw ukazuje jak automaticky
            aktivovat zálohování hodnot (backup) při změně hodnoty datového
            elementu. 
            settings
  ...
  backup
    method = on_demand;
  end_backup;
  ...
end_settings;
...
data
  var X {backuped = true};
    b1 : boolean;
    b2 : boolean {backuped = false};
    r1 : real;
    r2 : real {backuped = false};
    procedure OnScalarLogicalChange( var DataElement : boolean );
    begin
      (*
      Procedura je vyvolána vždy, když dojde ke změne skalárního booleanovského datového elementu.
      Backup() se volá jen pro datové elementy, které mají nastaven atribut backuped na true.
      *)
      if DataElement:backuped then
        Backup();
      end;
    end_procedure;
    procedure OnScalarNumericalChange( var DataElement : real );
    begin
      (*
      Procedura je vyvolána vždy, když dojde ke změne skalárního numerického datového elementu.
      Backup() se volá jen pro datové elementy, které mají nastaven atribut backuped na true.
      *)
      if DataElement:backuped then
        Backup();
      end;
    end_procedure;
  end_var;
end_data;
            
            Download: BackupOnChange.cw 
          
        
        Archivace změn hodnot (journal) pomocí datové sekce
          archive
          
          
            Příklad Journal.cw ukazuje možnost archivace změn hodnot
            (obdoba přístroje journal) pomocí datové sekce
            archive a událostních procedur datových sekcí. Výhodou tohoto
            řešení je možnost sdílet tyto události v distribuovaných
            aplikacích a jejich prohlížení pomocí přístroje data_viewer. 
            Aplikace využíva uživatelských atributů user0 a
            user1, kde v atributu user0 je uložen
            text, popisující událost a atribut user1 slouží pro
            uchování původní hodnoty datového elementu. Pro vyhodnocení změn
            hodnot datových elementů jsou použity událostní procedury datových
            sekcí On*Change. 
              archive Journal;
    Message : string {comment = 'Message'};
    NewValue : string {comment = 'New value'};
    OldValue : string {comment = 'Old value'};
    Operator : string {init_value = 'none'; comment = 'Operator'; user0 = 'User changed'};
    DataElement : string {comment = 'Data element'};
    procedure Notify( DE, Msg, OldVal, NewVal : string );
    begin
      DataElement = DE;
      Message = Msg;
      OldValue = OldVal;
      NewValue = NewVal;
      Archive();
    end_procedure;
    procedure On_Operator_Change();
    begin
      Notify( 'Operator', Operator:user0, Operator:user1, Operator:value_string );
      Operator:user1 = Operator:value_string;
    end_procedure;
  end_archive;
  var LogVars;
    b : boolean {user0 = 'Boolean value changed'};
    r : real {user0 = 'Real value changed'};
    s : string {user0 = 'String value changed'};
    procedure OnScalarLogicalChange( var DataElement : boolean );
    begin
      Journal.Notify( DataElement:long_name, DataElement:user0, DataElement:user1, DataElement:value_string );
      DataElement:user1 = DataElement:value_string; (* Save current value to user1 atribute *)
    end_procedure;
    procedure OnScalarNumericalChange( var DataElement : real );
    begin
      Journal.Notify( DataElement:long_name, DataElement:user0, DataElement:user1, DataElement:value_string );
      DataElement:user1 = DataElement:value_string; (* Save current value to user1 atribute *)
    end_procedure;
    procedure OnScalarStringChange( var DataElement : string );
    begin
      Journal.Notify( DataElement:long_name, DataElement:user0, DataElement:user1, DataElement:value_string );
      DataElement:user1 = DataElement:value_string; (* Save current value to user1 atribute *)
    end_procedure;
  end_var;
            Download: Journal.cw 
          
        
        Proměnné časování přístroje
          
          
            Potřebujete-li u přístroje měnit periodu časování, můžete to
            vyřešit tak, že parametr period nastavíte na hodnotu
            infinite a přepíšete událostní proceduru OnActivate
            příslušného přístroje tak, jak je uvedeno v následujícím
            příkladu: 
            var
  Period : real {init_value = 1};
end_var;
procedure OnActivate();
begin
  pause Period;
  send self;  
end_procedure;
            Download: VariableTiming.cw 
          
        
        Vícerozměrná pole
          
          
            Control Web umožňuje pracovat pouze
            s jednorozměrným polem. Pokud potřebujete vícerozměné pole, můžete
            se inspirovat následujícím příkladem, který ukazuje práci
            s dvourozměrným polem. 
              var Array;
    A1 : array[ 0..49 ] of real {comment = 'array [0..9][0..4] of real'; user0 = '9'; user1 = '4'};
    A2 : array[ 0..39 ] of real {comment = 'array [0..19][0..1] of real'; user0 = '19'; user1 = '1'};
    procedure idx( Array : array of real; x, y : integer ): cardinal;
    var
      i      : cardinal;
      lindex : integer;
      SizeX  : integer;
      SizeY  : integer;
    begin
      lindex = loindex(Array);
      SizeX = val(Array[ loindex(Array)]:user0, 10);
      SizeY = val(Array[ loindex(Array)]:user1, 10);
      if (x >= 0) and (x <= SizeX) and (y >=0 ) and (y <= SizeY) then
        return x + y * SizeX;
      else
        core.DebugOutput( 'ERROR: Index out of range. ' + Array[lindex]:name + '[' + x:s + ', ' + y:s + '] (' + Array[lindex]:name + ' : ' + Array[0]:comment + ')' );
        core.StopApplication();
      end;
    end_procedure;
    procedure GetItem( Array : array of real; x, y : cardinal ): real;
    begin
      return Array[ idx(Array, x, y ) ];
    end_procedure;
    procedure SetItem( Array : array of real; x, y : cardinal; Value : real );
    begin
      Array[ idx(Array, x, y ) ] = Value;
    end_procedure;
  end_var;
...
  procedure xy();
  var
    r : real;
  begin
    Array.SetItem( Array.A1, 1, 2, 10 );
    r = Array.GetItem( Array.A2, 9, 1, 10 );
  end_procedure;
          
        
        Jak automaticky odhlásit uživatele?
          
          
          
            Aplikace AutoLogout.cw ukazuje, jak lze vyřešit
            automatické odhlášení přihlášeného uživatele do aplikace v systému
            Control Web po definované době nečinnosti. 
          
        
        Jak omezit počet vybraných položek v přístroji multi_switch v
          módu check_box.
          
          
            Jednoduchá aplikace demonstrující omezeni počtu vybraných
            položek v přístroji multi_switch v módu check_box. 
             var
    ba : array[ 1..5 ] of boolean;
  end_var;
  multi_switch switch_1;
    const
      maxSelected = 3;
    end_const;
    static
      NoOfSelected : cardinal;
    end_static;
    owner = background;
    position = 35, 35, 59, 77;
    mode = check_box;
    item
      output = ba[1];
      text = ' Item 1';
    end_item;
    item
      output = ba[2];
      text = ' Item 2';
    end_item;
    item
      output = ba[3];
      text = ' Item 3';
    end_item;
    item
      output = ba[4];
      text = ' Item 4';
    end_item;
    item
      output = ba[5];
      text = ' Item 5';
    end_item;
    
    procedure OnIndexOutput( Index : longint; Output : boolean );
    begin
      if Output <> ba[Index] then
        if Output then
          if NoOfSelected = maxSelected then
            Output = false;
            Update(false);
          else
            NoOfSelected = NoOfSelected + 1;
          end; (* if *)
        else
          NoOfSelected = NoOfSelected - 1;
        end; (* if *)
      end; (* if *)
    end_procedure;
    
  end_multi_switch;
            Download: CheckBoxRestriction.cw 
          
        
        Jak měnit barvy pro jednotlivé stavy v přístroji
          multi_label.
          
          
          
            Pokud potřebujete zobrazovat texty a pozadí jednotlivých
            položek v přístroji multi_label různými barvami,
            můžete to udělat pomocí OCL procedur přístroje například
            takto: 
             multi_label mlbl;
    gui
      owner = pSample;
      position = 100, 40, 60, 20;
      window
        disable = zoom, maximize;
      end_window;
    end_gui;
    justify = center;
    item
      expression = BoolArray[0];
      text_list
        font = font_caption;
        text = 'Text 1';
      end_text_list;
    end_item;
    item
      expression = BoolArray[1];
      text_list
        font = font_caption;
        text = 'Text 2';
      end_text_list;
    end_item;
    item
      expression = BoolArray[2];
      text_list
        font = font_caption;
        text = 'Text 3';
      end_text_list;
    end_item;
    item
      expression = BoolArray[3];
      text_list
        font = font_caption;
        text = 'Text 4';
      end_text_list;
    end_item;
    procedure OnStartup();
    begin
      send self;
    end_procedure;
    procedure OnIndex( Index : longint );
    begin
      switch Index of
      case 1;
        SetColor( 'ink', 'white' );
        SetColor( 'paper', 'lred' );
      case 2;
        SetColor( 'ink', 'lyellow' );
        SetColor( 'paper', 'lgreen' );
      case 3;
        SetColor( 'ink', 'lcyan' );
        SetColor( 'paper', 'lblue' );
      case 4;
        SetColor( 'ink', 'lred' );
        SetColor( 'paper', 'black' );
      end; (* switch *)
    end_procedure;
  end_multi_label;
            Download: multi_label_ChangeColor.cw 
          
        
        Převod bitové reprezentace reálného čísla s jednoduchou
          přesností na shortreal
          
          
            Bitová reprezentace reálného čísla s jednoduchou přesností ve
            formátu definovaném podle IEEE 754 je následující: 
            
            Pro reprezentovanou hodnotu reálného čísla R platí: 
            
            Příklad převodu:    
            procedure BytesToFloat( b0, b1, b2, b3 : shortcard ): shortreal;
var
  b, e, m, s : longcard;
  E, M       : real;
  i          : integer;
begin
  b = bitshl( b3, 24 ) + bitshl( b2, 16 ) + bitshl( b1, 8 ) + b0;
  m = bitand(b, val('7FFFFF', 16 ));
  e = bitshr(bitand(b, val('7F800000', 16 )), 23);
  s = bitget(b, 31);
  for i = 0 to 7 do
    E = E + bitget( e, i ) * pow( 2, i );
    M = M + bitget( m, 23 - i ) * pow( 2, -i );
  end;
  for i = 8 to 23 do
    M = M + bitget( m, 23 - i ) * pow( 2, -i );
  end;
  if (E >= 1) and (E <=254) then
    return pow(-1, s) * pow( 2, E-127) * (1 + M); (* basic format *)
  elsif (E = 0) and (M <> 0) then
    return pow(-1, s) * pow( 2, -126) * M; (* denormalized number *)
  elsif (E = 0) and (M = 0) then
    return 0;
  elsif (E = 255) and (M = 0) then
    if s = 0 then
      return MaxShortReal; (* plus infinity *)
    else
      return MinShortReal; (* minus infinity *)
    end;
  else (* (E = 255) and (M > 0) *)
    core.DebugOutput( 'ERROR: Invalid number mask' );
    core.StopApplication();
  end;
end_procedure;
            Download: Float to-from Four Bytes Conversion (IEEE754
            format).cw 
          
        
        Jak zapsat hodnotu z přístroje s jedním výstupem (control,
          switch, apod.) na více datových elementů?
          
          
            Tyto přístroje mají událostní proceduru OnOutput,
            která je vyvolávána vždy po zadání hodnoty. Do této procedury je v
            parametru Output předávána právě zadaná hodnota,
            kterou pak můžeme jednoduše přiřadit na příslušné datové
            elementy. 
            Příklad:    
            control MyControl;
  procedure OnOutput( Output : real );
  begin
    data_element1 = Output;
    data_element2 = Output;
    data_element3 = Output > 50;
    ...
    data_elementN = k1 + Output * k2;
  end_procedure;
end_control;  
            Jak je vidět na příkladu, lze takto na datové elementy přířadit
            i hodnotu získanou vyčíslením výrazu. 
          
        
        Jak nastavit počítání čísla týdne v roce podle českých
          zvyklostí
          
          
          
            Pokud potřebujete prohlížet archivy sledovaných veličin
            v přístroji data_viewer, máte možnost nastavit
            počátek časové osy dialogem. Datum a čas lze zadat ručně vepsáním
            do editačních polí, nebo lze otevřít pomocný dialog s kalendářem
            pro výběr dne. Možná Vás zarazilo, že v zobrazeném kalendáři
            nesedí čísla týdnů. Problém je v tom, že kalendář
            respektuje nastavení operačního systému a pokud toto není pro dané
            národní prostředí správné, nesouhlasí číslování týdnů. 
             
 Číslování týdnů není podle všeobecně užívaného
              pravidla  
            Sjednat nápravu nelze prostřednictvím okna regionálních
            nastavení. Ačkoliv máte nastaveno české prostředí, číslování týdnů
            v roce nemusí odpovídat. Příčinou je chybně nastavená položka
            LOCALE_IFIRSTWEEKOFYEAR tzv. locale nastavení (více
            informací viz MSDN ). Opravit nastavení lze např. pomocí
            programu Regedit, kdy v klíči HKEY_CURRENT_USER\Control Panel\International
            nastavíte položku iFirstWeekOfYear na hodnotu 2. Od
            tohoto okamžiku bude výpočet proveden podle běžných českých
            zvyklostí a bude stejný jako např. v tištěných kalendářích. 
             
 Číslování podle českých zvyklostí  
          
        
      
    
  
 |