Io e 2 persone abbiamo cercato di capire quale dovrebbe essere una formula semplice. Ho una griglia, che può avere un numero variabile di colonne e righe. Quando l'utente fa clic su una delle celle, devo determinare quale 'indice' è stato cliccato in base a colonna/riga. Gli indici iniziano da 0 e vanno da sinistra a destra, quindi dall'alto verso il basso. Non ci sono colonne/righe fisse.Matematica per determinare l'indice delle voci in base alla selezione di colonne/righe nella griglia
Esempio di ciò che intendo:
Quindi, se ci sono 3 colonne, e l'utente clicca sul C2/R1, quindi ha bisogno di risolvere l'indice di 5. Tutti gli indici partono da 0 in questo esempio .
La mia formula attuale, che è lontano dal lavoro, è come questo:
//I = Calculated index based on row/col (starts from 0)
//ACol = Column index user clicked (starts from 0)
//ARow = Row index user clicked (starts from 0)
//ColCount = Number of columns
I:= (C * ColCount) + (R - ColCount);
EDIT
Per riferimento, qui è tutta la mia unità componente di seguito.
La linea con la formula è contrassegnato con un commento "FORMULA QUI"
unit ImageGrid;
interface
uses
Windows, Classes, SysUtils, Grids, Graphics, StdCtrls, ExtCtrls, Controls,
Jpeg, PngImage;
type
TImageGrid = class;
TImageGridItem = class;
TGridSizing = (gsManual, gsAuto, gsFit);
TImageGridItem = class(TObject)
private
FFilename: TFilename;
FOwner: TImageGrid;
FBmp: TBitmap;
procedure Event;
procedure SetFilename(const Value: TFilename);
public
constructor Create(AOwner: TImageGrid);
destructor Destroy; override;
procedure LoadFile;
published
property Filename: TFilename read FFilename write SetFilename;
end;
TImageGrid = class(TCustomDrawGrid)
private
FItems: TStringList;
FCacheDir: String;
FRowHeight: Integer;
FColWidth: Integer;
FSizing: TGridSizing;
FItemIndex: Integer;
procedure SetCacheDir(const Value: String);
procedure SetColWidth(const Value: Integer);
procedure SetRowHeight(const Value: Integer);
procedure SetSizing(const Value: TGridSizing);
function GetItem(Index: Integer): TImageGridItem;
procedure SetItem(Index: Integer; const Value: TImageGridItem);
procedure SetItemIndex(const Value: Integer);
procedure SelectCell(Sender: TObject; ACol, ARow: Longint;
var CanSelect: Boolean);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Count: Integer;
property Items[Index: Integer]: TImageGridItem
read GetItem write SetItem; default;
function Add: TImageGridItem;
procedure Delete(const Index: Integer);
procedure Clear;
published
property CacheDir: String read FCacheDir write SetCacheDir;
property ColWidth: Integer read FColWidth write SetColWidth;
property RowHeight: Integer read FRowHeight write SetRowHeight;
property Sizing: TGridSizing read FSizing write SetSizing;
property ItemIndex: Integer read FItemIndex write SetItemIndex;
property Align;
property Anchors;
property BevelEdges;
property BevelInner;
property BevelKind;
property BevelOuter;
property BevelWidth;
property BiDiMode;
property BorderStyle;
property Color;
property ColCount;
property Constraints;
property Ctl3D;
property DefaultColWidth;
property DefaultRowHeight;
property DefaultDrawing;
property DoubleBuffered;
property DragCursor;
property DragKind;
property DragMode;
property DrawingStyle;
property Enabled;
property Font;
property GradientEndColor;
property GradientStartColor;
property GridLineWidth;
property Options;
property ParentBiDiMode;
property ParentColor;
property ParentCtl3D;
property ParentDoubleBuffered;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ScrollBars;
property ShowHint;
property TabOrder;
property Touch;
property Visible;
property OnClick;
property OnColumnMoved;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawCell;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnGesture;
property OnGetEditMask;
property OnGetEditText;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseActivate;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnRowMoved;
property OnSelectCell;
property OnSetEditText;
property OnStartDock;
property OnStartDrag;
property OnTopLeftChanged;
end;
implementation
//Register procedure will come later...
{ TImageGrid }
function TImageGrid.Add: TImageGridItem;
begin
Result:= TImageGridItem.Create(Self);
FItems.AddObject('', Result);
end;
procedure TImageGrid.Clear;
begin
while Count > 0 do
Delete(0);
end;
function TImageGrid.Count: Integer;
begin
Result:= FItems.Count;
end;
constructor TImageGrid.Create(AOwner: TComponent);
begin
inherited;
Options:= [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine,
goRangeSelect,goThumbTracking];
Parent:= TWinControl(AOwner);
FItems:= TStringList.Create;
FixedCols:= 0;
FixedRows:= 0;
RowCount:= 1;
ColCount:= 1;
FColWidth:= 100;
FRowHeight:= 100;
ColWidths[0]:= FColWidth;
RowHeights[0]:= FRowHeight;
FSizing:= gsManual;
FItemIndex:= -1;
OnSelectCell:= SelectCell;
Invalidate;
end;
procedure TImageGrid.Delete(const Index: Integer);
begin
if (Index >= 0) and (Index < FItems.Count) then begin
TImageGridItem(FItems.Objects[Index]).Free;
FItems.Delete(Index);
end else begin
raise Exception.Create('List index out of bounds ('+IntToStr(Index)+')');
end;
end;
destructor TImageGrid.Destroy;
begin
FItems.Free;
inherited;
end;
function TImageGrid.GetItem(Index: Integer): TImageGridItem;
begin
if (Index >= 0) and (Index < FItems.Count) then begin
Result:= TImageGridItem(FItems.Objects[Index]);
end else begin
Result:= nil;
raise Exception.Create('List index out of bounds ('+IntToStr(Index)+')');
end;
end;
procedure TImageGrid.Paint;
var
Bmp: TBitmap;
C: Integer;
RC: Integer;
CC: Integer;
X, Y: Integer;
I: TImageGridItem;
R: TRect;
procedure DrawImage(B: TBitmap; const R: TRect);
begin
Canvas.StretchDraw(R, B);
end;
begin
Canvas.Brush.Style:= bsSolid;
Canvas.Pen.Style:= psClear;
Canvas.Brush.Color:= clWhite;
Canvas.FillRect(Canvas.ClipRect);
Bmp:= TBitmap.Create;
try
if Count > 0 then begin
case FSizing of
gsManual: begin
//Draw like regular grid with variable sizes - expand rows as needed
inherited;
end;
gsAuto: begin
//Calculate image width based on col count
end;
gsFit: begin
//Calculate col count based on image width
CC:= Trunc(ClientWidth/FColWidth);
RC:= Trunc(Count/CC);
ColCount:= CC;
RowCount:= RC;
for X := 0 to ColCount - 1 do
ColWidths[X]:= FColWidth;
for X := 0 to RowCount - 1 do
RowHeights[X]:= FRowHeight;
Canvas.Brush.Style:= bsSolid;
Canvas.Pen.Style:= psSolid;
Canvas.Brush.Color:= clWhite;
Canvas.Pen.Width:= 1;
C:= 0; //C = Count of items to show
for X := 0 to ColCount - 1 do begin
for Y := 0 to RowCount - 1 do begin
I:= Self.Items[C];
if C = FItemIndex then begin
Canvas.Pen.Color:= clRed;
Canvas.Pen.Width:= 2;
end else begin
Canvas.Pen.Color:= clNavy;
Canvas.Pen.Width:= 1;
end;
R:= CellRect(X,Y);
Canvas.Rectangle(R);
InflateRect(R, -4, -4);
Canvas.StretchDraw(R, I.FBmp);
C:= C + 1;
end;
end;
end;
end;
end else begin
ColCount:= 1;
RowCount:= 1;
end;
finally
Bmp.Free;
end;
end;
procedure TImageGrid.SelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
var
I: Integer;
C, R: Integer;
begin
//Determine item index based on col/row
C:= ACol;
R:= ARow;
//I = Calculated index based on row/col (starts from 0)
//ACol = Column index user clicked (starts from 0)
//ARow = Row index user clicked (starts from 0)
//ColCount = Number of columns
I:= (R * ColCount) + C; // <<----- FORMULA HERE
if I < Count - 1 then begin
FItemIndex:= I;
CanSelect:= True;
end else begin
FItemIndex:= -1;
CanSelect:= False;
end;
Invalidate;
end;
procedure TImageGrid.SetCacheDir(const Value: String);
begin
if Value <> FCacheDir then begin
FCacheDir := Value;
Invalidate;
end;
end;
procedure TImageGrid.SetColWidth(const Value: Integer);
begin
if Value <> FColWidth then begin
FColWidth := Value;
Invalidate;
end;
end;
procedure TImageGrid.SetItem(Index: Integer; const Value: TImageGridItem);
begin
if (Index >= 0) and (Index < FItems.Count) then begin
FItems.Objects[Index]:= Value;
Invalidate;
end else begin
raise Exception.Create('List index out of bounds ('+IntToStr(Index)+')');
end;
end;
procedure TImageGrid.SetItemIndex(const Value: Integer);
begin
if Value <> FItemIndex then begin
FItemIndex := Value;
Invalidate;
end;
end;
procedure TImageGrid.SetRowHeight(const Value: Integer);
begin
if Value <> FRowHeight then begin
FRowHeight := Value;
Invalidate;
end;
end;
procedure TImageGrid.SetSizing(const Value: TGridSizing);
begin
if Value <> FSizing then begin
FSizing := Value;
Invalidate;
end;
end;
{ TImageGridItem }
constructor TImageGridItem.Create(AOwner: TImageGrid);
begin
FOwner:= AOwner;
FBmp:= TBitmap.Create;
end;
destructor TImageGridItem.Destroy;
begin
FBmp.Free;
inherited;
end;
procedure TImageGridItem.Event;
begin
FOwner.Invalidate;
end;
procedure TImageGridItem.LoadFile;
//Determine file type and load accordingly
function GetImage(const Filename: String; B: TBitmap): Bool;
var
E: String;
IJ: TJpegImage;
IP: TPngObject;
begin
Result:= False;
if FileExists(Filename) then begin
E:= UpperCase(ExtractFileExt(Filename));
if E = '.BMP' then begin
B.LoadFromFile(Filename);
Result:= True;
end else
if (E = '.JPG') or (E = '.JPEG') then begin
IJ:= TJpegImage.Create;
try
IJ.LoadFromFile(Filename);
B.Assign(IJ);
Result:= True;
finally
IJ.Free;
end;
end else
if E = '.PNG' then begin
IP:= TPngObject.Create;
try
IP.LoadFromFile(Filename);
B.Assign(IP);
Result:= True;
finally
IP.Free;
end;
end else begin
raise Exception.Create('Invalid file extension ('+E+')');
end;
end;
end;
begin
GetImage(FFilename, FBmp);
end;
procedure TImageGridItem.SetFilename(const Value: TFilename);
begin
if Value <> FFilename then begin
FFilename := Value;
LoadFile;
Event;
end;
end;
end.
RISOLTO
Grazie alla risposta qui sotto, ho capito riparato. All'inizio pensavo che la formula fosse sbagliata, ma dopo aver esaminato più del mio codice, ho scoperto che in un altro punto, era in loop scorretto tra le righe e le colonne. Qui di seguito è come dovrebbe funzionare ...
for Y := 0 to RowCount - 1 do begin
for X := 0 to ColCount - 1 do begin
Ma quello che avevo prima era ...
for X := 0 to ColCount - 1 do begin
for Y := 0 to RowCount - 1 do begin
ne dite '(R * ColCount) + C'? –
E riguardo '(ARow * ColCount) + ACol'? @ Leneven, tu leggi la mia mente; eri più veloce, la risposta è tua :) – TLama
@TLama - Il mio segreto è fuori. Ora tutti sanno che non riesco a trovare una risposta io stesso :) –