Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.09.02;
Скачать: CL | DM;

Вниз

Псевдо MDI или как скрестить слона с мухой   Найти похожие ветки 

 
msts   (2002-07-01 07:20) [0]

Мастера, тут такой вопрос возник - что нужно изменить в TForm чтобы - приложение имея главную форму при создание дочерних окон помещала их в некую область (TPanel) внутри себя со стандартными возможностями минимизации, свертывания и т.п. этих окон иначе говоря MDI интерфейс но дочерние окна могут быть разных размеров
иметь свойство стайонтоп хидится по требованию и т.д. как в обычном режиме а область играть роль рабочего стола и НЕ иметь прокруток, так вот сделать это можно просто :

with TForm.Create(Self) do begin
Parent:=Panel1;
Show;
end;

но есть один косметический недостаток - при попадании фокуса в это окно, каптион не становится активным в отличие от MDIChild
и если нажать на окно то оно не всплывает на верхний уровень (Z order не меняется)
так что нужно перехватить чтоб исправить этот недочет?


 
Игорь Шевченко ©   (2002-07-01 11:49) [1]

А чем стандартное MDI не нравится ?
Как Scrollbar"ы убрать, я отвечал в основном форуме...

Можно и вашу идею реализовать, только зачем велосипед изобретать ?


 
SPeller ©   (2002-07-01 12:10) [2]

Вся проблема в том, что окна не получают сообщения WM_NCACTIVATE, которые и перекрашивают заголовок. Все остальные события приходят окнам нормально. Чтобы окна активизировались как обычно, нужно в OnMouseDown прописать ShowWindow. Ещё надо отловить тот же MouseDown на заголовке и сделать то же самое.

2 Игорь Шевченко © (01.07.02 11:49)
А чем стандартное MDI не нравится ?

А вдруг захочется иметь два поля с дочерними окнами, и не во всю высоту формы. Мало ли... :)


 
Игорь Шевченко ©   (2002-07-01 12:12) [3]

SPeller © (01.07.02 12:10)

Есть общеупотребительные концепции интерфейса...Зачем пугать пользователя ? Сделать-то можно все, что угодно, главный вопрос - зачем ?


 
msts   (2002-07-01 14:14) [4]

Удобство, все упирается в удобство :)
Чем удобен MDI интерфейс? группировкой окон и соответсвенно групповой их обработкой (свернуть, закрыть и т.д.)
чем неудобен сложностью доступа к конкретному окну (навигация), их идеологическое единообразие (все должны быть одного типа/поведения - повторяю "идеологическое единообразие" то что можно сделать в дельфе разные окна ниочем не говорит )
SDI - все наоборот шелл отображает список видимых окон - ненадо копаться в окнах/менюшках, окна могут быть разнообразными,
неудобства - замучеешься их закрывать, когда их слишком много - затрудняется навигация - недаром в XP появилась минимальная группировка окон - по его классу
XDI :) - главное окно содержит в себе полноценный рабочий стол для конкретного приложения (со списком окон внизу - линками к объектам на столе и глобальным меню сверху чего нехватает эксплореру - кнопочка старт неспасает - слишком тяжела в работе ), минусы - минимальны, плюсы от обоих идеологий
вот и самое прикольное сделать вполне можно только покопаться надо.
Это имеет смыс для больших приложений например корпоративная система автоматизации жизнидеятельности предприятия (где бухгалтерия от силы 15%) и из которой пользователю и вылазить не нужно но возможность такая должна быть

PS можно встроится в шелл но это резко увеличит сложность и исключит некоторые возможности системы, можно создовать рабочие столы (в потомках NT) но границы между ними непрозрачны и т.п


 
Игорь Шевченко ©   (2002-07-01 14:21) [5]

Что-то очень сложно замыслено, IMHO, нормальные коммерческие приложения придерживаются одной концепции в интерфейсе...


 
SPeller ©   (2002-07-01 14:43) [6]

У меня кстати получилось сэмулировать MDI, правда остались ещё небольшие косячки..


Unit1.pas
----------------------------------------------------------------------
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Controls, Forms,
Dialogs, unit2, ExtCtrls, StdCtrls;

type
TMyPanel=class(TPanel)
procedure CreateParams(var Par:TCreateParams);override;
end;

TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private

public
function ActiveChild:TForm;
end;

var
Form1: TForm1;
MyPanel:tmypanel;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
with tform2.Create(mypanel) do begin
Parent:=mypanel;
Show;
end;

end;

procedure TForm1.FormCreate(Sender: TObject);
var rc:longint;
begin
mypanel:=tmypanel.Create(self);
mypanel.Anchors:=panel1.Anchors;
mypanel.BevelInner:=panel1.BevelInner;
mypanel.BevelOuter:=panel1.BevelOuter;
mypanel.BevelWidth:=panel1.BevelWidth;
mypanel.BorderWidth:=panel1.BorderWidth;
mypanel.BorderStyle:=panel1.BorderStyle;
mypanel.Top:=panel1.Top;
mypanel.Left:=panel1.Left;
mypanel.Height:=panel1.Height;
mypanel.Width:=panel1.Width;
mypanel.Parent:=form1;
mypanel.Visible:=true;
mypanel.OnClick:=panel1.OnClick;
panel1.Visible:=false;
end;

procedure TMyPanel.CreateParams(var Par:TCreateParams);
begin
inherited;
par.ExStyle:=par.ExStyle or WS_EX_CONTROLPARENT;
end;

function TForm1.ActiveChild:TForm;
var i:integer;
begin
for i:=0 to mypanel.ControlCount-1 do
if (mypanel.Controls[i] is TForm2)and(mypanel.Controls[i].Tag=1) then begin
result:=tform2(mypanel.controls[i]);
break;
end;
end;

end.

----------------------------------------------------------------------


Unit2.pas
----------------------------------------------------------------------
unit Unit2;

interface

uses
Windows, Messages, SysUtils, Classes, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
procedure CreateParams(var Par:TCreateParams);override;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure WMNCLBUTTONDOWN(var Msg:TWMNCLBUTTONDOWN);message WM_NCLBUTTONDOWN;
procedure WMNCRBUTTONDOWN(var Msg:TWMNCRBUTTONDOWN);message WM_NCRBUTTONDOWN;
procedure WMNCMBUTTONDOWN(var Msg:TWMNCMBUTTONDOWN);message WM_NCMBUTTONDOWN;
procedure Edit1Enter(Sender: TObject);
private

public
procedure ReSetFocus;
end;

var
Form2: TForm2;

implementation
uses unit1;

{$R *.dfm}

procedure TForm2.CreateParams(var Par:TCreateParams);
begin
inherited;
par.Style:=par.Style or WS_CHILD or WS_OVERLAPPEDWINDOW and not WS_POPUP;
par.Width:=width;
par.Height:=height;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
action:=cafree;
end;

procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
resetfocus;
end;

procedure TForm2.WMNCLBUTTONDOWN(var Msg:TWMNCLBUTTONDOWN);
begin
resetfocus;
inherited;
end;

procedure TForm2.WMNCRBUTTONDOWN(var Msg:TWMNCRBUTTONDOWN);
begin
resetfocus;
inherited;
end;

procedure TForm2.WMNCMBUTTONDOWN(var Msg:TWMNCMBUTTONDOWN);
begin
ReSetFocus;
inherited;
end;

procedure TForm2.ReSetFocus;
begin
sendmessage(form1.activechild.Handle,WM_NCACTIVATE,0,0);
form1.activechild.Tag:=0;
sendmessage(Handle,WM_NCACTIVATE,1,0);
setwindowpos(Handle,hwnd_top,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW);
tag:=1;
end;

procedure TForm2.Edit1Enter(Sender: TObject);
begin
resetfocus;
end;

end.

----------------------------------------------------------------------

Пока один косяк - не удаётся поставить курсор в Edit в "неактивном" окошке. На кнопку нажать можно, а в Edit курсор поставить нельзя.
Немного вот это всё доработать, добавить таскбар и получится прями как в ХР :))


 
msts   (2002-07-01 20:08) [7]

re: Что-то очень сложно замыслено, IMHO, нормальные коммерческие приложения придерживаются одной концепции в интерфейсе...

в принципе верно но эти требования тоже не с потолка взялись программа работает и со временем накапливаются требования, они разнообразны и местами взаимоисключающие (например, пользователь: я хочу чтобы нажатимем мышки пререключится в конкретное окно - и - их слишком много открывается, невидно названий), если использовать дополнительные рабочие столы то в каждую его копию надо загружать сервистные проги, если в шелл добавлять тулбары - то для каждой копии делать надо свой, т.е. есть много вариантов и каждый из них по своему хорош/плох

Но не все потеряно - они уже шевелятся :) вот только
когда по ЛистВью кликаешь он всплывает на верх как форма :)если от этого избавится и протестировать на предмет всякbх шорткутов и актионов + добавить окошко переключения как при нажатии альт-таб и все готово :)


 
слон   (2002-07-02 06:46) [8]

2msts
2SPeller

все ваши извращения от незнания технологии MDI и особенностей
работы с этой технологией в Дельфях






 
SPeller ©   (2002-07-02 08:53) [9]

слон (02.07.02 06:46)

Ну какой вы умный, ну просто куда бы деться.... Хорошо я её не знаю, в общих чертах только. А раз вы такой умный, то предложи способ сделать подобное "по всем правилам технологии MDI". fsMDIChild установить согласно "особенностям работы в Дельфях" ??


 
Игорь Шевченко ©   (2002-07-02 09:42) [10]

msts (01.07.02 20:08)

Сделать можно все (почти). Вопрос такой - стоит ли потраченное время того выигрыша в удовлетворении потребностей пользователя ?
Пользователь - существо капризное и часто выражает в своих требованиях совсем не то, чего он хочет на самом деле. Я бы рекомендовал в разработке интерфейса придерживаться рекомендаций Microsoft (пардон), так как в этой фирме тратят очень большие деньги на исследования по usability. Об их концепциях неплохо написано в
http://msdn.microsoft.com/library/default.asp?URL=/library/partbook/winguide/welcome.htm

Также рекомендую www.usability.ru

С уважением,


 
msts   (2002-07-02 12:03) [11]

результат экспериментов -
куча мелких глюков но работает
использовать:
создайте проект
в нем три формы
подключите модуль UXDI.pas
унаследуйте
Form1(TXDIDesktop)
...
наложите компонентов
и вперед :)

UXDI.pas
part 1
___________________________________________________

//XDI 0.0.01.001а
//XDI - каждому приложению по рабочему столу!!!
//STS2002:COMSOFT
//sts@comsoft-corp.ru
//1.07.2002-2.07.2002

unit UXDI;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;

type

TXDIDesktop = class; //Главная форма - содержит в себе рабочий стол,
//унаследуйте от нее MainForm приложения
TXDIForm = class; //Базовая форма для внутреннего рабочего стола
//от нее наследуются все другие формы
TXDIDesktopForm = class; //Форма - содержимое рабочего стола, может быть
//только одна в главной форме
//дизайнтайме настройте содержимое например ListView
//находится всегда внизу


TXDIDesktop = class(TForm)
private
FDefXDIProc : TFarProc;
FXDIInstance : TFarProc;
FXDIHandle : HWND;
FXDIDesktop : TXDIDesktopForm;
protected
procedure CreateWnd; override;
procedure XDIWndProc(var Message: TMessage);
procedure AlignControls(AControl: TControl; var Rect: TRect); override;
public
procedure ProcessXDIMsg(SMSG : string; Message: TMessage); virtual;
property XDIHandle : HWND read FXDIHandle;
property XDIDesktop : TXDIDesktopForm read FXDIDesktop;
end;

TXDIForm = class(TForm)
private
FXDIDesktop : TXDIDesktop;
protected
procedure WndProc(var Message: TMessage); override;
procedure CreateWindowHandle(const Params: TCreateParams); override;
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner: TComponent); override;
procedure ProcessXDIMsg(SMSG : string; Message: TMessage); virtual;
end;

TXDIDesktopForm = class(TXDIForm)
protected
procedure WndProc(var Message: TMessage); override;
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner: TComponent); override;
end;

implementation

{ TXDIDesktop }

procedure TXDIDesktop.CreateWnd;
var
XDICreateStruct: TClientCreateStruct;
begin
inherited CreateWnd;
if not (csDesigning in ComponentState) then begin
with XDICreateStruct do
begin
idFirstChild := $FF00;
hWindowMenu := 0;
end;
FXDIHandle := Windows.CreateWindowEx(WS_EX_CLIENTEDGE, "MDICLIENT",
nil, WS_CHILD or WS_VISIBLE or WS_GROUP or WS_TABSTOP or
WS_CLIPCHILDREN or WS_CLIPSIBLINGS or MDIS_ALLCHILDSTYLES,
0, 0, ClientWidth, ClientHeight, Handle, 0, HInstance, @XDICreateStruct);
FXDIInstance := Classes.MakeObjectInstance(XDIWndProc);
FDefXDIProc := Pointer(GetWindowLong(FXDIHandle, GWL_WNDPROC));
SetWindowLong(FXDIHandle, GWL_WNDPROC, Longint(FXDIInstance));
end;
end;

procedure TXDIDesktop.XDIWndProc(var Message: TMessage);

procedure Default;
begin
with Message do
Result := CallWindowProc(FDefXDIProc, FXDIHandle, Msg, wParam, lParam);
end;

var
DC: HDC;
PS: TPaintStruct;
begin
with Message do
case Msg of
WM_NCHITTEST:
begin
Default;
if Result = HTCLIENT then Result := HTTRANSPARENT;
end;
WM_ERASEBKGND:
begin
FillRect(TWMEraseBkGnd(Message).DC, ClientRect, Brush.Handle);
Result := 1;
end;
$3F://!
begin
ProcessXDIMsg("$3F",Message);
Default;
// if FFormStyle = fsMDIForm then
// ShowMDIXDIEdge(FXDIHandle, (MDIChildCount = 0) or
// not MaximizedChildren} true );

ProcessXDIMsg("->",Message);
end;
WM_PAINT:
begin
ProcessXDIMsg("WM_PAINT",Message);
DC := TWMPaint(Message).DC;
if DC = 0 then TWMPaint(Message).DC := BeginPaint(FXDIHandle, PS);
try
PaintHandler(TWMPaint(Message));
finally
if DC = 0 then EndPaint(FXDIHandle, PS);
end;
ProcessXDIMsg("->",Message);
end;
else
ProcessXDIMsg("Default",Message);
Default;
ProcessXDIMsg("->",Message);
end;
end;




 
msts   (2002-07-02 12:05) [12]

part2
_________________________

procedure TXDIDesktop.AlignControls(AControl: TControl; var Rect: TRect);
var
LRect: TRect;
begin
inherited;
if FXDIHandle <> 0 then begin
with Rect do
SetWindowPos(FXDIHandle, HWND_BOTTOM, Left, Top, Right - Left,
Bottom - Top, SWP_NOZORDER + SWP_NOACTIVATE);

if Assigned(FXDIDesktop) then begin
if Windows.GetClientRect(FXDIHandle, LRect) then
with LRect do
SetWindowPos(FXDIDesktop.Handle, HWND_BOTTOM, Left, Top, Right - Left,
Bottom - Top, SWP_NOZORDER + SWP_NOACTIVATE);
end;

end;
end;

procedure TXDIDesktop.ProcessXDIMsg(SMSG : string; Message: TMessage);
begin
//
end;

{ TXDIForm }

procedure TXDIForm.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.WindowClass.lpfnWndProc := @DefMDIChildProc;
end;

procedure TXDIForm.CreateWindowHandle(const Params: TCreateParams);
var
CreateStruct: TMDICreateStruct;
NewParams: TCreateParams;
begin
with CreateStruct do
begin
szClass := Params.WinClassName;
szTitle := Params.Caption;
hOwner := HInstance;
X := Params.X;
Y := Params.Y;
cX := Params.Width;
cY := Params.Height;
style := Params.Style;
lParam := Longint(Params.Param);
end;
WindowHandle := SendMessage(TXDIDesktop(Application.MainForm).XDIHandle,
WM_MDICREATE, 0, Longint(@CreateStruct));
SetWindowPos(WindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE + SWP_NOSIZE);
end;



procedure TXDIForm.WndProc(var Message: TMessage);
begin
ProcessXDIMsg("default",Message);
inherited WndProc(Message);
ProcessXDIMsg("->",Message);
end;

procedure TXDIForm.ProcessXDIMsg(SMSG: string; Message: TMessage);
begin
//
end;

constructor TXDIForm.Create(AOwner: TComponent);
begin
if not Assigned(Application.MainForm) then
if not (Application.MainForm is TXDIDesktop) then
raise Exception.Create("Все не так и все не то...");
inherited Create(AOwner);
FXDIDesktop := TXDIDesktop(Application.MainForm);
end;

{ TXDIDesktopForm }

constructor TXDIDesktopForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if Assigned(FXDIDesktop.FXDIDesktop) then
raise Exception.Create("TXDIDesktopForm уже есть");
FXDIDesktop.FXDIDesktop := Self;
end;

procedure TXDIDesktopForm.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style and not(WS_CAPTION or WS_BORDER or WS_THICKFRAME);
end;

procedure TXDIDesktopForm.WndProc(var Message: TMessage);
begin
if (Message.Msg=WM_WINDOWPOSCHANGING) then PWindowPos(Message.LParam).flags:=PWindowPos(Message.LParam).flags or SWP_NOZORDER;
inherited WndProc(Message);

end;

end.


 
msts   (2002-07-02 12:12) [13]

PS: написано под 6 дельфу, если че...


 
SPeller ©   (2002-07-03 03:53) [14]

Писать на готовом не интересно. Вот самому всю эту систему примдумать и красиво реализовать - это другое дело..



Страницы: 1 вся ветка

Текущий архив: 2002.09.02;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.02 c
4-3657
Новенький в Делфи
2002-06-29 23:39
2002.09.02
как лучше использовать dll?


8-3528
Ptushenko Denis
2002-04-25 10:46
2002.09.02
Шрифты


1-3353
Ahmad
2002-08-19 13:03
2002.09.02
Файлы в DLL, миф или реальность?


1-3513
maxim2
2002-08-20 12:34
2002.09.02
Как отловить нажатие правой кнопки мыши


14-3573
Posny
2002-08-06 08:32
2002.09.02
RXLib275 D6