27. januar 2005 - 15:25Der er
8 kommentarer og 1 løsning
Scroll i en StringGrid
Mojn,
Jeg har en StringGrid på min form, der skal forestille en kalender med en række for hver dag. Dertil hører et sæt knapper til at rette indholdet af rækkerne. Det er så meningen, at når man flytter markeringen fra en række til en anden, så skal programmet kontrollere, om der er meldt nogen data ind i den række, man har hoppet til. Hvis rækken er tom, skal knapperne deaktiveres, og hvis der er noget, skal de aktiveres.
Jeg har klaret tastatur input - jeg har en OnKeyUp event, som holder øje med tryk på piltasterne, PageUp, PageDown, Home, End ...
Jeg har også fået bugt med museklik - En OnMouseDown event kontrollerer, om der er noget i den række, man har klikket på.
Nu mangler jeg bare scroll events. Jeg har lavet en OnMouseWheelDown og en OnMouseWheelUp event handlere, men der er noget, der ikke virker. StringGrid'dens Row property er ikke blevet opdateret på det tidspunkt, hvor de event handlere bliver fyret af, men først efter. Så hvis jeg scroller fra en tom linie til en med noget data, så kan min nuværende kode ikke kontrollere den nye række, men kigger i den tomme, og følgeligt ikke "tænder" knapperne.
Har jeg misforstået noget ?
Man kan vel ikke pille i den rækkefølge, de forskellige events kommer ?
StringGrid har et OnSelectCell event du kan bruge. Der får du Col og Row på den cell der er blevet selected enten via kbd, mus eller når du scroller. Så slipper du for alt det andet.
Jeg har haft kigget på OnSelectCell til at starte. Jeg har lavet et testprogram, som kun havde en StringGrid på formen. I OnMouseWheelUp, OnMouseWheelDown, OnMouseDown, OnKeyUp og i OnSelectCell har jeg puttet et ShowMessage() kald med en beskrivelse af den event, der er blevet trigget samt værdien af StringGrid.Row. I OnSelectCell tog jeg også ARow med.
Jeg har fundet ud af, at OnSelectCell kommer før OnMouseDown / OnKeyUp, men efter OnMouseWheelDown / OnMouseWheelUp.
Det bliver først tricky, når man skal tage højde for situationer, hvor brugeren markerer mere end en række. Jeg har brugt en "for i_row := StringGrid.Selection.Top to StringGrid.Selection.Bottom" løkke til at løbe igennem det markerede område. Men på det tidspunktet, hvor programmet håndterer en OnSelectCell, er de værdier endnu ikke blevet opdateret.
Jeg har en foreløbig løsning. Den er ikke skøn, men det virker.
I OnMouseWheelDown og OnMouseWheelUp sætter jeg et flag : b_isScroll: Boolean. OnSelectCell checker, om flaget er sat. Hvis det er - kalder den min EnableEditControls procedure og stikker den værdien af ARow som parameter. Hvis flaget ikke er sat, betyder det, at en række eller flere er blevet markeret v.h.a. museklik eller tastaturtryk - i dette tilfælde foretager OnSelectCell ikke noget. Det bliver så OnKeyUp og OnMouseDown, der får til opgave at kalde EnableEditControls, fordi på det tidspunkt er StringGrid.Selection.Top og StringGrid.Selection.Bottom sat og kan bruges til at se, om de(n) valgte række(r) kan rettes, og om knapper derfor skal gøres tilgængelige.
Jeg lader lige spørgsmålet stå lidt endnu. Det kan være, nogen kan fortælle om en mere elegant / simpel måde at gøre det på ...
Ihvertfald i Delphi 7 som jeg bruger virker piltaster, Home, End, Mouse Wheel osv. automatisk, dvs. de er allerede programmet til at skifte mellem cellerne når StringGrid'en har fokus. Så som doc404 er inde på kan burde du bare kunne nøjes med at lægge din kode i et OnSelectCell-event. Jeg har verificeret dette ved at droppe en TStringGrid og en TListBox på en TForm og i TStringGrid'ens OnSelectCell-event skrevet flg. kode:
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); begin Listbox1.Items.Add(IntToStr(ACol)+' - '+IntToStr(ARow)); end;
Problemet er ikke, at OnSelectCell ikke virker. Problemet er, at den procedure, jeg har til at kontrollere indholdet af rækkerne og slå knapper til og fra - EnableEditControls - bygger på en løkke :
.. for StringGrid.Selection.Top to StringGrid.Selection.Bottom do ..
Den bliver kaldt fra OnMouseDown og OnKeyUp - events, der kommer efter OnSelectCell.
Men når OnMouseWheelDown / OnMouseWheelUp eventet kommer, er Top og Bottom værdierne stadig ikke opdateret - det sker først efter OnSelectCell. Jeg kan derfor ikke benytte min eksisterende procedure, som den er og kalde den fra OnMouseWheelDown / OnMouseWheelUp, men skal lave nogle krumspring.
Jeg har dog fundet frem til, at når man scroller med musen, så bliver der altid kun markeret en række - det udnytter jeg så - fordi nu ved jeg, at Top og Bottom begge bliver sat lig med værdien af ARow i OnSelectCell. Jeg kan derfor kalde min EnableEditControls med ARow som parameter.
Hvorfor har du et for-loop? Det kan godt være at jeg så har misforstået opgaven, men jeg ville da bare disable/enable knapperne i OnSelectCell udfra ARow/ACol - altså ikke noget med loop..?
Programmet tillader brugeren at markere flere sammenhængende rækker i StringGrid'en, også selvom der er nogle tomme med i det valgte område. For at kontrollere gyldigheden af alle de valgte rækker bruger jeg så en for-loop til at gennemløbe StringGrid.Selection fra StringGrid.Selection.Top til StringGrid.Selection.Bottom.
Punkt 2. Events.
I selve OnSelectCell event'et er der ikke mulighed for at kontrollere, om brugeren har SHIFT trykket ned, og om der dermed skal markeres mere end en række - derfor får brugeren lov til markere hvad som helst. Som det står forklaret ovenfor, reagerer min OnSelectCell kun, når brugeren bruger musens scroll knap, og det kun på grund af den rækkefølge, som de forskellige events kommer i.
Punkt 3. EnableEditControls.
For at slippe for at have koden til håndtering af brugerens valg spredt over flere event-handler'e og gentagelser, har jeg samlet alt, der har med enabling/disabling af knapper m.m. at gøre i én procedure - EnableEditControls. Den bliver så kaldt, når brugeren har markeret en eller flere rækker på den ene eller den anden måde.
Et eksempel :
Brugeren vælger en række ved at klikke med venstre museknap (OnSelectCell foretager sig ikke noget, OnMouseDown kalder EnableEditControls - nemt nok), derefter holder brugeren SHIFT nede og klikker på en række længere nede (igen foretager OnSelectCell sig ikke noget og OnMouseDown kalder EnableEditControls). Hvis brugeren nu giver sig til at bruge piltasterne eller PageUp/PageDown/Home/End samtidigt med, at SHIFT stadig holdes nede, bliver det rigtigt sjovt. I stedet for at OnSelectCell nu skal til at sammenligne værdierne af ARow, StringGrid.Row, StringGrid.Selection.Top og StringGrid.Selection.Bottom for at finde ud af, hvor stort et område, der nu forsøges valgt, lader den som ingenting - OnKeyUp kalder EnableEditControls, når det nye område er markeret. Det eneste min OnSelectCell har af opgaver er at sørge for at opfange, når brugeren scroller - i disse tilfælde bliver det altid kun en række (ARow), der skal undersøges.
Nå, der kom ikke flere forslag. Tid til at pakke sammen.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.