Kilka elementów do StringGrid

0
  1. Mam kilka gridów na panelu, jak zrobić żeby program rozpoznawał, że myszka jest nad tym konkretnym i który ma obsługiwać, ale nie podświetlał go.
  2. Poszerzanie głównej kolumny automatycznie, ale tak aby nie była za szeroka w momecnie pojawienia się scrollbara.

Kod jest napisany tak, żeby automatycznie rozszerzała się w tym przypadku pierwsza kolumna, jeśli ostatnia kolumna sięga, krócej niż szerokość komponentu. Niestety w momencie gdy pojawia się scrollbar, szerokość się zmniejsza i pierwsza kolumna rozszerza się za bardzo.

  1. Po naciśnięciu przycisku na scrollbarach za tabelką pojawia się jeszcze tło, jak je usunąć?

  2. Przesuwanie myszką. Jak odnieść się do scrollbara, tak żeby przesuwał całego grida bezpośrednio po przekręceniu kółka myszy, a nie obniżał tylko o jedną komórkę.

  3. Czy można nadpisać procedurę Invalidate, tak by dopisać do niej kilka swoich procedur do wykonania?

  4. Mam zaprogramowane zdarzenie MouseMove, tak, że po przesunięciu kursora nad wiersz, ten się zaznacza. Jednak po przesunięciu go poza wszystkie wiersze, ale dalej w obrębie koponentu, wiersz który powinien wrócić do normalnej formy, nadal jest podświetlony.

Cały kod: http://4programmers.net/Pastebin/5870
W linkach zdjęcia, obrazujące jako tako to co jest opisane w danym punkcie.

2
  1. https://www.google.pl/search?q=delphi+control+at+mouse+position
  2. ClientWidth zamiast Width i poczytać czym się różni jedno od drugiego
  3. co, gdzie?
  4. co to znaczy całego? Na koniec? Ogólnie https://www.google.pl/search?q=delphi+stringgrid+mouse+wheel
  5. tak
  6. no to musisz dodać "odznaczenie" go w momencie wyjścia z komponentu albo przesunięcia myszki na "pusty" obszar.
0
  1. zobacze jutro co tam jest
  2. zrobione
  3. na drugiej grafice widać po prawej stronie jeszcze tło tabeli. przy przesuwaniu paskiem się nie pojawia, ale po naciśnięciu przycisku w prawo lub w dół pojawia się tak jakby dodatkowy wiersz/kolumna
  4. nie na koniec. po prostu obniżenie całej zawartości bezpośrednio po przekęceniu kółka. normalnie dzieje się tak, że po przekręceniu zaznacza się komórka o jedna niżej i dopiero jak focus zejdzie na sam dół tego co jest wyświetlone to obniża się dalej tak, że jest widoczne to co nie było wcześniej. W stringboxie robilem to w zdarzeniu on mousewheel poprzez scrollbox.vertscrollbar.position := ...
  5. tu będę musiał poprawić warunki, ale wszystko chyba działa
  6. jest obsługa mouseleave komponentu i wtedy faktycznie sie odznacza, problem mam w momencie gdy mam rozpoznać że kursor jest poza obszarem realnej tabeli

w zdarzeniu mousemove dodałem

 

  VCursor.X := X;
  VCursor.Y := Y;   

  if (FCol <> -1) and (FRow <> -1) then
    begin
      for I := 1 to ColCount - 1 do
        for J := 1 to RowCount - 1 do
          if PtInRect(CellRect(I, J), VCursor) then
            CrInTab := True;

      if CrInTab = False then
        begin
          for I := 1 to ColCount - 1 do
            begin
              SGCell[I, FRow].Focus := False;
              DrawCell(Sender, I, FRow, CellRect(I, FRow), [gdSelected]);
            end;
          DrawCell(Sender, 0, FRow, CellRect(0, FRow), [gdSelected]);
        end;
    end;

i faktycznie działa to niemal idealnie. konkretnie odznacz się zaznaczony wiersz, za to po najechaniu na najniższy wiersz, nie zaznacza się on. będę kombinował z tym jutro

EDIT
MouseMove działa chyba dobrze. kod zdarzenia wygląda teraz tak:

 
  CrInTab := False;
  CellCoord := MouseCoord(X, Y);
  VCursor.X := X;
  VCursor.Y := Y;

  for I := 1 to ColCount - 1 do
    for J := 1 to RowCount - 1 do
      if PtInRect(CellRect(I, J), VCursor) then
        CrInTab := True;

  if CrInTab then
    if FRow <> CellCoord.Y then
      begin
        if (FCol <> -1) and (FRow <> -1) then
          begin
            for I := 1 to ColCount - 1 do
              begin
                SGCell[I, FRow].Focus := False;
                DrawCell(Sender, I, FRow, CellRect(I, FRow), [gdSelected]);
              end;
            DrawCell(Sender, 0, FRow, CellRect(0, FRow), [gdSelected]);
          end;
        if CellCoord.Y <> 0 then
          begin
            for I := 1 to ColCount - 1 do
              begin
                SGCell[I, CellCoord.Y].Focus := True;
                DrawCell(Sender, I, CellCoord.Y, CellRect(I, CellCoord.Y), [gdSelected]);
              end;
            DrawCell(Sender, 0, CellCoord.Y, CellRect(0, CellCoord.Y), [gdSelected]);
          end;
    end;

  if (FCol <> -1) and (FRow <> -1) then
    begin
      if CrInTab = False then
        begin
          for I := 1 to ColCount - 1 do
            begin
              SGCell[I, FRow].Focus := False;
              DrawCell(Sender, I, FRow, CellRect(I, FRow), [gdSelected]);
            end;
          DrawCell(Sender, 0, FRow, CellRect(0, FRow), [gdSelected]);
          FCol := -1;
          FRow := -1;
        end;
    end;

  if CrInTab then
    begin
      FCol := CellCoord.X;
      FRow := CellCoord.Y;
    end;   
2
  1. tak działa grid - zauważ, że w lewo/prawo nie przewija się o x pikseli ale o szerokość komórki(komórek).
procedure TForm1.sg1MouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  Handled := True;
  SendMessage(sg1.Handle, WM_VSCROLL, 1, 0);
end;

procedure TForm1.sg1MouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  Handled := True;
  SendMessage(sg1.Handle, WM_VSCROLL, 0, 0);
end;
0
  1. A czy mimo wszystko da się to jakoś wyłączyć? Nie bardzo mi to pasuje, bo opuszczeniu na sam dół, żeby było widoczne jeszcze coś co nie jest już tabelką :/ W załączniku zamieszczam screena. Chodzi o ten element na czerwono.

  2. Jeszcze jeden dodatkowy problem. Wyłączenie całkowite focusa. Tabelka ma tylko wyświetlać dane. W konstruktorze umieściłem

TabStop := False

co powoduje iż nie jest podświetlona komórka [1,1] na starcie. Jednak później po kliknięciu w jakąkolwiek komórkę, zostaje ona podświetlona.

0
  1. no ale zaraz - wcześniej pisałeś o prawej stronie, teraz piszesz o dolnej. Dolnej też nie zniwelujesz ponieważ SG wyświetla wiersze od góry, tzn. nie przewija pikselami ale wierszami i jeśli wysokość obszaru roboczego SG nie dzieli się bez reszty przez wysokość wiersza to zawsze dostaniesz pasek na dole. Dzieje się tak dlatego, żeby ostatni wiersz pokazać w całości.
    Może wybrałeś zły komponent do wyświetlania - może np. ListBox byłby tu odpowiedniejszy, zważywszy, że nie korzystasz z żadnych "dobrodziejstw" SG.

  2. Musisz w malowaniu komórki nie obsługiwać zaznaczeni, co też czynisz tu

    if SGCell[ACol, ARow].Select then
      begin
        Brush.Color := SGCell[ACol, ARow].BackColor.Selected;
        Font.Color := SGCell[ACol, ARow].CFont.Color.Selected;
      end
    else
    if SGCell[ACol, ARow].Focus then
      begin
        Brush.Color := SGCell[ACol, ARow].BackColor.Focused;
        Font.Color := SGCell[ACol, ARow].CFont.Color.Focused;
      end
    else
      begin
        Brush.Color := SGCell[ACol, ARow].BackColor.Regular;
        Font.Color := SGCell[ACol, ARow].CFont.Color.Regular;
      end;
0

W razie czego, usunięcie ramki fokusa można obsłużyć inaczej, czyli ją zamalować :]

if sgFocused in AState then
begin
  Pen.Color := Pen.Color xor $FFFFFF;
  DrawFocusRect(ARect);
end;

Jeżeli nie umiesz pozbyć się tej ramki inaczej, rzecz jasna.

0

@abrakadaber:

Wydawało mi się, że to jednak będzie najodpowiedniejszy komponent, w momencie gdy mam do wyświetlenia dużą ilość danych w tabeli. Najłatwiej było go zmodyfikować do moich potrzeb. Te dwa elementy są już ostatnimi, które muszę poprawić. Co do punktu 3. To chodziło mi zarówno o ten pasek z prawej jak i o ten dolny. Ale jeśli się nie da, to na razie zostawię tak jak jest.

Natomiast jeśli chodzi o punkt 7. Ten kod pokazuje tylko moje zaznaczenia, a konkretnie najechanie na dany wiersz, powoduje zmianę koloru, tak samo zaznaczenie danego wiersza ze względu na dane w nim zawarte, powoduje zmianę na jeszcze inny kolor. Mi natomiast chodzi o taki czerwony obrys. Dołączam screeny. Chodzi o komórki nad którymi jest kursor, po kliknięciu w nie, robi się taki obrys.

@furious programming:

Przy czym, raczej chciałem pominąć malowania. Chyba, że nie jest to przeciwwskazane.

0

Przy czym, raczej chciałem pominąć malowania. Chyba, że nie jest to przeciwwskazane.

Wskazane jest, że komórka trzymająca fokusa (sgFocused) powinna być malowana inaczej niż ta podświetlona (sgSelected), zaznaczona inaczej niż zwykła, a zwykła inaczej niż fixed;

Teraz powinno być wszystko jasne :]

0

A jednak niestety nie jest. Zwłaszcza, że to się dzieję, tylko w momencie kliknięcia na daną komórkę, a nie w momencie najechania na nią.

Przy wciśnieciu LPM i przesuwaniu, podświetla się ta komórka nad którą jest kursor, a zaznaczenie poprzedniej znika.

1

Bo komponent nie ma zdarzenia typu OnMouseEnter i OnMouseLeave dla komórek; Komórki przemalowywane są jedynie po zmianie fokusa, po zaznaczeniu/odznaczeniu oraz po zablokowaniu/odblokowaniu komponentu;

Zobacz sobie pod maskę klasy TStringGrid i prześledź kod malowania komponentu, a zobaczysz, że nie jest to takie hop siup; No i też zobaczysz, że nie ma tam obsługi ficzera, którego potrzebujesz; Ale to nie zmienia faktu, iż możesz sobie rozszerzyć klasę TStringGrid (a jeszcze lepiej jej klasę bazową) i taki ficzer sobie dodać; Uprzedzam, że nie będzie to łatwe.

0

Przyznam szczerzę że kompletnie się w tym pogubiłem :/ Próbowałem tak

 

procedure TMyGrid.SelectCell(Sender: TObject; aCol, aRow: Integer;
  var CanSelect: Boolean);
begin
  CanSelect := False;
end;

Po części podziałało, bo już nie zaznacza się komórka naciśnięta, ale wtedy cały czas zaznaczona jest komórka [1, 1].

Próbowałem też przemalować konkretną komórkę po kliknięciu w nią, ale to również nie dało tego czego bym chciał.

0

Napisz jeszcze raz, w jednym długim zdaniu, jaki efekt konkretnie Cię interesuje; Pomaluj kontrolkę np. w Paint i dorzuć do załączników - znacznie ułatwisz nam odpowiadanie i szybciej uzyskasz pomoc.

0

Ogólnie nie potrzebuję żadnego Focusa. Może niepoprawnie bo dopiero się uczę tego StringGrida zrobiłem tak, że dla każdej komórki stworzyłem Record danych i w nim przechowuje informację czy jest zaznaczona, czy kursor jest nad nią etc. W żaden sposób nie wykorzystuję parametru aState.

W StringGridzie focus ustawia się na klikniętej komórce i dzięki temu jest ona obrysowana czerwoną linią, a w sumie kropkami. Ja nie chcę żeby te kropki były pokazane. Nie chcę, żeby było malowane po kliknięciu.

0

W żaden sposób nie wykorzystuję parametru aState.

Pokazałem Ci jak usunąć fokusa - ten warunek wcześniej; Na końcu zdarzenia malowania komórki sprawdź, czy w AState znajduje się enum sgFocused i jeśli tak to wykonaj sztuczkę z Xor koloru ołówka i metodą DrawFocusRect; Taki trick robiłem z różnymi kontrolkami pod Delphi7, ale w Lazarusie też powinien działać.

0

Kod:

if gdFocused in AState then
    begin
      Canvas.Pen.Color := Canvas.Pen.Color xor $FFFFFF;
      Canvas.DrawFocusRect(ARect);
    end;
 

dał efekt jak na załączonym screenie.

1

@dani17 - bo nie ustawiłeś właściwości DefaultDrawing na False!

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState);
var
  Grid: TStringGrid absolute Sender;
begin
  with Grid.Canvas do
  begin
    if (ACol < Grid.FixedCols) or (ARow < Grid.FixedRows) then
      Brush.Color := clBtnFace      // fixed
    else
      if gdSelected in AState then
        Brush.Color := clLtGray     // selected
      else
        Brush.Color := clWhite;     // normal

    FillRect(ARect);

    if gdFocused in AState then     // focused & selected
    begin
      Brush.Color := clGray;
      FrameRect(ARect);
    end;
  end;
end;

Efekt działania kodu jest następujący:

grid.png

Jak widzisz, wygląda tak jak według kodu ma wyglądać, bez kropkowanej, standardowej ramki fokusa; W opcjach usunąłem rysowanie standardowej siatki, dlatego jej nie ma; To co najważniejsze - komórka trzymająca fokusa ma malowane obramowanie na ciemnoszaro, co widać na zrzucie;

Tak więc wszystko działa jak należy.

0

Okej, wszystko rozwiązane. To DefaultDrawing było problemem. Nie wiem czemu ustawiłem na True, a wydaje mi się, że to juz automatycznie jest na True. Miało być od początku False, a później szukałem rozwiązania gdzieś indziej i o tym nie pomyślałem.

A teraz jeszcze jedno tylko dodatkowe pytanie, z ciekawości, bo już tego na razie nie zamierzam używać. Czy w DrawCell można pomalować komórkę np. gradientem?

1

Nie wiem czemu ustawiłem na True, a wydaje mi się, że to juz automatycznie jest na True.

Automatycznie jest na True, co pozwala na pomalowanie komponentu według systemowego, natywnego schematu;

Czy w DrawCell można pomalować komórkę np. gradientem?

A jaka jest różnica pomiędzy malowaniem prostokątów a gradientów? Jedno i drugie to malowanie;

Zrozum jedną rzecz - zdarzenie OnDrawCell dostarcza m.in. obszar komórki i jej stan, zawarty w zbiorze z parametru AState; Masz podany obszar, więc wiadomo gdzie malować, masz też stan danej komórki, więc wiadomo co/jak malować; Możesz sobie z tym obszarem robić co Ci się podoba - malować figury, linie, kropki, kreski, gradienty, wszystko co chcesz, również obrazki przezroczyste i nieprzezroczyste (ograniczeniem jest jedynie wyobraźnia);

Przykład uzyskanego efektu znajdziesz choćby w sąsiednim wątku :]

0

Zaciekawiło mnie tam to co pisałeś o pół przezroczystym prostokącie. To byłaby fajna opcja, ale jak taką przezroczystość zrobić? To tak dodatkowo.

A do zamknięcia wątku potrzebuje jeszcze raz pomocy. W momencie wciskania przycisku otwiera się Panel na którym umieszczony jest ten StringGrid. Jednak w momencie kliknięcia zanim wszystkie dane się pojawią, dwukrotnie w różnych miejscach przebijają się ScrollBary, co nie wygląda za ciekawie.

0

Zaciekawiło mnie tam to co pisałeś o pół przezroczystym prostokącie. To byłaby fajna opcja, ale jak taką przezroczystość zrobić? To tak dodatkowo.

To jest tylko półprzezroczysty efekt, nie prawdziwa przezroczystość - płótno obsługuje 24-bitową głębię, a nie 32-bitową; Wszystko zależy od tego, jaki efekt Cię interesuje;

Jeśli chodzi o proste malowanie chodzi (np. jednokolorowe tło) to teoretyczną półprzezroczystość można uzyskać za pomocą odpowiedniego zmieszania składowych RGB dwóch kolorów (czyli dokładnie to, co robią znane mechanizmy, podczas malowania piksela 32-bitowego na 24-bitowym płótnie);

Drugi sposób to użycie półprzezroczystej grafiki, np. PNG 32-bit - wystarczy ją przygotować w programie graficznym obsługującym przezroczystość (np. Paint.NET) i namalować na kanwie; Tyle, to cała filozofia - zapewne ten sposób wybrał @karpov w swoim programie;

W momencie wciskania przycisku otwiera się Panel na którym umieszczony jest ten StringGrid. Jednak w momencie kliknięcia zanim wszystkie dane się pojawią, dwukrotnie w różnych miejscach przebijają się ScrollBary, co nie wygląda za ciekawie.

Kod + co najmniej jeden zrzut ekranu, z tym złym efektem (ew. drugi z oczekiwanym).

0

Ok, postaram się wrzucić kod, ale to jutro. Przy czym nie jestem w stanie zrobić screena, bo to jest takie mignięcie i po chwili pojawia się wszystko tak jak powinno.

0

W załączniku przesyłam archiwum z projektem. Dodatkowo dwa screeny. Na pierwszym udało mi się uchwycić co się pokazuje przez chwilę, a na drugim efekt końcowy i docelowy. Taki jaki chciałbym widzieć od początku.

Wszytko dzieje się po kliknięciu Przycisk, Przycisk 2 usuwa całość.

0

@dani17 - wiesz po co kompilator uzupełnia okienko Messages? Po to, aby móc zlokalizować i poprawić teoretyczne problemy, a w kodzie Twojego projektu jest tego tyle:

Compile Project, Target: project1.exe: Success, Warnings: 4, Hints: 7

unit1.pas(83,15) Warning: An inherited method is hidden by "DrawCell(TObject;LongInt;LongInt;RECT;TGridDrawState);"
unit1.pas(84,15) Warning: An inherited method is hidden by "MouseMove(TObject;TShiftState;LongInt;LongInt);"
unit1.pas(85,15) Warning: An inherited method is hidden by "MouseLeave(TObject);"
unit1.pas(96,17) Warning: An inherited method is hidden by "constructor Create(TComponent;TSGStartInfo);"
unit1.pas(9,3) Hint: Unit "Types" not used in Unit1

Pominąłem hinty dotyczące nieużywanych argumentów metod (te z kolei można wyłączyć w ustawieniach projektu); Po czystej kompilacji, okienko Messages ma posiadać tylko jedną linijkę:

Compile Project, Target: project1.exe: Success

W przeciwnym razie nie ma sensu uruchamiać aplikacji; Chyba że celowo uruchamiasz aplikację, aby przetestować niedokończony kod, który powoduje hinty (np. podpowiedź o nieużywanych zmiennych);

Wracając do tego migania - jeżeli tworzysz komponent dynamicznie to najpierw go poustawiaj, a dopiero na sam koniec pokaż na ekranie; W przeciwnym razie najpierw zostanie wyświetlona surowa kontrolka, a dopiero później zmodyfikowana, co będzie widoczne właśnie jako mignięcie.

0

Okej, jeśli chodzi o nieużyte argument i moduły to tylko tymczasowo tak jest, później będzie zrobiony z tym porządek. Co do An inherited method is hidden by... to już kiedyś miałem taki problem i na tym forum było napisane, że to może tak zostać. Chyba, że coś źle zrozumiałem.

Migania faktycznie już nie ma.

0

Te ostrzeżenia nie są generowane randomowo, więc ignorując je, sam prosisz się o problemy; Sprzątaj kod od razu i nie zbieraj ostrzeżeń i podpowiedzi na później, bo później zapomnisz skąd one się wzięły i będziesz miał więcej roboty;

Jeśli chodzi o nieużywane moduły - kompilator i tak nie pokazuje wszystkich, bo np. moduł Dialogs, choć nieużywany, nie będzie brany pod uwagę (nie rozumiem dlaczego); W każdym razie, lepszym rozwiązaniem jest opcja:

  • RefactoringUnused units ...,
    dostępna w menu kontekstowym edytora kodu;

Ta opcja w sumie też jest z d**y, bo podpowiada usunięcie modułu Interfaces z głównego pliku projektu, a bez niego żadna standardowa aplikacja okienkowa nie może być skompilowana (w nim zawarty jest wymagany widgetset); Tak więc używaj jej, ale pamiętaj, aby nie ruszać modułu Interfaces - resztę możesz bezpiecznie usuwać z kodu.

0

A jak sobie poradzić z An inherited method is hidden by...?

0

Nie będę kombinował z subclassingiem i utworzę własny komponent w normalny sposób - najpierw pusta paczuszka, a w niej moduł kontrolki; Do tego użyję nadpisanej wersji konstruktora klasy bazowej, bez kombinacji z dodatkowym parametrem; A na koniec opatrzę taką deklarację słówkiem Override, tak samo jak destruktor:

public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy(); override;

Utworzenie Twojego komponentu z wykorzystaniem standardowego, jednoargumentowego konstruktora rozwali komponent, dlatego że dodatkowe dane nie zostaną zaalokowane.
Natomiast dodatkowe dane dla komponentu umieszczę w polach klasy, dając możliwość ich modyfikacji za pomocą publicznych metod lub publicznych/upublicznionych właściwości.

0

Mimo wszystko nie widzę w tym rozwiązania. Na prawdę nie mam pojęcia nawet skąd się bierze ten błąd. Jedyne co tutaj widzę to override czy konstruktorze, przy czym w moim przypadku nie można tego zrobić, ponieważ mam dwa przekazywane parametry.

Czy jest to kwestia nazw? Po zmianie jednej z nich ten jeden błąd zniknął.

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