|
Интерфейс
- создание удобных программ
|
||||
|
Главная
|
Программы
|
Исходники
|
Содержание
|
О себе
|
| Вопросы |
| Ответы |
О правилах хорошего тона в разработке интерфейса программ
Здесь, конечно
многое зависит от Ваших дизайнерских способностие и кто считает себя профи может
не читать дальше, а вот для тех, кто еще только или уже хоть что-то, это, думаю,
будет очень полезным. Ну во-первых, хороший интерфейс - это удобный интерфейс
и все рассуждения идут, в первую очередь, в пользу удобства использования программного
продукта. С хорошим интерфейсом будет та программа, которой легко пользоваться,
без особых напряжений, и легко научится пользоваться. Например, меня долго бесило
изменение положения объекта / обтекание текстом в 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-ом.
Написать в гостевую книгу