Форум: "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.008 c