Wątek przeniesiony 2014-01-16 22:13 z Delphi i Pascal przez olesio.

Sprawdzanie poprawności danych TEdit

0

Witam,
Chciałem zrobić sprawdzanie czy dana wartość wpisana do TEdit istnieje już na liście, jeśli tak to wyskakuje komunikat i musimy wpisać coś innego.
Napisałem pewna procedurę i wrzuciłem ją do zdarzenia OnExit. Program się kompiluje, ale procedura nie działa

  procedure TProject.sprawdzanie(Sender: TObject);
 begin
   e:=root;
while e<>nil do
begin
  if IntToStr(e.nr) = item.SubItems.Text then
  begin
   raise Exception.Create('Nie można podać dwa razy tego samego numeru');
   E_cena.Clear;
   Exit;
  end;
   e  := e^.nastepny;
end;
 end;
 

ListView jest ustawione na vsReport, a nr jest 2 kolumną. a item to item: TlistItem;

0

Można najprościej pod WinAPi tak jak poniżej. Zresztą kod został kiedyś użyty w jednym z moich programów w WinAPI. Są też inne sposoby. Ale skoro problem dla Ciebie jest po prostu banalnie zrobić pętlę po TListItemach i sprawdzać czy SubItems.Count > 0 i jeśli tak to sprawdzać tekst SubItems[1], to cóż mogę tylko rozłożyć ręce. Kombinujesz jakieś cuda ze wkaźnikami zamiast zrobić to zwykłą pętlą z Breakiem. Ale rób jak uważasz, ja w życiu nie wpadłbym na takie komplikowanie sobie sprawy tak błahej jak znalezienie Itema po Captionie Subitema w ListView ze stylem Report.

I do stu tysięcy nieszukających lenichów. Dlaczego znowu temat o podstawach nie jest w Newbie?! Ech, przenoszę. Ale za taki upór by nie pisać we właściwym dziale, póki on istnieje - chyba trzeba będzie równie złośliwie nagradzać wątki Koszem, bo do Was nie dociera :/

//..
uses
  CommCtrl;

function LVGetCount(LVHandle : HWND) : integer;
begin
  Result := ListView_GetItemCount(LVHandle);
end;


function LVIndexOf(LVHandle : HWND; WhichColumn : integer; FindText : string; IgnoreCase : boolean) : integer;
const
  L = 9999;
var
  PC : PChar;
  I : integer;
  Buf : string;
begin
  Result := -1;
  SetLength(Buf, L);
  PC := PChar(Buf);
  for I := 0 to LVGetCount(LVHandle) - 1 do
  begin
    ListView_GetItemText(LVHandle, I, WhichColumn, PC, L);
    if IgnoreCase then
    begin
      PC := PChar(AnsiLowerCase(PC));
      FindText := AnsiLowerCase(FindText);
    end;
    if PC = FindText then
    begin
      Result := I;
      Break;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption := IntToStr(LVIndexOf(ListView1.Handle, 1, 'googluje, kombinuje sam w ostateczności smaruje tutaj', True));
end;
0

@szamot - a to rajzowanie wyjątku potrzebne jest?

Na pierwszy rzut ucha problem jest w tej linijce:

if IntToStr(e.nr) = item.SubItems.Text then

SubItems to klasa TStrings, więc aby normalnie porównać jakąś daną z konkretną wartością w SubItems, wypadało by porównania dokonać na konkretnej "komórce", a nie na sumie ich wszystkich w danym wierszu, którą otrzymuje się przez właściwość Text;

Czyli jak już coś to tak:

if IntToStr(e^.nr) = Item.SubItems[0] then //SubItems[0] to druga komórka w wierszu

Poza tym konwersji e^.nr dokonaj RAZ, a nie w każdym obiegu pętli; Wynik konwersji wpakuj do zmiennej i ją porównuj z subitemem komponentu;

I nie wiem czy zauważyłeś, ale w powyższym warunku masz błąd, bo nie używasz w e.nr operatora odwołania do wartości - powinno być e^.nr wszędzie tam, gdzie próbujesz uzyskać dostęp do pola struktury spod wskaźnika;

I nadal nie wiem co ma ten wątek wspólnego z komponentem TEdit, o którym wspomniałeś w tytule wątku.


A jakbyś potrzebował szybsze rozwiązanie, to oprócz przechowywania liczb jako łańcuchy w SubItems możesz dodatkowo skorzystać z TListItem.Data do przechowania pojedynczej liczby (nie zajmującej więcej bajtów niż pointer) lub przypisać wskaźnik na jakąś strukturę, w której będą liczby; Dzięki temu samo wyszukiwanie będzie znacznie szybsze, a na wyświetlanie danych w komponencie to nie wpłynie.

0
furious programming napisał(a):

... Czyli jak już coś to tak:

if IntToStr(e^.nr) = Item.SubItems[0] then //SubItems[0] to druga komórka w wierszu

Poza tym konwersji e^.nr dokonaj RAZ, a nie w każdym obiegu pętli

Ja bym jednak radził za każdym obiegiem pętli ale tak:

if e^.nr=StrToInt(Item.SubItems[0]) then

bo inaczej program stwierdzi że 2 <> '02'

0

Zrobiłem, tak jak radzicie i teraz wszystko co wpisze generuje raise.

  procedure TProject.sprawdzanie(Sender: TObject);
 begin
   e:=root;
while e<>nil do
begin

  if e^.nr=StrToInt(Item.SubItems[0]) then
  begin
   raise Exception.Create('Nie można podać dwa razy tego samego numeru');
   E_cena.Clear;
   Exit;
  end;
   e  := e^.nastepny;
end;
 end;
 
0
szamot napisał(a):

Zrobiłem, tak jak radzicie i teraz wszystko co wpisze generuje raise.
Wniosek jeden - zrobiłeś nie tak jak radziliśmy.

0

@szamot - to co się znajduje w Item.SubItems[0] w każdym obiegu pętli, że ciągle znajduje taką liczbę w komponencie?

Sugeruję także odwrócić kolejność instrukcji z Raise z tą E_cena.Clear, bo po wykonaniu tej pierwszej, ta druga zostanie pominięta;

Pokaż zawartość tej kolumny, która ma być brana pod uwagę podczas wyszukiwania (podaj albo ich listę, albo ew. jakiś zrzut ekranu); Najlepiej by było gdybyś umieścił w załączniku cały projekt - wtedy można by pod debugerem spokojnie sprawdzić kod.

0

Proszę bardzo to cały projekt.

1 użytkowników online, w tym zalogowanych: 0, gości: 1