Интерфейс
- создание удобных программ
|
Главная
|
Программы
|
Исходники
|
Содержание
|
О себе
|
Вопросы |
Ответы |
О правилах хорошего тона в разработке интерфейса программ
Здесь, конечно
многое зависит от Ваших дизайнерских способностие и кто считает себя профи может
не читать дальше, а вот для тех, кто еще только или уже хоть что-то, это, думаю,
будет очень полезным. Ну во-первых, хороший интерфейс - это удобный интерфейс
и все рассуждения идут, в первую очередь, в пользу удобства использования программного
продукта. С хорошим интерфейсом будет та программа, которой легко пользоваться,
без особых напряжений, и легко научится пользоваться. Например, меня долго бесило
изменение положения объекта / обтекание текстом в Worde 2000, после 97-го. Приходилось
лишний раз нажимать на кнопку (дополнительно) и заново вглядываться в новое
окно. Но опять же, если у Вас все будет столкано на одно окно, где один элемент
на другом, и нет ни одной подписи, то лазийте в своей проге лучше сами.
Если в Вашей программе для получения какого-либо результата требуется совершить ряд действий,
то все элементы управления должны находится в одном окне, но они не должны быть
мелкими, чтобы не надо было в них метиться, и не должны быть крупными, чтобы
не гонять мышь по экрану. Если для нескольких действий требуется мало элементов
управления, то лучше их разместить в одном окне и "озаглавить" его соответствующим
образом.
В хорошей программе должно быть меню, откуда можно получить доступ
ко всем командам в программе. Оформление меню тоже должно быть логичным.
Когда
совсем нет необходимости использовать несколько копий программы одновременно,
то лучше перед загрузкой сделать проверку на наличие уже запущенной копии программы
и если уже есть, то завершить процесс загрузки и сделать активной существующую
копию, либо обратить каким-либо образом на нее внимание, либо, если она минимизирована,
то развернуть ее.
Если программа должна быть загружена долгое время, то будет
удобнее убрать кнопку приложения с панели задач (чтобы не мешалась) и поместить
иконку в TrayBar возле часиков.
Если программа работает с данными из файла или
их можно сохранять в файл и т.д., то перед закрытием приложения нужно спросить
о сохранение данных.
Если программа что-то показывает и при этом невозможен
ввод данных, то лучше на время показа отключить устройства ввода, а после показа
опять включить.
Если перед первым запуском программы требуется провести какие-либо
установки в системе, лучше оснастить продукт инсталятором, который бы все сделал
сам.
Программа должна содержать доступную для понимания помощь.
Если программа
долго выполняет какое-либо действие и при этом на экране ничего не происходит,
то необходимо поместить на форму индикатор, который показывал бы процесс выполнения
и сообщение с просьбой подождать пока длится процесс.
Цветовая гамма не должна
быть резкой и раздражительной. Раздражающие цвета следует применять только в
тех случаях, когда требуется обратить особое внимание. Чем приятней подбор цветов,
тем менее утомительна работа. Я не хочу говорить о таких окнах как у Winamp-а
и т.п. это конечно здорово, но и там бывают такие скины, что хочется плюнуть
да монитор жалко.
И в заключение, будет просто круто, если пользователь сможет
сам настраивать интерфейс под себя. И все настройки после этого сохранялись
и применялись бы.
Порядок, в котором обрабатываются события при загрузке формы
OnCreate, OnShow, OnPaint, OnActivate, OnResize, OnPaint.
Но это только основные, на самом деле при создании окна обрабатывается около двух сотен сообщений.
Как скрыть форму при старте приложения
Можно в обработчике событий OnCreate, OnShow, OnActivate вписать ShowWindow(Handle, SW_HIDE), но при это не избежать кратковременного мерцания окна.
Избавиться от этого можно, например, поместив окно где-нибудь за экраном:
Left := Screen.Width;
Затем скрыть окно и вернуть в обратное положение.
Как hint сделать многострочной
Напишем компоненту: unit MHint; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TMHint = class(TComponent) private ScreenSize: Integer; FActive: Boolean; FSeparator: Char; FOnShowHint: TShowHintEvent; procedure SetSeparator(Value: Char); { Private declarations } protected procedure SetActive (Value: Boolean); procedure NewHintInfo (var HintStr: String; var CanShow: Boolean; var HintInfo: THintInfo); { Protected declarations } public constructor Create (AOwner: TComponent); override; { Public declarations } published property Active: Boolean read FActive write SetActive; property Separator: Char read FSeparator write SetSeparator; { Published declarations } end; procedure Register; implementation procedure TMHint.SetActive(Value: Boolean); begin FActive := Value; end; procedure TMHint.NewHintInfo; var I: Byte; begin if FActive then begin I := Pos(FSeparator, HintStr); while I > 0 do begin HintStr[I] := #13; I := Pos(FSeparator, HintStr); end; if HintInfo.HintPos.y+10 > ScreenSize then HintInfo.HintPos.y := ScreenSize - 11; end; end; procedure Register; begin RegisterComponents('Samples', [TMHint]); end; constructor TMHint.Create(AOwner: TComponent); begin inherited Create(AOwner); FActive := True; FSeparator := '0'; Application.OnShowHint := NewHintInfo; ScreenSize := GetSystemMetrics(SM_CYSCREEN); end; procedure TMHint.SetSeparator(Value: Char); begin FSeparator := Value; end; end.
Системные сообщения (сокращения)
BM - ButtonMode (BM_) BN - Button (BN_) BS - ButtonStyle (BS_) CB - ComboBox (CB_) CBN - ComboBox Notification (CBN_) CBS - ComboBoxStyle (CBS_) EM - EditMessage (EM_) ES - EditStyle (ES_) FM - FileManager (FM_) LB - ListBox (LB_) LBN - ListBox Notification (LBN_) LBS - ListBoxStyle (LBS_) MB - MessgeButton (MB_) PS - PenStyle (PS_) SB - ScrollBar (SB_) SBS - ScrollBarStyle (SBS_) SM - SystemMetrics (SM_) SPI - SystemParametersInfo (SPI_) WM - WindowMessage (WM_) WS - WindowStyle (WS_)
uses ShlObj, ComObj, ActiveX; procedure CreateLink(const PathObj, PathLink, Desk, Param: string); var IObject: IUnknown; SLink: IShellLink; PFile: IPersistFile; begin IObject := CreateComObject(CLSID_ShellLink); SLink := IObject as IShellLink; PLink := IObject as IPersistFile; with SLink do begin SetArguments(PChar(Param)); SetDescription(PChar(Desk)); SetPath(PChar(PahtObj)); end; PFile.Save(PWChar(WideString(PathLink)), false); end;
Добавление программы в автозапузк
sProgTitle: название для программы; sCmdLine: имя EXE файла с путем доступа; bRunOnce: запускать только один раз или всегда при загрузке Windows; procedure RunOnStartup(sProgTitle, sCmdLine: string; bRunOnce: Boolean); var sKey: string; reg: TRegIniFile; begin if bRunOnce then sKey := 'Once'; else sKey := ''; reg := TRegIniFile.Create(''); reg.RootKey := HKEY_LOCAL_MACHINE; reg.WriteString('Software\Microsoft\Windows\CurrentVersion\Run' + sKey + #0, sProgTitle, sCmdLine); reg.Free; end;
События нажатия на системные кнопки формы (минимизация, закрытие ...)
В описание класса вставить: protected procedure WMGetSysCommand(var Message: TMessage); message WM_SYSCOMMAND; И собственно обработчик: procedure Tform1.WMGetSysCommand(var Message: TMessage); begin if Message.wParam = SC_MINIMIZE then ShowMessage('Окно минимизируется'); end;
Как поменять разрешение экрана
procedure ChangeDisplayResolution(x, y: Word); var dm: TDEVMODE; begin ZeroMemory(@dm, sizeof(TDEVMODE)); dm.dmSize := sizeof(TDEVMODE); dm.dmPelsWidth := x; dm.dmPelsHeight := y; dm.dmFields := DM_PELSWIDTH or DM_PELSHEIGHT; ChangeDisplaySettings(dm, 0); end; Работают только стандартные разрешения.
Изменение положения указателя мыши
Чтобы установить курсор мыши в какое-либо место экрана необходимо воспользоваться функцией SetCursorPos(x, y);
И собственно получение координат: var pos: TPoint; begin GetCursorPos(pos); x := pos.x; y := pos.y; end;
Как перетаскивать форму не только за Caption, но и за любое другое место
Первый способ: procedure TForm1.MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ReleaseCapture; perform(WM_SYSCOMMAND, $F012, 0); end; Второй способ: В описании класса нужно добавить: private procedure WMNCHitTest(var M: TWMNCHitTest); message WM_NCHITTEST; Ну и сам обработчик: procedure WMNCHitTest(var M: TWMNCHitTest); message WM_NCHITTEST; begin inherited; if M.Result = htClient then M.Result := htCaption; {смысл такой: если мышь сидит на окне, то пусть винда думает, что мышь на Caption Bar} end;
Как определить работает ли уже данное приложение или это его первая копия
Способ первый:
Идея такая: ищем в системе окно с таким же заголовком как у запускаемого приложения и ели такое окно есть то завершаем приложение.
procedure TForm1.FormCreate(Sender: TObject); var Wnd: THandle; buff: array[0..127] of Char; begin Wnd := GetWindow(Handle, GW_HWNDFIRST); while Wnd <> 0 do begin if (Wnd <> Application.Handle) and (GetWindow(Wnd, GW_OWNER) = 0) then begin GetWindowText(Wnd, Buff, SizeOf(Buff)); if StrPas(buff) = Application.Title then begin ShowMessage('Копия'); Halt(0); end; end; Wnd := GetWindow(Wnd, GW_HWNDNEXT); end; end; Способ второй (ИМХО лучший): var HM: THandle; function Check: boolean; begin HM := OpenMutex(MUTEX_ALL_ACCESS, false, 'MyOwnMutex'); Result := (HM <> 0); if HM = 0 then HM := CreateMutex(nil, false, 'MyOwnMutex'); end;
Заставить мигать кнопку приложения на панели задач можно используя функцию FlashWindow, если вызывать ее в таймере: procedure TForm1.Timer1Timer(Sender: TObject); begin FlashWindow(Application.Handle, true); end;
Как вставить ProgressBar в StatusBar
TForm1 = class(TForm) * * * ProgressBar1: TProgressBar; StatusBar1: TStatusBar; Timer1: TTimer; * * * procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean); * * * procedure TForm1.FormCreate(Sender: TObject); begin ProgressBar1.Parent := StatusBar1; ProgressBar1.Top := 2; ProgressBar1.Left := 152; ProgressBar1.Height := ProgressBar1.Height + 1; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if ProgressBar1.Position < 100 then ProgressBar1.Position := ProgressBar1.Position + 1 else ProgressBar1.Position := 0; end; procedure TForm1.FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean); begin ProgressBar1.Width := Form1.Width - 180; end;
Как выделить окошко DBGrid другим цветом
Идея простая: обрабатываем OnDrawCellData - рисуем в нужной ячейке залитый прямоугольники выводим текст. procedure TForm1.DBGridDrawCellDataCell(Sender: TObject; const Recr: TRect; Field: TField; State: TGridDrawState); begin if gdFocused in State then wiht (Sender as TDBGrid).Canvas do begin Brush.Color := Red; FillRect(Rect); TextOut(Rect.Left, Rect.Top, Field.Asstring); end; end;
Как использовать новую форму курсора
В OnCreate для формы: Button.Cursor := LoadCursor(hInstance, 'Curcor file name'); или можно попробовать вот так: var h : THandle; begin h := LoadImage(0,'C:\TheWall\Magic.ani', IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE or LR_LOADFROMFILE); if h = 0 then ShowMessage('Cursor not loaded') else begin Screen.Cursors[1] := h; Form1.Cursor := 1; end; end;
Как установить минимальные размеры окна
В описании класса: procedure WMGetMinMaxInfo(var Msg: TMessage); message WM_GETMINMAXINFO; И собственно обработчик: procedure WMGetMinMaxInfo(var Msg: TMessage); begin PMinMaxInfo(Msg.lParam)^.ptMinTrackSize.x := 600; PMinMaxInfo(Msg.lParam)^.ptMinTrackSize.y := 350; end;
Как заставить окно не разворачиваться из иконки
В описании класса: procedure WMQueryOpen(var Msg: TMessage); message WM_QUERYOPEN; И собственно обработчик: procedure WMQueryOpen(var Msg: TMessage); begin Msg.Result := 0; end;
Как получить горизонтальную прокрутку в ListBox
Посылаем сообщение и все готово: procedure TForm1.FormCreate(Sender: TObject); begin ListBox1.Perform(LB_SETHORIZONTALEXTENT, 1000{ширина прокрытки в пикселах}, LongInt(0)); end;
Как сделать так, что при нажатии на Enter происходил переход к следующему элементу формы
Свойство формы KeyPreview установить в true и обработать OnKeyPress: procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then begin Key :=#0; Perform(WM_NEXTDLGCTL, 0, 0); end; end;
Для начала в разделе Uses необходимо подключить модуль ShellAPI. В private области окна нужно вставить следующую строку: procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; //получение сообщений о переносе файла в окно приложения Процедура обработки этого сообщения будет выглядеть следующим образом: procedure TForm1.WMDropFiles(var Msg: TWMDropFiles); var CFileName: array[0..MAX_PATH] of Char; // переменная, хранящая имя файла begin try If DragQueryFile(Msg.Drop, 0, CFileName, MAX_PATH)>0 then // получение пути файла begin Form1.Caption:=CFileName; // имя файла в заголовок окна Memo1.Lines.LoadFromFile(CFileName); // открываем файл Msg.Result := 0; end; finally DragFinish(Msg.Drop); // отпустить файл end; end; Для того, чтобы форма знала, что может принимать такие файлы, необходимо в процедуре создания окна указать: procedure TForm1.FormCreate(Sender: TObject); begin DragAcceptFiles(Handle, True); end;
Как сделать свою кнопку в заголовке формы
Вот есть такой примерчик: //Непосредственно такой функции нет, но можно изловчиться. //Нарисовать там кнопку вручную и обрабатывать команды нажатия //мышки на Caption Bar. unit Unit1; interface uses Windows, Buttons, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) procedure FormResize (Sender: TObject); private CaptionBtn: TRect; procedure DrawCaptButton; procedure WMNCPaint (var Msg: TWMNCPaint); message WM_NCPaint; procedure WMNCActivate (var Msg: TWMNCActivate); message WM_NCActivate; procedure WMSetText (var Msg: TWMSetText); message Wm_SetText; procedure WMNCHitTest (var Msg: TWMNCHitTest); message WM_NCHitTest; procedure WMNCLButtonDown (var Msg: TWMNCLButtonDown); message WM_NCLButtonDown; { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation const htCaptionBtn = htSizeLast + 1; {$R *.DFM} procedure TForm1.DrawCaptButton; var xFrame, yFrame, xSize, ySize: Integer; R: Trect; begin //Dimensions of Sizeable Frame xFrame := GetSystemMetrics (SM_CXFrame); yFrame := GetSystemMetrics (SM_CYFrame); //Dimensions of Caption Buttons xSize := GetSystemMetrics (SM_CXSize); ySize := GetSystemMetrics (SM_CYSize); //Define the placement of the new caption button CaptionBtn := Bounds (Width - xFrame - 4 * xSize + 2, yFrame + 2, xSize - 2, ySize - 4); //Get the handle to canvas using Form's device context Canvas.Handle := GetWindowDC (Self.Handle); Canvas.Font.Name := 'Symbol'; Canvas.Font.Color := clBlue; Canvas.Font.Style := [fsBold]; Canvas.Pen.Color := clYellow; Canvas.Brush.Color := clBtnFace; try DrawButtonFace (Canvas, CaptionBtn, 1, bsAutoDetect, False, False, False); //Define a smaller drawing rectangle within the button R := Bounds (Width - xFrame - 4 * xSize + 2, yFrame + 3, xSize - 6, ySize - 7); with CaptionBtn do Canvas.TextRect (R, R.Left + 2, R.Top - 1, 'W'); finally ReleaseDC (Self.Handle, Canvas.Handle); Canvas.Handle := 0; end; end; procedure TForm1.WMNCPaint (var Msg: TWMNCPaint); begin inherited; DrawCaptButton; end; procedure TForm1.WMNCActivate (var Msg: TWMNCActivate); begin inherited; DrawCaptButton; end; procedure TForm1.WMSetText (var Msg: TWMSetText); begin inherited; DrawCaptButton; end; procedure TForm1.WMNCHitTest (var Msg: TWMNCHitTest); begin inherited; with Msg do if PtInRect (CaptionBtn, Point(xPos - Left, yPos - Top)) then Result := htCaptionBtn; end; procedure TForm1.WMNCLButtonDown (var Msg: TWMNCLButtonDown); begin inherited; if (Msg.HitTest = htCaptionBtn) then ShowMessage ('You hit the button on the caption bar'); end; procedure TForm1.FormResize (Sender: TObject); begin //Force a redraw of caption bar if form is resized Perform (WM_NCActivate, Word(Active), 0); end; end.
Как в программе переключить раскладку клавиатуры
Для переключения языка применяется вызов LoadKeyboardLayout: var russian, latin: HKL; begin russian := LoadKeyboardLayout('00000419', 0); latin := LoadKeyboardLayout('00000409', 0); end; -- -- -- -- -- где то в программе --- --- --- SetActiveKeyboardLayout(russian);
Включение / выключение устройств ввода из программы
Элементарно Ватсон: EnableHardwareInput(Enable: Boolean); //Enable - требуемое состояние: true - включены; false - выключены. Правда отключенное состояние можно снять Ctrl + Alt + Del-ом.
Написать в гостевую книгу