Stworzyłem sobie procedure do wczytywania pliku z lista. Zrobiłem sobie okienko, aby użytkownik wpisał hasło do listy. Jednak z tego co czytałem nie ma w delphi zmiennej password aby hasło wpisywane nie było widoczne. Nie wiem za bardzo jakby to zmodyfikować.
Z tego co widzę w dokumentacji, InputBox
nie daje możliwości zasłonięcia zawartości pola edycyjnego, ale skoro robisz program na studia, to raczej nie powinieneś się tym przejmować. Można by stworzyć własne okienko dialogowe, położyć na nim TEdit
i ustawić mu PasswordChar
np. na *
i wtedy tekst będzie zasłonięty, ale na razie to za dużo jak na Twoje zdolności. Raczej skup się na tym, aby ten program w ogóle działał, niż na wodotryskach.
Jeśli chodzi o kod logowania, to trudno zrozumieć co masz na myśli. Jeśli logowanie ma się odbywać po wciśnięciu danego przycisku i ma być jednorazowe, to powinieneś mieć jakąś zmienną, która przechowa stan logowania (zmienną logiczną). W skrócie, wyglądałoby to w ten sposób:
var
// zmienna globalna przechowująca stan logowania
LoggedIn: Boolean;
procedure TForm1.Button1Click(Sender: TObject);
begin
// jesli użytkownik wpisał hasło i zaakceptował okienko, do zmiennej
// zostanie wpisane "True", jeśli podał hasło "test", a jesli
// podał inne hasło, to do zmiennej trafi wartość "False"
LoggedIn := InputBox('Dostęp do listy', 'Wpisz haslo:', '') = 'test';
// sprawdzamy czy podano nieprawidłowe hasło
if not LoggedIn then
MessageDlgPos('Błędne hasło!', mtError, mbOKCancel, 0, 200, 200);
end;
Ten kod jest skrócony, bo bardziej przyjazna wersja wyglądałaby tak (nie licząc deklaracji zmiennej):
procedure TForm1.Button1Click(Sender: TObject);
var
Password: String;
begin
// pobieramy tekst wpisany przez użytkownika (lub domyślny, jeśli anulował okienko)
Password := InputBox('Dostęp do listy', 'Wpisz haslo:', '');
// sprawdzamy czy hasło jest poprawne
if Password = 'test' then
// jest poprawne, więc wpisujemy "True" do zmiennej
LoggedIn := True
else
begin
// hasło jest błędne, wpisujemy "False", bo nie zalogowano
LoggedIn := False;
// wyświetlamy okienko z informacjami o błędzie logowania
MessageDlgPos('Błędne hasło!', mtError, mbOKCancel, 0, 200, 200);
end;
end;
W każdym razie to jest prostu przykład tego jak przeprowadzić logowanie i ustawić wartość logiczną, określającą stan logowania. Mała uwaga — do wyświetlenia błędu wystarczy funkcja MessageBox
— użycie MessageDlgPos
nie jest konieczne.
Co do usuwania elementu to mam coś takiego jednak jest to procedura wykorzystująca numer id. A skąd użytkownik ma wiedzieć który wiersz wyświetlany w okienku ma numer.
Niech sobie policzy. ;)
Wszystko zależy od tego, w jaki sposób przedstawiasz dane w okienku. Jeśli używasz do tego ListBox
, to użytkownik musiałby samodzielnie obliczyć numer wiersza, co jest raczej słabe. Są kontrolki, które pokazują numerowanie (np. TStringGrid
), więc można by z nich skorzystać, ale na razie wystarczy Ci to co masz, czyli zwykły ListBox
.
Moze da się to zrobić aby użytkownik wpisywał dany element wiersza i on na tej podstawie został usunięty.
Można i tak, a nawet w tym przypadku trzeba. I nie będzie to trudne, bo klasa TSinglyLinkedList
ma już zdefiniowaną metodę Find
, która służy właśnie do wyszukania elementu w liście i zwrócenia jego indeksu — a ten indeks można użyć do wywołania metody Delete
. Pamiętać należy, że elementy listy oraz linie w ListBox
są indeksowane od 0
, a także o tym, że element z danymi wskazanymi przez użytkownika może w liście nie istnieć i w takim przypadku metoda Find
zwróci wartość -1
, co trzeba sprawdzić.
Jeśli Twoja lista również przechowuje liczby (tak jak w moim artykule) i zakładając, że lista jedokierunkowa ma nazwę List
:
var
// zmienna z Twoją listą jednokierunkową
List: TSinglyLinkedList;
{..}
procedure TForm1.UsuńClick(Sender: TObject);
var
DataValue, DataIndex: Integer;
begin
// pobieramy wartość do usunięcia z listy
// wartość "-1" to wartość domyślna, która oznacza anulowanie chęci usuwania
DataValue := InputBox('Usuń element','Podaj liczbę do usunięcia z listy:', -1);
// sprawdzamy czy użytkownik wpisał dane i zaakceptował okienko
if DataValue <> -1 then
begin
// użytkownik podał dane, więc szukamy ich w liście
DataIndex := List.Find(DataValue);
// jeśli dane istnieją w liście
if DataIndex <> -1 then
begin
// znaleziono wartość w liście, więc ją usuwamy z listy oraz z kontrolki
List.Delete(DataIndex);
ListBox1.Items.Delete(DataIndex);
end
else
// dane nie istnieją w liście, wyświetlamy informację
MessageDlgPos('Nie znaleziono danej liczby w liście.', mtInformation, mbOKCancel, 0, 200, 200);
end;
end;
Przy czym pamiętaj o nie używaniu polskich słów do nazywania danych i komponentów — to zła praktyka.
Ostatnia sprawa to z tym okienkiem które ma się wyświetlać jak użytkownik coś zmodyfikował w liście, ma się pytać czy zapisać zmiany.
Żeby wiedzieć czy lista została zmodyfikowana czy nie, pasuje mieć jakąś zmienną, która będzie taką informację przechowywała — wcześniej sugerowałem zadeklarowanie zmiennej Modified
. Czyli za każdym razem gdy coś się w liście zmienia, trzeba przypisać do tej zmiennej wartość True
. Wyżej podałem kod usuwania danych, do którego należy dodać ustawianie tej zmiennej, ale tylko wtedy, gdy usuwanie faktycznie będzie miało miejsce (czyli gdy użytkownik poda dane istniejące w liście).
var
Modified: Boolean;
{..}
procedure TForm1.UsuńClick(Sender: TObject);
var
DataValue, DataIndex: Integer;
begin
DataValue := InputBox('Usuń element','Podaj liczbę do usunięcia z listy:', -1);
if DataValue <> -1 then
begin
DataIndex := List.Find(DataValue);
if DataIndex <> -1 then
begin
List.Delete(DataIndex);
ListBox1.Items.Delete(DataIndex);
// lista została zmodyfikowana, więc ustawiamy zmienną na "True"
Modified := True;
end
else
MessageDlgPos('Nie znaleziono danej liczby w liście.', mtInformation, mbOKCancel, 0, 200, 200);
end;
end;
Teraz tę zmienną będzie można użyć podczas zamykania programu i opcjonalnego wyświetlania pytania o zapis listy. Twój kod OnCloseQuery
niestety jest zupełnie błędny, bo nadal nie zaznajomiłeś się z kursem programowania — np. używasz operatora przypisania zamiast porównania oraz instrukcji switch
, której nie ma w Delphi.
Zdarzenie OnCloseQuery
posiada parametr CanClose
, który domyślnie zawiera wartość True
i aby przerwać zamykanie okna, należy przypisać do tej zmiennej wartość False
. To ma się dziać wtedy, gdy użytkownik w okienku z pytaniem wciśnie przycisk Anuluj
lub zamknie okienko krzyżykiem (lub Alt+F4). Jeśli wciśnie przycisk Tak
, lista ma być zapisana, a jeśli Nie
, to nie. W obu przypadkach okno musi zostać zamknięte, więc CanClose
nie powinien być modyfikowany.
W krócie można to napisać tak (pisane z głowy, nietestowane):
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
// jeśli lista nie została zmodyfikowana, wychodzimy z tego zdarzenia
// okno zotanie zamknięte, a lista nie będzie zapisana do pliku
if not Modified then Exit;
// tutaj wiemy, że lista została zmodyfikowana, czyli zmienna "Modified" zawiera "True"
// musimy zapytać użytkownika czy chce ją zapisać czy nie
// wyświetlamy okienko z pytaniem i rozróżniamy w instrukcji wyboru to który przycisk został wciśnięty
case MessageBox('Zapisać listę do pliku?', 'Wyjście z programu', MB_YESNOCANCEL) of
// użytkownik wyraził zgodę na zapis, więc zapisujemy listę do pliku
IDYES: List.SaveToFile('lista.txt');
// użytkownik anulował wybór, więc anulujemy zamykanie okna
IDCANCEL: CanClose := False;
end;
end;
To jest skrócona wersja — dłuższa i bardziej przyjazna początkującemu wygląda tak:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
DialogResult: Integer;
begin
// jeśli lista nie została zmodyfikowana, wychodzimy z tej metody
// okno zotanie zamknięte, a lista nie będzie zapisana do pliku
if not Modified then Exit;
// tutaj wiemy, że lista została zmodyfikowana, czyli zmienna "Modified" zawiera "True"
// musimy zapytać użytkownika czy chce ją zapisać czy nie
// wyświetlamy okienko z pytaniem i pobieramy ID wciśniętego przycisku
DialogResult := MessageBox('Zapisać listę do pliku?', 'Wyjście z programu', MB_YESNOCANCEL);
// jeśli użytkownik wcisnął przycisk "Tak"
if DialogResult = IDYES
begin
List.SaveToFile('lista.txt'); // zapisujemy listę do pliku
CanClose := True; // wpisyjemy "True", czyli wyrażamy zgodę na zamknięcie okna
end;
// jeśli użytkownik wcisnął przycisk "Nie"
if DialogResult = IDNO then
CanClose := True; // wpisyjemy "True", czyli wyrażamy zgodę na zamknięcie okna
if DialogResult = IDCANCEL then
CanClose := False; // wpisujemy "False", czyli przerywamy zamykanie okna
end;
Powyższe pisane z głowy, mogą być błędy.