Вывожу список видео канала ютуба. Для каждого видео создаётся отдельный экземппяр TFrame. Если вывести много таких видео, то в какой-то момент некоторые элементы фрейма начинают уезжать вверх.
Так а как они создаются, может с высотой/позицией что-то не так?
Картинки лучше на форум загружать (например, Ctrl+V если она в буфере, или перетащить файл в область редактора), чтобы не смотреть на кучу рекламы (даже через юблок один баннер пробился ) и чтобы внезапно не пропали.
Весь фрейм создаётся в дизайн-тайме. Потом при парсинге JSON’ов создаётся динамический массив таких фреймов. При создании происходит первый ресайз, чтобы подтянуть размер фрейма под форму. Потом при ресайзе формы, ресайзятся все фреймы. Но там всё ресайзится только в ширину. Позиция компонентов по высоте не теребонькается.
Всем проще, пара кликов мышки и не нужен весь этот сложный код.
Вот сделал сейчас в Лазарусе за 20 минут, всё работает и не сбивается.
Во фрейме добавить anchor Right у прогрессбара, у кнопки поменять Left на Right.
На форме все стороны у пейджконтрола, и все кроме Left у групбокса справа.
На вкладку кинул скролбокс с align Client, и добавлять фреймы с align Top.
{$mode delphi}{$H+}
uses ..., myframe, Generics.Collections;
...
var
frames: TList<TFrame1>;
procedure TForm1.FormCreate(Sender: TObject);
begin
frames := TList<TFrame1>.Create;
end;
procedure TForm1.btnAppendClick(Sender: TObject);
var
frame: TFrame1;
lastPos: integer;
begin
frame := TFrame1.Create(Self);
frame.Name := 'myframe' + IntToStr(frames.Count);
frame.Parent := ScrollBox1;
frame.Align := alTop;
if frames.Count mod 2 = 0 then frame.Color:= clCream else frame.Color := clSkyBlue;
lastPos := 0;
if (frames.Count > 0) then
begin
lastPos := frames[frames.Count - 1].Top + frames[frames.Count - 1].Height;
end;
frame.Top := lastPos;
frames.Add(frame);
end;
Кстати, при отладке подобных проблем бывает помогает задать цвет фона у элементов. Например, разный для четных/нечетных. Чтобы понять что на что залезает и т.п.
И выводить куда-нибудь позиции (например, OutputDebugString и смотреть View —> Debug Windows —> Event Log).
Вы показали только 5 фреймов. И что вы этим доказали? У меня при пяти фреймах тоже всё работает. А вот создайте фреймов столько же, сколько у меня (примерно 60-70), отключите автовыравнивание и т.д. и вот тогда посмотрим, что будет.
Не выйдет. У меня фрейм можно двигать влево-вправо. Он шире, чем его видимая область.
Не понял, чем именно это поможет? В моём случае ведь и так понятно, что улетает кнопка и прогрессбар. Но почему именно они и почему это происходит, начиная только примерно с 60-го фрейма?
Естественно. Фреймы тоже зло, делфи тем более, и вообще программирование зло еще то) А если серьезно стараюсь с фреймами не работать из-за их глючности, особенно при наследовании. А если уж деваться некуда, то вообще на них не дышать и обращаться как с предметами искусства из тончайшего хрусталя )
Из стандартных DrawGrid c этим справится. В OnDrawCell прорисовывать картинки с текстом и кнопку. Кнопку не создавать, а именно прорисовывать и ловить на этом месте клик в ячейке грида
У меня фрейм может скроллиться. По-этому, такие штуки не прокатят. Точнее, прокатят, но придётся сильно извращаться. Тогда уж эту GUI’ню проще на WinAPI написать.
Параметра из сообщения винапи, которое передается каким-то из контролов-оберток над винапи. То есть Top фреймов нужны для вычисления позиций и вызова функций винапи.
Забавно, что Лазарус на Линуксе эмулирует это.
See the documentation on the WM_SIZE message wherein width and height are passed together in a single 32 bit parameter:
…
So width and height values are limited to 16 bits. That is: when SetWindowPos or alike is involved, which is called by SetBounds , which is called by setting Top .
Subsequently, the Top value of a control, which can be negative, is limited to 15 bits and 1 sign bit, thus ±32,767. To be specific: that is where Control.ClientOrigin.X/Y is bound by. E.g. thus resolving in a maximum Top value of 32,167 for a control placed in the middle of a 1920x1200 pixel screen.
So this is why the last panels appear on the same spot within your scroll box.
Note that this limitation does not apply to VCL controls without Windows handle.
Там по ссылке вроде есть какое-то костыльное решение в первом куске кода, может поможет.
Да, в вкл/винформс сложно с этим, поэтому я там стараюсь ограничиваться стандартным поведением.
WPF/Qt/QML/JavaFX/HTML хороши для такого. Может быть FireMonkey в новых Дельфи, не пробовал.
В данном случае было бы видно, что сбивается Top после 32к.
UPD: хотя не, скорее всего только при создании сообщений для винапи.
В общем
Тогда ваш эксперимент не имеет смысла. Тут смысл в том, чтобы вымутить из-за чего оно сбивается, если не влиять на их позицию.
Костыльное решеие и так известно. Если при ресайзе самому выставлять им Top, то всё работает. Правда, не пробовал создавать овер дофига фреймов. Но в пределах 120 точно работает.
Попробую вывести куда-нибудь их количество и позицию.
Дык при выравнивании тоже вычисляется позиция аналогично, просто самому не надо этот код писать )
- frame.Align := alTop;
+ frame.Top := 33000;
та же ошибка в TWinControl.SendMoveSizeMessages
{-------------------------------------------------------------------------------
Send Move and Size messages through the LCL message paths. This simulates the
VCL behaviour and has no real effect.
-------------------------------------------------------------------------------}
procedure TWinControl.SendMoveSizeMessages(SizeChanged, PosChanged: boolean);
begin
...
if PosChanged then
begin
with MoveMsg do
begin
Msg:= LM_MOVE;
MoveType:= 1;
if (FLeft < Low(Smallint)) or (FLeft > High(Smallint))
or (FTop < Low(Smallint)) or (FTop > High(Smallint)) then
raise Exception.CreateFmt('Position range overflow in %s.SendMoveSizeMessages:'
+' Left=%d, Top=%d.', [Name, FLeft, FTop]);
XPos := FLeft;
YPos := FTop;
...
end;
WindowProc(TLMessage(MoveMsg));