Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2002.09.02;
Скачать: [xml.tar.bz2];

Вниз

Псевдо 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 вся ветка

Форум: "WinAPI";
Текущий архив: 2002.09.02;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.007 c
1-3450
Андрусь
2002-08-20 18:38
2002.09.02
нужно ввести число 10 в степени 1.8


1-3383
Lendl
2002-08-22 10:06
2002.09.02
Координаты X и Y текущего положения окна на экране?


14-3617
Fiend
2002-08-08 10:22
2002.09.02
рецепт спохмела


14-3602
Bboy
2002-08-07 15:19
2002.09.02
Очень нужна программа


1-3496
guts
2002-08-20 11:08
2002.09.02
Процедура написания даты прописью.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский