Delphi - TScrollBox выдает после X количество компонентов

Я заметил в одном из моих тестовых приложений после того, как я добавил так много TPanels в TScrollBox, я столкнулся с проблемой с теми, которые были прорисованы на определенное количество. Я отключаю поле прокрутки перед рисованием, и оно всегда очищается перед рисованием, чтобы не было проблем с относительным положением. Сначала я подумал, что, возможно, я столкнулся с какой-то максимальной высотой, чтобы рисовать. Итак, вы знаете, что расположение панелей по ширине сложено вертикально.

Поэтому я создал новый проект, чтобы попытаться выявить и решить проблему, и он выявил дополнительные детали проблемы. Когда я дома, я могу предоставить пример и видео, но пока опишу. Сделал форму с TScrollBox spinedit, чтобы указать, сколько панелей кнопка для создания панелей в цикле и кнопка для освобождения панелей и очистки массива для следующей попытки. Я устанавливаю подпись к номеру в цикле для идентификации.

Я попытался 2 способа укладки, чтобы увидеть, если бит имеет значение. Один из них состоит в том, чтобы установить позицию, умноженную на высоту, поэтому, если высота равна 200, тогда i * 202 дает ему пространство 2 пикселя. Новый способ, которым я пробовал, - использовать выравнивание верха. Это может иметь небольшую разницу в действии, но проблема в целом остается той же.

Новая проблема с диапазоном прокрутки. После завершения цикла и включения поля прокрутки прокрутка вниз до нижних упоров на последней пронумерованной панели. Но это неуместно, может быть, 199 прямо под 169 его 200 панелей. Затем полоса прокрутки регулирует диапазон, позволяя мне достичь дна только для того, чтобы увидеть следующую за последней панелью 198. Я считаю, что это происходит с использованием метода выравнивания по верху, как это никогда не происходило в моем приложении. Я буду проверять дальше.

Нижняя панель не остается в стороне. Я думаю, что решение этой проблемы - вручную вычислить и установить диапазон.

Основная проблема, которая возникает в моем приложении при установке положения вместо выравнивания верха, заключается в том, что после определенного количества панелей все они располагаются в конце в одном и том же месте. Перед определенным количеством его штраф, скажем, 50 или 100, но после стольких это случается. Я знаю, что 200 умножить на 200 - это довольно маленькое целое число, но, может быть, есть ограничение адреса

Я продолжу тестирование. Мне все еще нужно проверить, добавляет ли высота панели к нему. Но решил, что это должно быть известной проблемой. Delphi 2009, кстати.

1 ответ

Решение

Это ограничение Windows: размер оконного элемента управления не может превышать 65 535 пикселей.

См. Документацию к сообщению WM_SIZE, в котором ширина и высота передаются вместе в одном 32-битном параметре:

LPARAM

Слово младшего разряда lParam указывает новую ширину клиентской области.

Старшее слово lParam указывает новую высоту клиентской области.

Значения ширины и высоты ограничены 16 битами. То есть: когда SetWindowPos или похожий, который называется SetBounds, который вызывается установкой Top,

Впоследствии Top Значение элемента управления, которое может быть отрицательным, ограничено 15 битами и 1 знаковым битом, таким образом, +-32,767. Чтобы быть конкретным: это где Control.ClientOrigin.X/Y связан с. Например, при максимальном разрешении Top значение 32 167 для элемента управления, размещенного посередине экрана 1920x1200 пикселей.

Вот почему последние панели появляются в одном и том же месте в вашем поле прокрутки.

Обратите внимание, что это ограничение не распространяется на элементы управления VCL без дескриптора Windows.


Как решить?

Top свойство дочернего элемента управления в поле прокрутки относится к видимому клиенту; прокрутка полосы прокрутки сбрасывает Top свойства всех детей.

Так что (просто), прежде чем достигнуть магического предела, обманите Windows, прокрутив поле прокрутки:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  J: Integer;
  P: TPanel;
begin
  ScrollBox1.DisableAlign;
  try
    ScrollBox1.VertScrollBar.Range := 400 * 202; // 80,800 ! ;-)
    for I := 0 to 3 do
    begin
      ScrollBox1.VertScrollBar.Position := I * 100 * 202;
      for J := 0 to 99 do
      begin
        P := TPanel.Create(Self);
        P.SetBounds(0, J * 202, 100, 200);
        P.Align := alCustom;
        P.Caption := IntToStr(I * 100 + J);
        P.ParentBackground := False;
        P.Color := Random(clWhite);
        P.Parent := ScrollBox1;
      end;
    end;
  finally
    ScrollBox1.VertScrollBar.Position := 0;
    ScrollBox1.EnableAlign;
  end;
end;

Как решить это лучше?

Вместо TPanelTWinControl), используйте TControl производные для обхода вызовов API для SetWindowPos,


Как решить это лучше всего?

Используйте виртуальный подход, как TDBControlGrid показывает только несколько панелей, создавая впечатление, что их много.

Другие вопросы по тегам