Wątek przeniesiony 2014-11-04 13:51 z Newbie przez furious programming.

Linia z funkcją edycji w trakcie działania programu.

0

W Delphi za pomocą Canvas można rysować linie, jednak taka linia nie ma możliwości edycji. Chciałbym móc stworzyć linię, którą mogę kliknięciem zaznaczyć w trakcie działania programu, usunąć, przesunąć wierzchołek, nadać jej indywidualną nazwę. Prosiłbym o pomoc w stworzeniu takiego komponentu, bo chyba tak to trzeba rozwiązać. Nie wiem od której strony się do tego zabrać, choćby jaki obiekt ma stanowić klasę bazową. Chyba, że do takiej linii nie potrzeba osobnego komponentu.

1

Zapamiętaj dwa punkty i rysuj linie wraz z punktami w OnPaint
W zdarzeniu OnMouseDown zapamiętaj na który punkt nacisnąłeś
W zdarzeniu OnMouseMove zmieniaj kursor myszy kiedy jesteś nad jednym z punktów (plus/minus 3 piksele) zaś jeżeli przycisk myszy wciśnięty to przesuwaj punkt zapamiętany w OnMouseDown

0

Możesz dokładniej mi objaśnić? W chwili kliknięcia mam sprawdzić, czy współrzędne kliknięcia pokrywają się (z tolerancją kilku pikseli) z którąś z zapisanych współrzędnych, tak?

1

Musisz gdzieś mieć zapisane informacje o tych narysowanych elementach (liniach), aby móc je później edytować; Poprzednik napisał Ci, że musisz trzymać w pamięci przynajmniej dwa punkty tej linii - dzięki temu będzie wiadomo (już po rysowaniu) gdzie są te wierzchołki;

Wystarczy Ci do tego prosty rekord:

type
  TLine = record
    A, B: TPoint;
  end;

W momencie utworzenia linii tworzysz sobie taki rekord i trzymasz w pamięci, uzupełniasz go w informacje na temat wierzchołków i malujesz; Podczas edycji linii modyfikujesz dane z takiego rekordu, usuwasz z kanwy poprzednio namalowaną linię i malujesz jeszcze raz - tym razem już o nowych współrzędnych;

Prosiłbym o pomoc w stworzeniu takiego komponentu, bo chyba tak to trzeba rozwiązać.

Niekoniecznie - komponent można zrobić, jeżeli takie kanwy z możliwością edytowania elementów będą Ci potrzebne co najmniej w kilku miejscach w programie; Jeżeli potrzebujesz tylko jedno takie pole, to nie potrzebujesz komponentu, bo możesz to wszystko zaprogramować w klasie formularza; Ale wybierz sobie odpowiednie rozwiązanie według Twoich oczekiwań.

1

A dobra, trochę pobawiłem się i stworzyłem przykładową aplikację do zabawy pojedynczą linią; Zaimplementowane jest tworzenie i przesuwanie linii na komponencie klasy TPaintBox, plus kilka bajerów (zmiana Caption i Cursor) - poniżej zrzut:

lineedit.png

Podglądnij sobie kod i spróbuj go zrozumieć, ewentualnie pytaj; Nie posiada zabezpieczeń przed przesunięciem punktu linii poza formularz, więc to ewentualnie sobie dodaj; W załącznikach dodatkowo umieszczam spakowany plik wykonywalny; Program stworzony i testowany w Delphi7;
____PS: Instrukcja obsługi znajduje się w Caption formularza.

0

Zasadniczo problem rozwiązany.

furious programming napisał(a):

Jeżeli potrzebujesz tylko jedno takie pole, to nie potrzebujesz komponentu

Właśnie tu jest problem, takich linii może być nawet do kilku tysięcy. Stworzyłem tabelę w której zapisuję wszystkie wierzchołki, działa prawidłowo; obawiam się jednak, że przy większej ilości wierzchołków program nie nadąży znaleźć po współrzędnej danej linii w tabeli.

0

Dla kilkudziesięciu tysięcy - użytkownik nawet nie zauważy.
Przy większej ilości i tak już się nie połapie gdzie co jest.

1
nieznany napisał(a)

Właśnie tu jest problem, takich linii może być nawet do kilku tysięcy.

Ale tu nie ma żadnego problemu, bo ja nie pisałem o jednej linii, tylko o jednym polu do bawienia się liniami;

nieznany napisał(a)

Stworzyłem tabelę w której zapisuję wszystkie wierzchołki, działa prawidłowo; [...]

Nie tabelę, tylko tablicę, bo to zupełnie różne pojęcia; Ale jaka to tablica - statyczna czy dynamiczna? Jak ją deklarowałeś i jak jej używasz? Jakimi typami się posługujesz? Pokaż kod, to się coś doradzi;

[...] obawiam się jednak, że przy większej ilości wierzchołków program nie nadąży znaleźć po współrzędnej danej linii w tabeli.

O to się nie martw - zdąży bez problemu; Chyba że masz baaardzo starą maszynę, ale tego nie podejrzewam;

A nawet jeśli takich linii ma być tysiące, a wierzchołków 2x więcej, to kwadraciki, którymi oznaczamy wierzchołki całkowicie przykryją kanwę komponentu; Nie przesadziłeś trochę z tą ilością, czy faktycznie potrzebujesz AutoCADa w komponencie?

0

Ale jaka to tablica - statyczna czy dynamiczna? Jak ją deklarowałeś i jak jej używasz?

Na czas testu i nauki tablica statyczna, zapełniłem ją przykładowymi wartościami wierzchołków dla 4 linii. Do programu właściwego zamierzam użyć tablicy dynamicznej, wartości wczytywane z pliku.

kwadraciki, którymi oznaczamy wierzchołki całkowicie przykryją kanwę komponentu

One nie będą rysowane bezpośrednio na formie, a na komponencie Image zawartym w komponencie ScrollBox. Dla zobrazowania załącznik 1.

Nie przesadziłeś trochę z tą ilością

Powiedzmy, że będzie to służyło mniej więcej do modyfikowania pewnych schematów. Poniżej kod sprawdzający, czy kursor znajduje się nad początkowym wierzchołkiem linii; przy kilku liniach działa prawidłowo, nie wiem jeszcze jak będzie przy większej liczbie.

For I := 0 to 4 do
begin
  If ((X >= Wartosci[1][I]-3) and (X <= Wartosci[1][I]+3) and (Y >= Wartosci[2][I]-3) and (Y <= Wartosci[2][I]+3)) then
  begin
    Form1.Image.Cursor := crCross;
    Break
  end
  else
  begin
    Form1.Image.Cursor := crDefault;
  end;
end;
1
  1. Użyj TPaintBox do rysowania
  2. Break zamień na Exit
  3. Form1.Image.Cursor := crDefault; wynieś poza pętle lepiej na dół.
  4. Tablice Wartosci zamień na Wartosci:array of TPoint;
  5. Użyj funkcji PtInRect(Point(X,Y),Bounds(Wartosci[I].X,Wartosci[I].Y,5,5))
    Czyli razem:
for I:=0 to Length(Wartosci)-1 do
begin
  if PtInRect(Point(X,Y),Bounds(Wartosci[I].X-2,Wartosci[I].Y-2,5,5)) then
  begin
    PaintBox.Cursor:=crHand;
    Exit;
  end;
end;
PaintBox.Cursor:=crCross;
0

Na czas testu i nauki tablica statyczna, zapełniłem ją przykładowymi wartościami wierzchołków dla 4 linii. Do programu właściwego zamierzam użyć tablicy dynamicznej, wartości wczytywane z pliku.

Testuj od razu na macierzy dynamicznej; Później zostanie Ci tylko załadować dane linii z pliku, bez przerabiania połowy programu;

Poniżej kod sprawdzający, czy kursor znajduje się nad początkowym wierzchołkiem linii; przy kilku liniach działa prawidłowo, nie wiem jeszcze jak będzie przy większej liczbie.

For I := 0 to 4 do
{...}

Najpierw piszesz, że testujesz program na czterech liniach, a pętla sprawdza pięć; Albo zły jest opis, albo kod powoduje wykroczenie poza rozmiar macierzy;

One nie będą rysowane bezpośrednio na formie, a na komponencie Image zawartym w komponencie ScrollBox. Dla zobrazowania załącznik 1.

Cały czas mam wrażenie, że cytujesz moje słowa, ale nie odpowiadasz na nie lub w ogóle ich nie rozumiesz; Poza tym powyższe słowa są odpowiedzią na wyrwany z kontekstu fragment mojego posta;

Napisałem, że jeżeli załadujesz do takiego komponentu kilka tysiecy linii (x2 punktów`), to kwadraciki które uwidaczniać mają wierzchołki linii pokryją znaczną część komponentu; Teraz dopiero piszesz, że kanwa komponentu może być dużo większa niż rozmiar formularza, więc jeśli te kwadraciki nie były zbyt gęsto upakowane, dokument musi być bardzo duży;
____Póki co sugeruj się wypowiedzią poprzednika i zastanawiaj się przy pisaniu kodu, bo trochę długi kod Ci wychodzi; No i dalej nie wiadomo, czy potrzebujesz oznaczać kwadracikami wierzchołki linii czy nie, bo na załączonym zrzucie ich nie widzę.

0

Tak, pomyliłem się z tablicą. Co do kwadracików, nie potrzebuję ich, zresztą nic o takich nie wspominałem. Co do długości kodu, nie mam jeszcze wprawy, ale z upływem czasu myślę będzie coraz lepiej; wykorzystam teraz funkcje pokazane przez @_13th_Dragon. Nie pisałem, że kanwa komponentu będzie znacznie większa, chodziło tu tylko o modyfikowanie linii, których ilość może być znaczna. Przepraszam, może źle się wyrażałem. Tak czy siak, problem rozwiązany, dzięki Wam za pomoc.
Jeszcze jeden problem z tego zakresu. Mamy narysowaną linię, znamy wierzchołki. Po kliknięciu w obszarze wierzchołka ma pojawić się kolejna. To potrafię, tylko co zrobić, by ta stworzona była przedłużeniem poprzedniej?

0

Mamy narysowaną linię, znamy wierzchołki. Po kliknięciu w obszarze wierzchołka ma pojawić się kolejna. To potrafię, tylko co zrobić, by ta stworzona była przedłużeniem poprzedniej?

No dobrze, ale jak to dokładnie ma działać? Chcesz móc tworzyć linie np. łamane, zaznaczając od którego wierzchołka chcesz ją poprowadzić?

W takim przypadku dochodzić będą powiązania wierzchołków/linii, aby można było przesuwać kilka linii, trzymając za współny wierzchołek; Chyba że nie takie coś masz na myśli? Rozwiń swoją wypowiedź.

0

Nie, nie trzeba czegoś takiego. Mamy daną linię prostą, znamy jej wierzchołki. Klikamy na jednym z wierzchołków i tworzy się kolejna, osobna linia prosta. Nie chcę by były ze sobą jakoś ,,sprzęgnięte" czy zespolone; jedyne wspólne cechy to identyczne współrzędne jednego wierzchołka i kierunek tych linii.

0

Wystarczy, że podczas tworzenia nowej linii sprawdzisz, czy pierwszy wierzchołek znajduje się nad innym wierzchołkiem (z tolerancją tych kilku pikseli) i jeśli tak - pobierzesz współrzędne tego punktu i wpiszesz do rekordu z nową linią; Czyli musisz sobie oprogramować zdarzenie OnMouseUp, jeśli z niego korzystasz do tworzenia nowych wierzchołków.

0
nieznany napisał(a):

jedyne wspólne cechy to identyczne współrzędne jednego wierzchołka i kierunek tych linii.

Jeżeli mas ten sam jeden wierzchołek oraz ten sam kierunek linii to znaczy że masz tylko jedna linię, na której masz kilka punktów.

0

Nie zrozumieliśmy się. Dodać nową linię z pokrywającym się wierzchołkiem z inną linią potrafię, chodzi o to, by zwrot tej linii był taki sam. Powiedzmy mamy narysowaną linię po skosie o długości 50px, klikam na jeden z końców tej linii i rysuje się druga, osobna linia na 50px, takie przedłużenie, które zaczyna się od tamtego wierzchołka i również jest pod takim samym skosem. Dodałem obrazek, powinien wszystko wyjaśnić.

0

No to przeczytaj jeszcze raz mój poprzedni post, bo w nim napisałem Ci jak coś takiego zrobić; Tyle że oprogramuj to sobie tak, aby tworzyła się dokładna kopia odcinka.

0

Ale to jest rozwiązanie na to, by nowa linia się pokrywała z tą starą. Powiem tak, kierunek dobry, zwrot przeciwny ;) To ma być przedłużenie starej linii. Tak, jakbym stworzył jedną na 50px i przypomniał sobie, że ona ma być na 100px długa. Klikam na wierzchołek robi sie kolejne 50px. Ale to juz osobna linia.

0

Po kiego ci osobna linia jak wystarczy dodać kolejny punkt?

0

Tak jak na rysunkach, te linie są odcinkami, nie są to nieskończone linie z punktami.

0

Powiedziałeś że ma to być kontynuacja linii, więc jeżeli masz odcinek A-B to po kliknięciu ma powstać odcinek B-C.
Więc pytam po kiego chcesz trzymać dwa odcinki: A-B i B-C
Skoro możesz trzymać sklejoną: A-B-C
?

0

One będą eksportowane na zewnętrzne potrzeby i wymagane jest, by nie łączyć dwóch o wspólnym wierzchołku.

0

Skoro i tak kiedyś umrzesz może ma sens ciebie już teraz na części pokroić?
Jak będziesz eksportować to sobie podzielisz w jednej pętli, nie utrudniaj sobie życia podczas edycji.

0

Nie rozumiem... To może podobny, pochodny problem, bo w tym trudno osiągnąć porozumienie. Mam tą linię i chcę ją wydłużyć. Pomoże ktoś?

0

Może ktoś i pomoże ale na 100% nie wcześniej niż wyraźnie powiesz z czym masz problem.

0

Chcę wydłużyć narysowany odcinek. Znam współrzędne jego końców.

2

Podstawy geometrii się kłaniają:

dx:=bx-ax;
dy:=by-ay;
Len:=sqrt(dx*dx+dy*dy);
NewLen:=Len+50;
bx:=ax+dx*NewLen/Len;
by:=ay+dy*NewLen/Len;
0

Dziękuję, temat rozwiązany.

0

@nieznany - zaczynasz przeginać...

Ale to jest rozwiązanie na to, by nowa linia się pokrywała z tą starą.

Nie o to mi chodzi... Miałem na myśli taką możliwość, aby móc narysować drugą linię, gdzie pierwszy wierzchołek nowo tworzonej linii znajduje się dokładnie w tej samej współrzędnej, co wierzchołek innej linii;

Poza tym sam sobie przeczysz:

To ma być przedłużenie starej linii. Tak, jakbym stworzył jedną na 50px i przypomniał sobie, że ona ma być na 100px długa.

Tu piszesz o wydłużeniu wskazanej linii, czyli rozciągnięciu istniejącej linii;

Klikam na wierzchołek robi sie kolejne 50px. Ale to juz osobna linia.

A tu piszesz już nie o rozciąganiu istniejącej linii, a o stworzeniu nowej - więc skup się i napisz, czy potrzebujesz wydłużyć istniejącą linię bez tworzenia nowej, czy stworzyć chcesz nową linię, która będzie miała taki sam kierunek co istniejąca; Czyli stworzenie nowej linii, która w parze z inną linią będzie wyglądać jak jedna prosta, ale składać się będzie z dwóch odcinków.

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