Autor Beitrag
Chaosworld
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Di 04.04.06 00:39 
Ich habe eine Datenbankanwendung geschrieben für ein chemisches Laboratorium. Ich habe als Teil dessen ein Feld "Formel" in der Parametertabelle erstellt. Die Formeln sehen dann z.B. so aus:
("Rohproteingehalt"-"Bindegewebseiweiß")*100/"Rohproteingehalt"
ich speicher die Formel so:
(#1#-#2#)*100/#1#
wobei die # immer die Nummer des Parameters darstellt
hier ist also
Parameter 1 = Rohproteingehalt und 2 = Bindegewebseiweiß

Die komplette Berechnung klappt auch soweit ohne Probleme (auch komplexere Formeln mit Pozenzen, log,..)

Nun kann keiner wirklich die Formel (#1#-#2#)*100/#1# verstehen. Daher würde ich sie gerne anders darstellen.
Es ist kein Problem die Formel so umzuwandeln, dass z.B. in dem Fall #1# durch "Rohproteingehalt" ersetzt wird. Jedoch könnte man die so erstellte Formel kaum bearbeiten.
Meine Idee ist es nun, dass ich irgendwie ziehbare, feste Objekte erstellt
also so:
(A-B)*100/C
wobei bei A, B und C halt ein Text steht, den ich aber nicht bearbeiten kann, sondern nur komplett löschen kann, oder mit der Maus verschieben kann.
Als für den Anwender soll es zwar so aussehen
("Rohproteingehalt"-"Bindegewebseiweiß")*100/"Rohproteingehalt"
aber es ist nicht möglich aus "Rohproteingehalt" z.B. einfach das "ein" rauszulöschen.

Ich muss nur sagen, dass ich überhaubt keine Idee habe, wie man so etwas realisieren könnte. Mir würden ja schon Hinweise helfen, und welchem Stichpunkt ich vielleicht Informationen finden könnte, um so etwas zu erreichen.


Bin echt für jeden Tipp dankbar, ich selber habe keinerlei Idee und könnte es höchstens mit einer Funktion machen, die die Formel leserlicher macht, aber diese wäre dann nicht mehr bearbeitbar (auf jedenfall nicht so, dass sie eine formel in der Datenbank ergibt, die ich dann an anderer Stelle auch verwenden könnte um den Wert der sich aus der Formel ergibt zu berechnen.

Im vorraus vielen dank für jede Antwort
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 04.04.06 11:56 
Hi Chaosworld

user profile iconChaosworld hat folgendes geschrieben:

("Rohproteingehalt"-"Bindegewebseiweiß")*100/"Rohproteingehalt"
aber es ist nicht möglich aus "Rohproteingehalt" z.B. einfach das "ein" rauszulöschen.


Reine Vorgehensweise:
beim KeyEvent
Suche ausgehend von der Cursorposition recht und links die Zeichen ".
Prüfe ob Cursor innerhalb eines Objekts ist.
wenn ja und (key = "Delete" oder "BackSpace")
Setzte die Markierung (SelStart & SelLength) auf die Grenzen und lösche alles.
wenn ja und (key = "Sichtbares Zeichen")
drop Key (Key = #0)

Das wäre die einfachste Lösung. Benutzerfreundlicher wäre sowas wie die Code-vervollständigung von Delphi.

MfG Simon
Chaosworld Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Di 04.04.06 15:29 
danke für deine Antwort, also dass mit dem KeyEvent würde wahrscheinlich Probleme machen, da ich dass ja irgendwie zurück zu der berechenbaren Formel zurück verwandeln müsste. Ausserdem kann man ja mit der Maus in den Text gehen. Ich denke das wäre am ende nicht wirklich sehr hilfreich.
Das mit der Idee von der art Code-Vervollständigung hört sich gut an, frage ist, weisst du wie ich das mache?

Im vorraus vielen dank

Chaosworld
Chaosworld Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Di 04.04.06 18:24 
Also ich habe hier
synedit.sourceforge.net
eine Komponente gefunden, die die Vervollständigung ermöglicht. Aber dennoch wäre da noch das Problem mit dem automatisch makieren und des nur komplett löschen, selbst wenn man mit der Mause manuell innerhalb ein Element rein klickt.

MFG

Chaosworld
Lannes
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2352
Erhaltene Danke: 4

Win XP, 95, 3.11, IE6
D3 Prof, D4 Standard, D2005 PE, TurboDelphi, Lazarus, D2010
BeitragVerfasst: Di 04.04.06 23:29 
Hallo,
user profile iconChaosworld hat folgendes geschrieben:
...Aber dennoch wäre da noch das Problem mit dem automatisch makieren und des nur komplett löschen, selbst wenn man mit der Mause manuell innerhalb ein Element rein klickt.
hab mal etwas Code bezogen auf ein Editfeld geschrieben, ist nicht voll ausgereift, aber sollte ein guter Ansatz zum weiterentwickeln sein.

Inhalt Edit : '( Rohproteingehalt - Bindegewebseiweiß ) * 100 / Rohproteingehalt'

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
function IsElement(MyE: TEdit;x: Integer): Boolean;
var z,a,e : Integer;
    s,sEle : String;
begin
  Result := False;
  a := 0;
  s := MyE.Text;
  e := Length(s)+1;
  for z := MyE.SelStart downto 1 do
    if s[z] in ['0'..'9',',','-','*','/','+','(',')',' '] then
      begin
      a := z;
      Break;
      end;
  for z := MyE.SelStart + x to Length(s) do
    if s[z] in ['0'..'9',',','-','*','/','+','(',')',' '] then
      begin
      e := z;
      Break;
      end;
  sEle := Copy(s,a+1,e-a-1);
  if Pos(sEle,'Rohproteingehalt,Bindegewebseiweiß') <> 0 then
    begin
    MyE.SelStart := a;
    MyE.SelLength := e-a-1;
    Result := True;
    end;
end;

procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case key of
   VK_Left : if Edit1.SelLength > 0 then
               Edit1.SelStart := Edit1.SelStart+1
               else
                 if IsElement(Edit1,0) then
                   key := 0;
   VK_Right : if Edit1.SelLength > 0 then
                 begin
                 Edit1.SelStart := Edit1.SelStart+Edit1.SelLength;
                 key := 0;
                 end
                 else
                   if Edit1.SelStart < Length(Edit1.Text) then
                     if not (Edit1.Text[Edit1.SelStart+1] in ['0'..'9',',','-','*','/','+','(',')',' ']) then
                       if IsElement(Edit1,1) then
                         key := 0;
   VK_Up,VK_Down : key := 0;
  end;
end;

procedure TForm1.Edit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Edit1.SelStart <> Length(Edit1.Text) then
    IsElement(Edit1,0);
end;

_________________
MfG Lannes
(Nichts ist nicht Nichts) and ('' <> nil ) and (Pointer('') = nil ) and (@('') <> nil )
bnessler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 36

alle Win's , suse u. Ubuntu Linux
Delphi1,2,4,5,7,2005, Java (Eclipse), C++,C#, (VS2005)
BeitragVerfasst: Mi 05.04.06 08:26 
Hallo,

ein anderer Ansatz wäre die Formeln dynamisch in mehrere Editfelder aufzuteilen,
in Parameterfelder und Operatorenfelder, dann automatisch die entsprechenden Properties für die Feldart zu vergeben.

Allerdings muss es dann zum Ergänzen/Ändern einer Formel Möglichkeiten geben, wie
z.B. Parameterfeld hinzufügen oder Operatorenfeld hinzufügen. Dort wäre dann aber wiederum eine einfache Möglichkeit gegeben die möglichen Eingaben zu kontrollieren bzw. vorzugeben.

Gruß

Bernhard
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Mi 05.04.06 14:48 
Ok es ist nicht trivial, aber auch nicht unmöglich.

Formatierungen habe ich nicht verwendet, sind aber auch kein Problem.

Ich bin mir ziemlich sicher, das ich nicht alle Fehler getilgt habe, aber dennoch viel Spass damit.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
unit UnitMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TFormMain = class(TForm)
    CodeMemo: TRichEdit;
    ListBoxObjects: TListBox;
    Label1: TLabel;
    Label2: TLabel;
    GroupBox1: TGroupBox;
    EditObjName: TEdit;
    Label3: TLabel;
    EditObjDesc: TEdit;
    Label4: TLabel;
    ButtonAddObj: TButton;
    ButtonDelObj: TButton;
    ListBoxAutoComplete: TListBox;
    function GetWordOnCursor(RichEdit: TRichEdit;AutoSelect:boolean): string;
    procedure CodeMemoKeyPress(Sender: TObject; var Key: Char);
    procedure CodeMemoMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure CodeMemoKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure CodeMemoKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure CodeMemoProtectChange(Sender: TObject; StartPos,
      EndPos: Integer; var AllowChange: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure CodeMemoChange(Sender: TObject);
    procedure ButtonAddObjClick(Sender: TObject);
    procedure ButtonDelObjClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    ObjectWord:string;
    isObjectWord : boolean;
    DoChange : boolean;
    EditOK : boolean;
    procedure FillQuickList(FillQuickList:string);
  end;

var
  FormMain: TFormMain;

implementation

{$R *.dfm}

function TFormMain.GetWordOnCursor(RichEdit: TRichEdit;AutoSelect:boolean): string;
var
  i, j: Integer;
  s: string;
begin
  result := '';
  with RichEdit do 
  begin
    // Speichern des ParseStrings
    s := Text; 
    // Suche den Beginn des Wortes
    i := SelStart;
    while (i > 0) and (s[i] <> '"') and (s[i] <> ' ') and
          (s[i] <> #10) and (s[i] <> #13)
    do Dec(i);
    // Suche das Ende des Wortes
    j := SelStart + 1;
    while (j <= Length(s)) and (s[j] <> '"') and (s[j] <> ' ') and
          (s[j] <> #10) and (s[j] <> #13)
    do Inc(j);
    result := Copy(s, i+1, j - i-1);
    //Testen ob Objekt
    isObjectWord := false;
    if (s[i] = '"') and (s[j] = '"') then begin
      ObjectWord := result;
      isObjectWord := true;
      if AutoSelect then begin
        SelStart := i;
        SelLength := Length(result);
      end;
    end else begin
      result := '';
    end;
  end;
end;   

procedure TFormMain.FillQuickList(FillQuickList:string);
var
  i:integer;
  ObjektName:string;
begin
  ListBoxAutoComplete.Items.Clear;
  if isObjectWord then begin
    for i:=0 to ListBoxObjects.Items.Count-1 do begin
      ObjektName := ListBoxObjects.Items.Values[ListBoxObjects.Items.Names[i]];
      if UpperCase(copy(ObjektName,1,length(ObjectWord))) = UpperCase(ObjectWord) then
        ListBoxAutoComplete.Items.Add(ObjektName);
    end;
    if ListBoxAutoComplete.Items.Count > 0 then
      ListBoxAutoComplete.ItemIndex := 0;
  end;
end;  

procedure TFormMain.CodeMemoMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  DoChange := true;
  GetWordOnCursor(CodeMemo,true);
  FillQuickList(ObjectWord);
  DoChange := false;
end;


procedure TFormMain.CodeMemoKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);      
var
  EditString :string;
begin      
  DoChange := true;
  //Auswahlliste up/down
  if (key in [38,40]) and (ObjectWord <> '') then begin
    if ListBoxAutoComplete.Items.Count > 1 then begin
      if (key = 38) and (ListBoxAutoComplete.ItemIndex > 0) then
        ListBoxAutoComplete.ItemIndex := ListBoxAutoComplete.ItemIndex-1;
      if (key = 40) and (ListBoxAutoComplete.ItemIndex < ListBoxAutoComplete.Items.Count -1) then
        ListBoxAutoComplete.ItemIndex := ListBoxAutoComplete.ItemIndex+1;
    end;
    key := 0;
  end;
  //Eingaben sind OK
  if key in [65..90,46,8,13] then
    EditOK := true;
  //auf Löschen von Objekten testen
  if key = 8 then begin   //Backspace
    EditString := CodeMemo.Text;
    if EditString[CodeMemo.SelStart] = '"' then begin
      CodeMemo.SelStart := CodeMemo.SelStart-1;
      GetWordOnCursor(CodeMemo,true);
      CodeMemo.SelStart  := CodeMemo.SelStart-1;
      CodeMemo.SelLength := length(ObjectWord)+2;
    end;
  end;
  if key = 46 then begin
    //hab keine Bock mehr! (geht analog zu Backspace) 
  end;
  DoChange := false;
end;

procedure TFormMain.CodeMemoKeyPress(Sender: TObject; var Key: Char);
var
  EditString :string;
  MemSelStart :integer;
begin    
  DoChange := true;
  if Key = '"' then begin  //Autoverfollständigen von "
    MemSelStart := CodeMemo.SelStart;
    EditString := CodeMemo.Text;
    insert('"',EditString,CodeMemo.SelStart+1);
    CodeMemo.Text := EditString;
    CodeMemo.SelStart := MemSelStart;  
    CodeMemo.SelLength := 0;
  end;
  if Key = #13 then key := #0;   
  DoChange := false;
end;

procedure TFormMain.CodeMemoKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  EditString :string;
  MemSelStart :integer;
begin
  DoChange := true;
  //ShowMessage(IntToStr(Key));
  if key in [37] then begin
    CodeMemo.SelStart := CodeMemo.SelStart -1;
    GetWordOnCursor(CodeMemo,true);
  end;
  if key in [39] then begin
    CodeMemo.SelStart := CodeMemo.SelStart + CodeMemo.SelLength+1; 
    GetWordOnCursor(CodeMemo,true);
  end;
  if key in [38,40] then
    GetWordOnCursor(CodeMemo,true);
  //Eingaben  
  if key in [65..90,46,8] then begin
    MemSelStart := CodeMemo.SelStart;
    GetWordOnCursor(CodeMemo,false);
    if isObjectWord then begin
      FillQuickList(ObjectWord);
      CodeMemo.SelStart := MemSelStart;
    end;
  end;
  //Enter
  if (key in [13]) and (ObjectWord <> '') and (ListBoxAutoComplete.ItemIndex <> -1) then begin
    MemSelStart := CodeMemo.SelStart;
    GetWordOnCursor(CodeMemo,true);
    EditString := CodeMemo.Text;
    delete(EditString,CodeMemo.SelStart+1,length(ObjectWord));
    insert(ListBoxAutoComplete.Items[ListBoxAutoComplete.ItemIndex],EditString,CodeMemo.SelStart+1);
    CodeMemo.Text := EditString;
    CodeMemo.SelStart := MemSelStart;
    GetWordOnCursor(CodeMemo,true);
    key := 0;
  end;
  DoChange := false;
end;


procedure TFormMain.CodeMemoProtectChange(Sender: TObject; StartPos,
  EndPos: Integer; var AllowChange: Boolean);
begin
  AllowChange := EditOK;
  if not isObjectWord then
    AllowChange := true;
  EditOK := false;
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
  CodeMemo.DefAttributes.Protected := true;     
  ObjectWord   := '';
  isObjectWord := false;
  DoChange     := false;
  EditOK       := false;
end;

procedure TFormMain.CodeMemoChange(Sender: TObject);
begin
  if (not isObjectWord) and (GetWordOnCursor(CodeMemo,false) <> '') then
    CodeMemo.Undo;
end;

procedure TFormMain.ButtonAddObjClick(Sender: TObject);
begin
  ListBoxObjects.Items.Add(EditObjName.Text+'='+EditObjDesc.Text);
end;

procedure TFormMain.ButtonDelObjClick(Sender: TObject);
begin
  if ListBoxObjects.ItemIndex <> -1 then
    ListBoxObjects.Items.Delete(ListBoxObjects.ItemIndex);
end;

end.
Einloggen, um Attachments anzusehen!

Für diesen Beitrag haben gedankt: FURIOS
Chaosworld Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Mi 05.04.06 14:54 
Danke für eure antworten

@Lannes&Simon Joker
die Lösung werde ich gleich ausprobieren / durchdenken, ob dass was bringt

@bnessler
Deine lösung hört sich interessant an, nur wie meinst du dass mit dynamisch? Kann ich mir irgendwie noch nichts drunter vorstellen

Auf jeden Fall danke für eure ganzen Antworten

Habe jetzt erst einmal einiges zum testen, melde mich noch mal, sobald ich dass alles durch bin

Chaosworld
bnessler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 36

alle Win's , suse u. Ubuntu Linux
Delphi1,2,4,5,7,2005, Java (Eclipse), C++,C#, (VS2005)
BeitragVerfasst: Mi 05.04.06 15:05 
Hallo,

dynamisch bedeutet in diesem Fall die Editfelder werden zur Laufzeit erzeugt und gegebenenfalls auch wieder gelöscht.
Da Deine Formeln nicht alle gleich lang sind und die Idee darauf beruht pro Parameter/Operator etc. ein Feld zu haben, musst Du entweder die Länge der Formeln begrenzen, oder eben abhängig von der Länge der Formel die Felder dynamisch erstellen.


Gruß
Bernhard
Chaosworld Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Mi 05.04.06 15:07 
@Simon Joker
Habe mir gerade deine Lösung angesehen, die idee mit dem Protected-Text finde ich klasse, kannte ich noch garnicht. Ich glaube dass ist echt eine super Lösung.

Danke an euch alle für eure Hilfen

Chaosworld