Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Максимизированные окна MDI

Автор: delover
Дата сообщения: 10.04.2008 13:14
Данная бага присуща Visual Studio С++ и Delphi.
Я смотрел вопросы на эту тему в гугле. Нашёл кучу вопросов, но ответов-решений нет. На борде тож ничего на эту тему. По этому специальный топик.

Характеристика:
Глюк похож на двадцать пятый кадр. Приходится улавливать глазом рисование сцены объектов, которой в реальности мы не видели и не увидим, т.е. открыт канал в паралельный мир. При насыщеном перерисовками и выравниваниями скролбаров и сплитов IDE, начинает подташнивать.

Описание (шаги):
1. Так как я пользую Delphi, то пишу для про неё, но уважаемые мучители микросовтовского компилера, думаю, могут продублировать шаги у себя.
2. Создаём новый проект (кнопа New Items, категория Delphi Projects, иконка MDI Application).
3. Будет запрошен целевой каталог - делаем типа "Новая папка" (нам и этого хватит).
4. Запускаем...
-->
5. Теперь в запущеной проге создадим два или более новых MDI окна.
6. Максимизируем любое из них.
7. Жмем <Ctrl+Tab> окна нормально переключаются.
8. Идём в меню Window меняем окно - в результате мерцает глюк!!!!!!


При переключении этих окон в дизайнере Delphi, та же глюка, а вот при Ctrl+Tab её нет нигде. Были идеи посылать в главное окно комбинацию клавиш, пока не переключишся на нужное, но уже при пяти окнах пришлось отказаться - ещё хуже.

Какие вопросы всвязи с этим интересуют меня:
а. Может кто знает как с этим бороться или причины этого.
б. Может будут здоровые свежие идеи по этому поводу.
в. Я уже кое что сделал, но идея сильно не доработана. Много ситуаций когда меняется сценарий поведения VCL или система перестаёт понимать что произошло. Код я выложу немного позже, пока интереснее первые вопросы.
г. Ну и какую Вы хотели бы логику поведения окон, что для Вас было бы стандартным при ситуациях минимизации максимизации, переключениях и т.д. Ситуации я тоже отпишу попозжа.


=====


Заранее благодарен всем участникам.
Автор: WiseAlex
Дата сообщения: 10.04.2008 13:55
delover

Цитата:
Глюк похож на двадцать пятый кадр.

да глюк есть, но там не 25-ый кадр, а окно на которое переключаемся (или с которого), которое отрисовывается в обычном размере, а потом соображается, что нужно в максимайзд.
Как лечить - нет времени разбираться, но можно проследить все сообщения которые проходят по каркасу или отладить переключение по меню. Скорее всего это связано с активацией конкретного окна.
Автор: delover
Дата сообщения: 11.04.2008 08:41
WiseAlex

Цитата:
Скорее всего это связано с активацией конкретного окна.

Дело очень много сложнее, так как связано это именно с максимизацией окна. По умолчанию в поведении всех окон, MDI это или не MDI:

1. Максимизируемое окно всегда переводится на передний план! Это стандарт, так как тебе могут послать сообщение вообще из другого приложения, и будут ожидать что ты поведёшь себя правильно.
2. Если у тебя окно максимизировано, то переключаясь ты должен иметь впереди максимизированное окно. Значит при максимизации одного окна мы хотели бы максимизирувать остальные, но первое окно уже максимизируется, а остальные если мы начнём максимизировать, то вылезет вперёд последнее максимизированное.
3. Так как винда отслеживает WindowPlacement (инфа о нормальном состоянии при востановлении), то VCL обязана поддерживать эту штуку и реагирувать суутветственно, так что при активации следующего максимального - востанавливается предыдущее.


Цитата:
но можно проследить все сообщения которые проходят по каркасу

Во! Вот это не плохо было бы по каркасу или ещё как нибудь, так как у МДюх есть одно но - окна работают в отдельных потоках, по этому когда одно максимизируется а предыдущее востанавливается, то потоки и рисуют то, чего никогда нет.


Цитата:
Как лечить - нет времени разбираться

Жаль. Так как на вопрос который в инете у многих у сишников и пасквилянтов русскоязычного формата ответа нет, а возраст вопроса с бородой (в Delphi6 и CBuilder 5)... На такое думаю следовало бы уделить малость. Да и свою идею я пока не пишу, чтобы не направить сразу в, возможно, тупиковую ветку... Так надо же изобрести, много народу вздохнёт свободней. Ты у Adobы или Impacta подобное видел?
Автор: delover
Дата сообщения: 15.04.2008 10:03
Надо было тему в "Вопросы по Delphi" кидать. ((

Ладно. Короче что я делаю, и что делаю не так?

Идея следующая. Кодга окно максимизируется, то я устанавливаю размеры и положение окна, так чтобы они совпадали с клиентской областью. При активизации следующего окна, перерисовки и реалигны совпадают с той картиной которую мы увидим. Но конечно некоторый геморой - требуется запоминать истинные нормальные размеры. Востанавливать их когда надо. Реагировать на закрытие Main, так как используются rx-овские сторожи сохраняющие позицию в ini файле и TMS-овские "офисные" контролы. И т.д.

[more=Вот код]
Код: [no]
{*******************************************************}
{ Components of virtual value }
{ }
{ Project: sub-real.pin v1.1.2.24 }
{ }
{ "Company "AutoDealer" Ltd. sources }
{ Copyright (C) Roman Silin. All Rights Reserved. }
{ }
{ $Ver: 2006/05/17 08:07:02 Id: CHILDWIN.pas$ }
{*******************************************************}

unit CHILDWIN;

interface

uses Windows, Classes, Graphics, Forms, Controls, StdCtrls, ExtCtrls;

type
TMDIChild = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
FNormalPosition: TRect;
function IsMaximized(ChildBounds: TRect): Boolean;
function MaximizedChildren: Boolean;
protected
procedure Resizing(State: TWindowState); override;
public
function CloseQuery: Boolean; override;
end;

implementation

{$R *.dfm}

uses
Messages, SysUtils, Main, Types;

type
{$HINTS OFF}
TPeekAtCustomForm = class(TScrollingWinControl)
private
FActiveControl: TWinControl;
FFocusedControl: TWinControl;
FBorderIcons: TBorderIcons;
FBorderStyle: TFormBorderStyle;
FSizeChanging: Boolean;
FWindowState: TWindowState;
end;
{$HINTS ON}

var
MDINum: Integer = 1;

function TMDIChild.CloseQuery: Boolean;
var
Placement: TWindowPlacement;
begin
if (FormStyle = fsMDIChild) and
IsMaximized(BoundsRect) and not IsMaximized(FNormalPosition) and
(FNormalPosition.Left <> FNormalPosition.Right) and HandleAllocated then
begin
Placement.Length := SizeOf(Placement);
GetWindowPlacement(Handle, @Placement);
Placement.rcNormalPosition := FNormalPosition;
SetWindowPlacement(Handle, @Placement);
end;
Result := inherited CloseQuery;
end;

procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;

procedure TMDIChild.FormCreate(Sender: TObject);
begin
Name := Format('MDI_Child_%d',[MDINum]);
Caption := Format('MDI_Child_%d',[MDINum]);
Inc(MDINum);
end;

function TMDIChild.IsMaximized(ChildBounds: TRect): Boolean;
begin
Result := (ChildBounds.Left < 0) and (ChildBounds.Top < 0);
end;

function TMDIChild.MaximizedChildren: Boolean;
var
I: Integer;
begin
Result := False;
if not Assigned(Application.MainForm) then Exit;
with Application.MainForm do
for I := MDIChildCount - 1 to 0 do
if MDIChildren[I].WindowState = wsMaximized then
begin
Result := True;
Exit;
end;
end;

procedure TMDIChild.Resizing(State: TWindowState);

procedure MaximizeChildren;
var
I: Integer;
Childs: array of TMDIChild;
Rect: TRect;
begin
with Application.MainForm do
if Self <> ActiveMDIChild then Exit;
Rect := BoundsRect;
with Application.MainForm do
begin
SetLength(Childs, MDIChildCount);
for I := 0 to MDIChildCount - 1 do
Childs[I] := TMDIChild(MDIChildren[I]);
for I := 0 to Length(Childs) - 1 do
begin
if Self = Childs[I] then Continue;
Childs[I].BoundsRect := Rect;
end;
SetLength(Childs, 0);
end;
end;

procedure RestoreChildren(ForMinimize: Boolean);
var
I: Integer;
Childs: array of TMDIChild;
begin
with Application.MainForm do
begin
SetLength(Childs, MDIChildCount);
for I := 0 to MDIChildCount - 1 do
Childs[I] := TMDIChild(MDIChildren[I]);
for I := Length(Childs) - 1 downto 0 do
begin
if (Self = Childs[I]) and not Childs[I].Active then Continue;
with Childs[I].FNormalPosition do
if (Left = Right) or (Top = Bottom) then Continue;
if Childs[I].WindowState <> wsNormal then Continue;
if ForMinimize then
begin
TPeekAtCustomForm(Childs[I]).FWindowState := wsMaximized;
Childs[I].WindowState := wsNormal;
end;
Childs[I].BoundsRect := Childs[I].FNormalPosition;
with Childs[I].FNormalPosition do
TopLeft := BottomRight;
end;
SetLength(Childs, 0);
end;
end;

procedure SaveChildrenBounds;
var
I: Integer;
Childs: array of TMDIChild;
Rect: TRect;
Placement: TWindowPlacement;
begin
with Application.MainForm do
begin
SetLength(Childs, MDIChildCount);
for I := 0 to MDIChildCount - 1 do
Childs[I] := TMDIChild(MDIChildren[I]);
for I := Length(Childs) - 1 downto 0 do
begin
Placement.Length := SizeOf(Placement);
GetWindowPlacement(Childs[I].Handle, @Placement);
Rect := Placement.rcNormalPosition;
if not IsMaximized(Rect) then
Childs[I].FNormalPosition := Rect;
end;
SetLength(Childs, 0);
end;
end;

var
OldState: TWindowState;
OldRect, NewRect: TRect;
Child: TMDIChild;
begin
OldState := WindowState;
OldRect := BoundsRect;
if (State = wsNormal) and not IsMaximized(OldRect) then
FNormalPosition := OldRect;
if (OldState <> wsMaximized) and (State = wsMaximized) and
not MaximizedChildren then SaveChildrenBounds;
if Application.MainForm.MDIChildCount > 0 then
Child := TMDIChild(Application.MainForm.MDIChildren[0]) else
Child := nil;
if (OldState = wsMaximized) and (State <> wsMaximized) and
(Child = Self) and not Active and
(FNormalPosition.Left = FNormalPosition.Right) then
begin
FNormalPosition := Child.BoundsRect;
if Application.MainForm.MDIChildCount > 1 then
BoundsRect := Application.MainForm.MDIChildren[1].BoundsRect;
end;
inherited Resizing(State);
if (State <> wsMaximized) and Active then
begin
NewRect := BoundsRect;
if (IsMaximized(NewRect) or not IsMaximized(OldRect)) and
(Application.MainForm.MDIChildren[0] = Self) and
not MaximizedChildren then
RestoreChildren(False);
end;
if (OldState <> wsNormal) and (State = wsMinimized) and
not MaximizedChildren then RestoreChildren(True);
if (OldState <> wsMaximized) and (State = wsMaximized) then
MaximizeChildren;
end;

procedure TMDIChild.Timer1Timer(Sender: TObject);
var
I: Integer;
S: string;
begin
S := Format('%s(normal)',[Name]);
if MainForm.MDIChildCount > 1 then
if MainForm.MDIChildren[0].WindowState = wsMaximized then
S := Format('%s(max)',[Name]);
for I := 0 to MainForm.MDIChildCount - 1 do
if MainForm.MDIChildren[I] = Self then
begin
Panel1.Caption := Format('Child: %d; 1=%s', [I,S]);
end;
end;

end.[/no]
Автор: delover
Дата сообщения: 10.03.2010 11:53
Ага, нашёл. Изменения размеров окон ещё и зависят от следующего:

"Сообщение Cm_AppSysCommand посылается в ответ на сообщение Wm_SysCommand только в том случае, если посылающей формой не является основная форма, форма не минимизирована, командой является Sc_KeyMenu и клавиша отлична от пробела или дефиса. Другими словами, это сообщение посылается, когда пользователь нажимает клавишу прямого доступа к заголовку."

От себя добавлю, что мало что понял хотя читал несколько раз, и знаю чо почти до сих пор так. Т.е. лучше эти штуки дублировать в свои буленовские переменные, а дальше разгребать ситуёвину методом псевдонаучного тыка. Так как в одной оси у тебя так и будет, а в той же оси после использования ещё и других компонентов...
Автор: volser
Дата сообщения: 10.03.2010 12:45
delover
Ссылка
Автор: delover
Дата сообщения: 10.03.2010 18:59
volser
Сенкс. Там и с курсором пляски, так вот если бы с курсором больше нигде плясок не было, так можно сослаться на интуицию.
Документ сохраняю. Правильный шрифт. И моя уважуха.

Добавлено:
Сохраняя веб архив, шрифт сохраняется.

Страницы: 1

Предыдущая тема: Вопросы по Delphi (все версии) - часть 4


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.