2010. július 29., csütörtök

Create columns of equal width in a TStringGrid


Problem/Question/Abstract:

How to create columns of equal width in a TStringGrid

Answer:

The main problem we encounter, it’s that width of any object is translated to screen pixels, thus - integer value. While we try to divide the TStringGrid columns to fit the grid client area, we might get a non-integer value and a fractional remainder. Therefore, in order to compensate for the insufficient gap we got (if the total columns width is less than the grid client area) or to compensate the exceeding gap (if the total columns width exceed the grid client area), we need to adjust one or more of the columns width.

procedure WidthEqually(AGrid: TStringGrid);
var
  I, GrdWidth: Integer;
  FinalWidth: Double;
  GoOn: Boolean;
begin
  with AGrid do
  begin
    {Avoiding StringGrid to be repainted }
    Perform(WM_SETREDRAW, 0, 0);
    if FAutoWidth then
      FAutoWidth := False;
    try
      GrdWidth := Width;
      {Taking into consideration our vertical scrollbar width, if any ...}
      if IsScrollBar(AGrid, WS_VSCROLL) then
        Dec(GrdWidth, GetSystemMetrics(SM_CXVSCROLL));
      {Here we subtract additional pixels for our GridLines width}
      FinalWidth := (GrdWidth / ColCount) - (ColCount * GridLineWidth);
      {The first sizing session}
      for I := 0 to ColCount - 1 do
      begin
        Application.ProcessMessages;
        ColWidths[I] := Trunc(FinalWidth);
      end;
      {Now we need to check where we ended. Either we are right on spot,
                        meaning columns could be divided equally to fit our FinalWidth.
                        If so, we should not have any horizontal scrollbar
      or a gap between our last columns to the grid edge.}
      GoOn := True;
      {If we exceeded our FinalWidth, we start reducing widths starting
                        from our last columns.}
      if IsScrollBar(AGrid, WS_HSCROLL) then
      begin
        while GoOn do
        begin
          Application.ProcessMessages;
          for I := ColCount - 1 downto 0 do
          begin
            Application.ProcessMessages;
            ColWidths[I] := ColWidths[I] - 1;
            {We are Ok now, time to leave...}
            if not IsScrollBar(AGrid, WS_HSCROLL) then
            begin
              GoOn := False;
              Break;
            end;
          end;
        end;
      end
      else
      begin
        {If we still have a gap, we increase our ColWidths}
        while GoOn do
        begin
          Application.ProcessMessages;
          for I := ColCount - 1 downto 0 do
          begin
            Application.ProcessMessages;
            ColWidths[I] := ColWidths[I] + 1;
            {We are Ok now, time to leave...}
            if IsScrollBar(AGrid, WS_HSCROLL) then
            begin
              {We resize this column back. We don't want any horizontal scrollbar.}
              ColWidths[I] := ColWidths[I] - 1;
              GoOn := False;
              Break;
            end;
          end;
        end;
      end;
    finally
      {Unlocking our grid and repainting}
      Perform(WM_SETREDRAW, 1, 0);
      Repaint;
    end;
  end;
end;

function IsScrollBar(AGrid: TStringGrid; nFlag: Cardinal): Boolean;
begin
  Result := (GetWindowLong(AGrid.Handle, GWL_STYLE) and nFlag) <> 0;
end;

Nincsenek megjegyzések:

Megjegyzés küldése