Можно ли уменьшить потребляемые компонентами tnotebook и ttabbednotebook ресурсы

Содержание

500+ FAQ по Delphi

Перейти на: Главную | Индексную | Предыдущую | Следующую страницу

Узин проекты деревянных домов деревянный дом
Как сделать прямоугольник для выделения части картинки для редактирования?

Самый простой способ — воспользоваться функцией Windows API DrawFocusRect. Функция DrawFocusRect использует операцию XOR при рисовании — таким образом вывод прямоугольника дважды с одними и теми же координатами стирает прямоугольник, и прямоугольник всегда будет виден, на фоне какого бы цвета он не выводился.
Пример:

type
TForm1 = class(TForm)
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private

Capturing : bool;
Captured : bool;
StartPlace : TPoint;
EndPlace : TPoint;
public

end;

var
Form1: TForm1;

function MakeRect(Pt1 : TPoint; Pt2 : TPoint) : TRect;
begin
if pt1.x Можно ли использовать иконку как картинку на кнопке TSpeedButton?

Можно.
uses ShellApi;

procedure TForm1.FormShow(Sender: TObject);
var
Icon: TIcon;
begin
Icon := TIcon.Create;
Icon.Handle := ExtractIcon(0,’C:\WINDOWS\NOTEPAD.EXE’,1);
SpeedButton1.Glyph.W > SpeedButton1.Glyph.Height := Icon.Height;
SpeedButton1.Glyph.Canvas.Draw(0, 0, Icon);
Icon.Free;
end;
Как поместить прозрачную фоновую каринку на компонент CoolBar?

procedure TForm1.Button1Click(Sender: TObject);
var
Bm1 : TBitmap;
Bm2 : TBitmap;
begin
Bm1 := TBitmap.Create;
Bm2 := TBitmap.Create;
Bm1.LoadFromFile(‘c:\download\test.bmp’);
Bm2.W > Bm2.Height := Bm1.Height;
bm2.Canvas.Brush.Color := CoolBar1.Color;
bm2.Canvas.BrushCopy(Rect(0, 0, bm2.Width, bm2.Height), Bm1,
Rect(0, 0, Bm1.width, Bm1.Height), ClWhite);
bm1.Free;
CoolBar1.Bitmap.Assign(bm2);
bm2.Free;
end;
Ползунок компонента TScrollBar все время мигает. Как это отключить?

Установите свойтсво ScrollBar.TabStop в False.
Как программно перевести DBgrid в режим редактирования и установить курсор в окошке редактирования в требуемую позицию?

Переведите таблицу в режим редактирования, затем получите дескриптор (handle) окна редактирования и перешлите ей сообщение EM_SETSEL. В качестве параметров вы должны переслать начальную позицию курсора, и конечную позицию, определяющую конец выделения текста цветом. В приведенном примере курсор помещается во вторую позицию, текст внутри ячейки не выделяется.

procedure TForm1.Button1Click(Sender: TObject);
var
h : THandle;
begin
Application.ProcessMessages;
DbGrid1.SetFocus;
DbGr > Application.ProcessMessages;
h:= Windows.GetFocus;
SendMessage(h, EM_SETSEL, 2, 2);
end;
Как поместить курсор в определенную позицию edit’а и подобных ему элементов управления?

Можно использовать методы Delphi SelStart() и SelectLength().
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.SetFocus;
<переводим курсор во вторую позицию>
Edit1.SelStart := 2;
<не выделяем никакого текста>
Edit1.SelLength := 0;
end;
Как среагировать на минимизацию-максимизацию формы перед тем как произойдет изменение размера формы?

В примере перехватывается сообщение WM_SYSCOMMAND. Если это сообщение говорит о
минимизации или максимизации формы — пищит динамик.

type
TForm1 = class(TForm)
private

procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
public

end;

var
Form1: TForm1;

procedure TForm1.WMSysCommand;
begin
if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0)
else
inherited;
end;
Можно ли сделать так — одна форма показывает другую и остается позади нее, но фокус ввода не переходит к новой форме, а остается у старой?

В примере показывается не автосоздаваемая (non auto-created) форма, но фокус ввода ей
не передается.

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Application);
Form2.Visible := FALSE;
ShowWindow(Form2.Handle, SW_SHOWNA);
end;
На некоторых laptop компьютерах может не быть флоппи дисковода. Можно ли удалять из списка TDriveComboBox диски которые отключены?

В примере TDriveComboBox не показывает дисководы, которые не готовы. (not ready).
Учтите что на многих компьютерах будет ощутимая задержка при поверке plug&play
флоппи дисковода.

procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
OldErrorMode : Word;
OldDirectory : string;
begin
OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
GetDir(0, OldDirectory);
i := 0;
while i 0 then
DriveComboBox1.Items.Delete(i)
else
inc(i);
end;
ChDir(OldDirectory);
SetErrorMode(OldErrorMode);
end;
Как сообщить всем формам моего приложения (в том числе и не видимым в данный момент) об изминении каких-то глобальных значений?

Один из способов — создать пользовательское сообщение и использовать метод preform
чтобы разослать его всем формам из массива Screen.Forms.

const
UM_MyGlobalMessage = WM_USER + 1;

type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private

procedure UMMyGlobalMessage(var AMessage: TMessage); message
UM_MyGlobalMessage;
public

end;

var
Form1: TForm1;

procedure TForm1.FormShow(Sender: TObject);
begin
Form2.Show;
end;

procedure TForm1.UMMyGlobalMessage(var AMessage: TMessage);
begin
Label1.Left := AMessage.WParam;
Label1.Top := AMessage.LParam;
Form1.Caption := ‘Got It!’;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
f: integer;
begin
for f := 0 to Screen.FormCount — 1 do
Screen.Forms[f].Perform(UM_MyGlobalMessage, 42, 42);
end;

const
UM_MyGlobalMessage = WM_USER + 1;
type
TForm2 = class(TForm)
Label1: TLabel;
private

procedure UMMyGlobalMessage(var AMessage: TMessage);
message UM_MyGlobalMessage;
public

end;

var
Form2: TForm2;

procedure TForm2.UMMyGlobalMessage(var AMessage: TMessage);
begin
Label1.Left := AMessage.WParam;
Label1.Top := AMessage.LParam;
Form2.Caption := ‘Got It!’;
end;
Как обновить список дисков компонента TDriveComboBox, учитывая, что могут быть подключены/отключены сетевые диски и произведена «горячая замена» plug&play дисков?

Следующий пример вызывает защищенный (protected) метод класса TDriveComboBox
BuildList() для регеирации списка дисков. (использовая так наз. «class cracer»)

type
TNewDriveComboBox = class(TDriveComboBox) //это наш «class cracer»
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Drive : char;
begin
Drive := DriveComboBox1.Drive;
TNewDriveComboBox(DriveComboBox1).BuildList;
//вызываем защищенный метод родительского класса
DriveComboBox1.Drive := Drive;
end;
Как программно заставить выпасть меню?

В примере показано как показать меню и выбрать в нем какой-то пункт, эмулируя нажатие «быстрой кдавиши» пункта меню. Если у Вашего пункта меню нет «быстрой клавиши» Вы можете посылать комбинации VK_MENU, VK_LEFT, VK_DOWN, и VK_RETURN, чтобы программно «путешествовать» по меню.
Пример:

procedure TForm1.Button1Click(Sender: TObject);
begin
//Allow button to finish painting in response to the click
Application.ProcessMessages;

keybd_Event(VK_MENU, 0, 0, 0);

keybd_Event(ord(‘F’), 0, 0, 0);

keybd_Event(ord(‘F’), 0, KEYEVENTF_KEYUP, 0);

keybd_Event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);

keybd_Event(ord(‘S’), 0, 0, 0);

keybd_Event(ord(‘S’), 0, KEYEVENTF_KEYUP, 0);
end;
Как сделать клавишу-акселератор (keyboard shortcut) компонету у которого нет заголовка?

Возможный вариант — присвоить ссылку на этот компонент свойству FocusControl TLabel’а. В примере используется невидимый Label для создания «быстрой» клавиши (Alt+M) компонента Memo. Чтобы использовать пример, разместите на форме компонет TMemo, Label и несколько других компонентов, которые могут принимать фокус ввода. Запустите программу, перевидите фокус ввода куда-нибудь вне Memo и нажмите Alt+M — фокус ввода вернется в Memo.
Пример:

procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Visible := false;
Label1.Caption := ‘&M’;
Label1.FocusControl := Memo1;
end;
Можно ли как-то уменьшить мерцание при перерисовке компонента?

Если добавить флаг csOpaque (непрозрачный) к свойству ControlStyle компонента
— то фон компонента перерисовываться не будет.

constructor TMyControl.Create;
begin
inherited;
ControlStyle := ControlStyle + [csOpaque];
end;
Как запретить изменение размера моего компонента в design-time?

Поместите в конструктор компонента код, устанавливающий размеры по умолчанию.
Переопределите метод SetBounds и проверяйте в нем «componentstate». Если компонет
находится режиме «design-time» (csDesigning in ComponentState) просто передавайте
значения ширины и высоты (width и heights) компонента по умолчанию (в нашем
примере 50) методу класса-предка.

procedure TVu.SetBounds(ALeft : integer; ATop : integer; AWidth : integer;
AHeight : integer);
begin
if csdesigning in componentstate then
begin
AW > AHeight := 50;
inherited; //вызываем унаследованный от предка метод
end;
end;
Можно ли уменьшить потребляемые компонентами TNotebook и TTabbedNotebook ресурсы?

Да. Можно уничтожать обьекты, расположенные не на текущей странице TNotebook или
TTabbedNotebook. В примере вызывается защищенный (Protected) метод путем создания
так называемый «class cracer’ов».

type TMyTabbedNotebook = class(TTabbedNotebook); //это наш «class cracer»
type TMyNotebook = class(TNotebook);

Delphi-Help

Многостраничные панели — компоненты TabControl, PageControl, TabSet, TabbedNoteBook, NoteBook

  • размер шрифта уменьшить размер шрифтаувеличить размер шрифта
  • Печать

Многостраничные панели — компоненты TabControl, PageControl, TabSet, TabbedNoteBook, NoteBook

Многостраничные панели позволяют экономить пространство окна приложения, размещая на одном и том же месте страницы разного содержания. На рис.1 показаны различные формы отображения многостраничного компонента PageControl. Начнем рассмотрение многостраничных панелей именно с этого компонента.

Рис.1

Иллюстрация различных вариантов панели PageControl

Перенесите компонент PageControl на форму. Чтобы задавать и редактировать страницы этого компонента, надо щелкнуть на нем правой кнопкой мыши. Во всплывшем меню вы можете видеть команды: New Page — создать новую страницу, Next Page — переключиться на следующую страницу, Previous Page — переключиться на предыдущую страницу.

Каждая создаваемая вами страница является объектом типа TTabSheet. Это панель, на которой можно размещать любые управляющие компоненты, окна редактирования и т.п. После того, как вы создадите несколько страниц, выделите одну из них, щелкнув в ее середине, и посмотрите ее свойства в Инспекторе Объектов. Страница имеет следующие основные свойства:

  • Name Имя, по которому можно ссылаться на страницу
  • Caption Надпись, которая появляется на ярлычке закладки
  • PageIndex Индекс страницы, по которому можно ссылаться на страницу
  • ImageIndex Индекс изображения, которое может появляться на ярлычке закладки

Из общих свойств компонента PageControl можно отметить:

  • Style Определяет стиль отображения компонента: tsTabs — закладки (верхние компоненты на рис.1), tsButtons — кнопки (левый нижний компонент на рис.1), tsFlatButtons — плоские кнопки (правый нижний компонент на рис.1)
  • MultiLine Определяет, будут ли закладки размещаться в несколько рядов, если все они не помещаются в один ряд (на рис. 1вверху два одинаковых компонента, но в левом MultiLine = false, а в правом — true; примером компонента с MultiLine = false является также знакомая вам палитра компонентов в Delphi)
  • TabPosition Определяет место расположения ярлычков закладок: tpBottom — внизу, tpLeft — слева, tpRight — справа и tpTop — вверху компонента (это значение по умолчанию и именно оно задано в примерах рис.1)
  • TabHeight и TabWidth Высота и ширина ярлычков закладок в пикселях. Если значения этих параметров заданы равными 0, то размеры ярлычков определяются автоматически по размерам надписей на них
  • Images Ссылка на компонент ImageList (см. раздел 9.3), который содержит список изображений на ярлычках. Свойства ImageIndex страниц содержат индексы, соответствующие именно этому списку
  • ScrollOpposite Определят способ перемещения закладок при размещении их в несколько рядов (опробуйте экспериментально, как это свойство влияет на поведение компонента)
  • ActivePage Имя активной страницы
  • Pages[Index: Integer] Доступ к странице по индексу (первая страница имеет индекс 0). Свойство только для чтения
  • PageCount Количество страниц. Свойство только для чтения

В компоненте имеется ряд методов, позволяющих оперировать страницами, создавать их, уничтожать, переключать. Посмотрите их во встроенной справке Delphi. Основные события компонента — OnChanging и OnChange. Первое из них происходит непосредственно перед переключением на другую страницу после щелчка пользователя на новой закладке. При этом в обработчик события передается по ссылке параметр AllowChange — разрешение переключения. Если в обработчике задать AllowChange = false, то переключение не произойдет. Событие OnChange происходит сразу после переключения.

Рассмотрим теперь компонент TabControl. Внешне этот компонент выглядит так же, как PageControl, и имеет много тех же свойств: Style, MultiLine, TabPosition, TabHeight, TabWidth, Images, ScrollOpposite, тех же событий: OnChanging и OnChange. Но принципиальное отличие его от PageControl заключается в том, что TabControl не имеет множества панелей (страниц). Компонент представляет собой одну страницу с управляющим элементом типа кнопки со многими положениями. И надо написать соответствующие обработчики событий OnChanging и OnChange, чтобы определить, что именно должно происходить на панели при переключениях закладок пользователем. У компонента имеется еще одно свойство — MultySelect, позволяющее множественный выбор закладок. Если это свойство установлено в true, то в обработчиках событий надо описать реакцию на такой выбор пользователя.

Число закладок и их надписи определяются свойством Tabs типа TStrings. В нем вы можете задать надписи закладок. Сколько строчек надписей вы укажете, столько будет закладок. Текущее состояние переключателя определяется свойством TabIndex. Вы можете установить его в процессе проектирования, чтобы определить исходное состояние переключателя. А затем в обработчиках событий OnChanging и OnChange можете читать это свойство, чтобы определить, что именно выбрал пользователь.

Применять компонент TabControl имеет смысл в тех приложениях, в которых нужен многопозиционный переключатель. Вы можете, конечно, имитировать с помощью TabControl поведение, аналогичное компоненту PageControl. Для этого достаточно, например, расположить в пределах TabControl две закрывающие друг друга панели и в обработчик события OnChange вставить оператор:

Если Panel2 — верхняя панель, то при выборе первой закладки (TabIndex = 0) она будет делаться невидимой и под ней будет проступать нижняя панель.

Но подобная имитация PageControl не имеет смысла, так как проще использовать сам компонент PageControl. A TabControl надо применять, если требуются какие-то перестроения в рамках одной панели.

Теперь коротко остановимся на компонентах TabSet, TabbedNoteBook и NoteBook. Эти компоненты применяются в Delphi 1 и не рекомендуются для применения в 32-разрядных приложениях.

Компонент TabbedNoteBook является аналогом многостраничной панели PageControl. Только многие одинаковые у этих панелей свойства называются по-разному. Основное свойство — Pages, определяющее число страниц и надписи закладок. Свойство ActivePage определяет надпись активной страницы. Свойство PageIndex определяет индекс активной страницы (0 — первая страница). Так что узнать, какая страница активна, можно или по значению ActivePage, или по PageIndex.

В обработчик события OnChange, происходящего при переключении пользователем страницы, передается параметр NewTab, равный индексу новой страницы, и AllowChange — разрешение переключения. Для запрета переключения можно в обработчике задать AllowChange = false.

Рассмотренный компонент TabbedNoteBook является как бы соединением двух компонентов: пачки панелей (страниц) NoteBook и набора закладок TabSet. Эти два компонента могут использоваться и раздельно. Компонент TabSet во многом аналогичен рассмотренному ранее 32-разрядному компоненту TabControl. Это многопозиционный управляющий элемент, который сам по себе не имеет никакой панели. Его основное свойство — Tabs типа TStrings. Задавая строки этого свойства вы тем самым определяете число закладок и их надписи. Свойства StartMargin и EndMargin определяют поля — расстояния крайних закладок от краев компонента. Сами закладки всегда направлены вниз. Поэтому компонент TabSet надо располагать внизу управляемого им компонента. Свойство AutoScroll определяет появление кнопок при большом количестве закладок, которые позволяют пользователю прокручивать полосу закладок, как это делается в компонентах PageControl и TabControl при MultiLine = false. Индекс выбранной закладки определяется свойством TabIndex, значение которого можно устанавливать и можно читать в обработчике события OnChange, происходящего при смене пользователем закладки и идентичного такому событию в компоненте TabbedNoteBook.

Компонент NoteBook является пачкой панелей, имена и количество которых определяются свойством Pages, как в компоненте TabbedNoteBook. Индекс выбранной страницы определяется свойством PageIndex. В этом компоненте отсутствует управляющий элемент — закладки. Так что страницы можно переключать какими-то кнопками, переключать их в зависимости от действий пользователя, в зависимости от отображаемых данных и т.п. Компоненты NoteBook и TabSet могут быть, конечно, объединены программно в компонент, аналогичный TabbedNoteBook. Для этого достаточно в обработчик события OnChange компонента TabSet вставить оператор

Но подобное использование этих компонентов вряд ли целесообразно: уж лучше использовать непосредственно TabbedNoteBook.

Добавление элементов управления в TTabbedNotebook и TNotebook

Delphi , Компоненты и Классы , Вкладки и Страницы

Я несколько раз видел в конференциях вопросы типа «как мне добавить элементы управления в TTabbedNotebook или TNotebook во время выполнения программы?». Теперь, когда у меня выдалось несколько свободных минут, я попытаюсь осветить этот вопрос как можно подробнее:

Добавление элементов управления в TTabbedNotebook во время проектирования — красивая и простая задача. Все, что Вам нужно — это установить свойство PageIndex или ActivePage на необходимую страницу и начать заполнять ее элементами управления.

Добавление элементов управление во время выполнения приложения также очень просто. Тем не менее, в прилагаемой документации по Delphi вы не найдете рецептов типа Что-и-Как. Видимо для того, чтобы окончательно запутать начинающих программистов, фирма-изготовитель даже не удосужилась включить исходный код TTabbedNotebook в VCL-библиотеку. Таким образом, TTabbedNotebook остается для некоторых тайной за семью печатями. К счастью, я имею некоторый опыт, коим и хочу поделиться.

Первым шагом к раскрытию тайны послужит просмотр файла \DELPHI\DOC\TABNOTBK.INT, интерфейсной секции модуля TABNOTBK.PAS, в котором определен класс TTabbedNotebook. Беглый просмотр позволяет обнаружить класс TTabPage, описанный как хранилище элементов управления отдельной страницы TTabbedNotebook.

Вторым шагом в исследовании TTabbedNotebook может стать факт наличия свойством Pages типа TStrings. В связи с этим отметим, что Delphi-классы TStrings и TStringList соорганизуются с двумя свойствами: Strings и Objects. Другими словами, для каждой строки в TStrings есть указатель на соответствующий Objects. Во многих случаях этот дополнительный указатель игнорируется, нам же он очень пригодится.

После небольшого эксперимента выясняем, что свойство Objects указывает на нашу копию TTabPage и ссылается на имя страницы в свойстве Strings. Блестяще! Всегда полезно знать что ищешь. Теперь посмотрим что мы можем сделать:

Операция по заполнению элементами управления компонента TNotebook почти такая же, как и в TTabbedNotebook — разница лишь в типе класса — TPage вместо TTabPage. Тем не менее, если вы заглянете в DELPHI\DOC\EXTCTRLS.INT, декларацию класса TPage вы там не найдете. По неизвестной причине Borland не включил определение TPage и в DOC-файлы, поставляемые с Delphi. Декларация TPage в EXTCTRLS.PAS (можно найти в библиотеке VCL-исходников), правда, расположена в интерфейсной части модуля. Мы восполним пропущенную информацию о классе TPage:

Теперь, по аналогии с вышеприведенной процедурой, попробуем добавить кнопку на TNotebook. Все, что мы должны сделать — заменить «TTabbedNotebook» на «TNotebook» и «TTabPage» на «TPage». Вот что должно получиться:

Остальное не менее просто!

Статья Добавление элементов управления в TTabbedNotebook и TNotebook раздела Компоненты и Классы Вкладки и Страницы может быть полезна для разработчиков на Delphi и FreePascal.

Комментарии и вопросы

Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.

Лови Книгу .ру

Огромная коллекция книг в открытом доступе

Виртуальная библиотека Delphi

Поместите в конструктор компонента код, устанавливающий размеры по умолчанию. Переопределите метод SetBounds и проверяйте в нем «componentstate». Если компонет находится режиме «design-time» (csDesigning in ComponentState) просто передавайте значения ширины и высоты (width и heights) компонента по умолчанию (в нашем примере 50) методу класса-предка.

procedure TVu.SetBounds(ALeft : integer; ATop : integer; AWidth : integer; AHeight : integer);

if csdesigning in componentstate then begin

inherited; //вызываем унаследованный от предка метод

Можно ли уменьшить потребляемые компонентами TNotebook и TTabbedNotebook ресурсы?

Да. Можно уничтожать обьекты, расположенные не на текущей странице TNotebook или TTabbedNotebook. В примере вызывается защищенный (Protected) метод путем создания так называемый «class

Добавление Edit в компонент TabbedNotebook

а вот именно в этот компонент и + чтоб он стал по размеру окна компонента

Edit то должен оставаться на той в кладке куда я его добавил

Вот попробовал с компонентом PageControl добавление , такая же история

Вот добавил я на первую вкладку Edit. Потом переключился на вторую вкладку. И что должно произойти? А потом взял и вернулся назад на первую. И что теперь?

Python потребляет много памяти или как уменьшить размер объектов?

Проблема памяти может возникнуть, когда в процессе выполнения программы нужно иметь большое количество объектов, особенно если есть ограничения на общий размер доступной оперативной памяти.

Ниже приводится обзор некоторых методов уменьшения размера объектов, которые позволяют существенно сократить объем оперативной памяти, необходимой для программ на чистом Python.

Для простоты будем рассматривать структуры в Python для представления точки с координатами x , y , z с доступом к значениям координат по имени.

В небольших программах, особенно в скриптах, довольно просто и удобно использовать встроенный dict для представления структурной информации:

С появлением более «компактной» реализации в Python 3.6 с упорядоченным набором ключей dict стал еще более привлекательным. Однако, посмотрим на размер его следа в оперативной памяти:

Он занимает много памяти, особенно, если вдруг понадобится создать большое число экземпляров:

Количество экземпляров Размер следа
1 000 000 240 Мб
10 000 000 2.40 Гб
100 000 000 24 Гб

Class instance

Для любителей все облекать в классы более предпочтительным является определение в виде класса с доступом по имени атрибута:

Интересна структура экземпляра класса:

Поле Размер (байт)
PyGC_Head 24
PyObject_HEAD 16
__weakref__ 8
__dict__ 8
ВСЕГО: 56

Здесь __weakref__ это ссылка на список, так называемых, слабых ссылок (weak reference) на данный объект, поле __dict__ это ссылка на словарь экземпляра класса, в котором содержатся значения атрибутов экземпляра (заметим, что ссылки на 64-битной платформе занимают 8 байт). Начиная с Python 3.3, используется общее пространство для хранения ключей в словаре для всех экземпляров класса. Это сокращает размер следа экземпляра в памяти:

Как результате большое количество экземпляров класса оставляют меньший след в памяти, чем обычный словарь ( dict ):

Количество экземпляров Размер следа
1 000 000 168 Мб
10 000 000 1.68 Гб
100 000 000 16.8 Гб

Нетрудно заметить, что след экземпляра в памяти все еще велик из-за размера словаря экземпляра.

Instance of class with __slots__

Существенное уменьшение следа экземпляра в памяти достигается путем исключения __dict__ и __weakref__ . Это возможно при помощи «трюка» со __slots__ :

След в памяти стал существенно компактнее:

Поле Размер (байт)
PyGC_Head 24
PyObject_HEAD 16
x 8
y 8
z 8
ВСЕГО: 64

Использование __slots__ в определении класса приводит к тому, что след большого числа экземпляров в памяти существенно уменьшается:

Количество экземпляров Размер следа
1 000 000 64 Мб
10 000 000 640 Мб
100 000 000 6.4 Гб

В настоящее время это основной метод существенного сокращения следа памяти экземпляра класса в памяти программы.

Достигается такое сокращение тем, что в памяти после заголовка объекта хранятся ссылки на объекты, а доступ к ним осуществляется при помощи специальных дескрипторов (descriptor), которые находятся в словаре класса:

Для автоматизации процесса создания класса со __slots__ существует библиотека namedlist. Функция namedlist.namedlist создает класс по структуре идентичный классу со __slots__ :

Другой пакет attrs позволяет автоматизировать процесс создания классов как со __slots__ , так и без него.

Tuple

Для представления наборов данных в Python также есть встроенный тип tuple . Tuple это фиксированная структура или запись, но без имен полей. Для доступа к полю используется индекс поля. Поля tuple раз и навсегда связываются с объектами-значениями в момент создания экземпляра tuple:

Экземпляры tuple вполне компактны:

Они занимают в памяти на 8 байт больше, чем экземпляры классов со __slots__ , так как след tuple в памяти также содержит количеством полей:

Поле Размер (байт)
PyGC_Head 24
PyObject_HEAD 16
ob_size 8
[0] 8
[1] 8
[2] 8
ВСЕГО: 72

Namedtuple

Так как tuple используется очень широко, то однажды возник запрос на то, чтобы можно было все-таки иметь доступ к полям и по имени тоже. Ответом на этот запрос стал модуль collections.namedtuple .

Функция namedtuple создана, чтобы автоматизировать процесс порождения таких классов:

Она создает подкласс tuple, в котором определены дескрипторы для доступа в полям по имени. Для нашего примера это будет выглядеть примерно так:

Все экземпляры таких классов имеет след в памяти, идентичный с tuple. Большое число экземпляров оставляют чуть больший след памяти:

Количество экземпляров Размер следа
1 000 000 72 Мб
10 000 000 720 Мб

Recordclass: мутируемый namedtuple без GC

Так как tuple и, соответственно, namedtuple -классы порождают немутируемые объекты в том смысле, что объект значение ob.x уже нельзя связать с другим объектом-значением, то возник запрос на мутируемый вариант namedtuple. Так как в Python нет встроенного типа, идентичного tuple, поддерживающего присваивания, то было создано множество вариантов. Мы остановимся на recordclass, получившем оценку на stackoverflow. Кроме того, с его помощью можно уменьшить размер следа объекта в памяти по сравнению с размером следа объектов типа tuple .

В пакете recordclass вводится в обиход тип recordclass.mutabletuple , который практически во всем идентичен tuple, но также поддерживает присваивания. На его основе создаются подклассы, которые практически во всем идентичны namedtuples, но также поддерживают присваивание новых значений полям (не создавая новых экземпляров). Функция recordclass подобно функции namedtuple позволяет автоматизировать создание таких классов:

Экземпляры класса имеют аналогичную стуктуру, что и tuple , но только без PyGC_Head :

Поле Размер (байт)
PyObject_HEAD 16
ob_size 8
x 8
y 8
y 8
ВСЕГО: 48

По умолчанию функция recordclass порождает класс, который не участвует в механизме циклической сборки мусора. Обычно namedtuple и recordclass используют для порождения классов, представляющих записи или простые (нерекурсивные) структуры данных. Корректное их использование в Python не порождает циклических ссылок. По этой причине в следе экземпляров классов, порожденных recordclass по умолчанию, исключен фрагмент PyGC_Head , который необходим для классов, поддерживающих механизм циклической сборки мусора (более точно: в структуре PyTypeObject , соответствующей создаваемому классу в поле flags по умолчанию не установлен флаг Py_TPFLAGS_HAVE_GC ).

Размер следа большого количества экземпляров оказывается меньше, чем у экземпляров класса со __slots__ :

Количество экземпляров Размер следа
1 000 000 48 Мб
10 000 000 480 Мб
100 000 000 4.8 Гб

Dataobject

Другое решение, предложенное в библиотеке recordclass основано на идее: использовать структуру хранения в памяти, как у экземпляров классов со __slots__ , но не участвовать при этом в механизме циклической сборки мусора. Класс порождается при помощи функции recordclass.make_dataclass :

Созданный таким образом класс по умолчанию, создает мутируемые экземпляры.

Другой способ – использовать объявление класса путем наследования от recordclass.dataobject :

Создаваемые таким образом классы будут порождать экземпляры, которые не участвуют в механизме циклической сборки мусора. Структура экземпляра в памяти такая же, как в случае со __slots__ , но без заголовка PyGC_Head :

Поле Размер (байт)
PyObject_HEAD 16
x 8
y 8
y 8
ВСЕГО: 40

Для доступа к полям также используются специальные дескрипторы для доступа к полю по его смещению относительно начала объекта, которые размещены в словаре класса:

Размер следа большого количества экземпляров оказывается минимально возможным для CPython :

Количество экземпляров Размер следа
1 000 000 40 Мб
10 000 000 400 Мб
100 000 000 4.0 Гб

Cython

Есть один подход, основанный на использовании Cython. Его достоинство состоит в том, что поля могут принимать значения типов языка C. Дескрипторы для доступа к полям из чистого Python создаются автоматически. Например:

В этом случае экземпляры имеют еще меньший размер памяти:

След экземпляра в памяти имеет следующую структуру:

Поле Размер (байт)
PyObject_HEAD 16
x 4
y 4
y 4
пусто 4
ВСЕГО: 32

Размер следа большого количества экземпляров получается меньше:

Количество экземпляров Размер следа
1 000 000 32 Мб
10 000 000 320 Мб
100 000 000 3.2 Гб

Однако следует помнить, что при доступе из кода на Python всякий раз будет осуществляться преобразование из int в объект Python и наоборот.

Numpy

Использование многомерных массивов или массивов записей для большого количества данных дает выигрыш в памяти. Однако для эффективной обработки на чистом Python следует использовать методы обработки, ориентированные на применение функций из пакета numpy .

Массив и N элементов, инициализированный нулями создается при помощи функции:

Размер массива минимально возможный:

Количество экземпляров Размер следа
1 000 000 12 Мб
10 000 000 120 Мб
100 000 000 1.20 Гб

Обычный доступ к элементам массива и строкам потребует преобразования объекта Python
в значение C int и наоборот. Извлечение одной строки приводит к созданию массива, содержащего единственный элемент. След его уже не будет столь компактен:

Поэтому, как было отмечено выше, в коде на Python необходимо осуществлять обработку массивов, используя функции из пакета numpy .

Заключение

На наглядном и простом примере можно было убедиться, что сообщество разработчиков и пользователей языка программирования Python (CPython) располагает реальными возможностями для существенного сокращения объема памяти, используемой объектами.

Читают сейчас

Похожие публикации

  • 17 сентября 2015 в 10:34

Написание framework на asyncio, aiohttp и мысли про Python3 часть первая

Катастрофа Unicode в Python3

Простой классификатор на PyBrain и PyQt4 (Python3)

Заказы

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Комментарии 22

Как-то рассуждая о проблемах оптимизации использования памяти и времени выполнения я услышал на мой взгляд классный вывод:

Сегодня проблемы памяти и времени не существует. Существует проблема денег.

Ну не всегда это правильно, существуют моменты пикового потребления памяти, например до 10..20гб, а в остальное время, 99.9%, приложение живет в скромных 100..200мб.
Плюс, не надо забывать, что сначала к нам приходит 10 человек в минуту, а через неделю 100 и так далее. Можно и устать масштабироваться :)

Recordclass: мутируемый namedtuple без GC

А как в данном случае чистить память? Или ждать конца работы программы?

Здесь срабатывает механизм подсчета ссылок. Как только количество ссылок станет равным нулю, объект сразу утилизируется. Предполагается, что циклические ссылки на этот объект не возникают.

Можно обосновать минус? Что в ответе не верно?

И да, и нет. Подсчет ссылок — это часть GC. Т.к. GC брлее широкое понятие, включающее в себе определение, например, кластеров объектов, ссылающихся друг на друга (но не имеющих ссылки извне), и, например, релокации объектов в памяти для уменьшения ее фрагментации

Нет, это разные вещи. С разным механизмом работы, разными возможностями и разным влиянием на производительность.

Простым подсчетом ссылок не определишь, что набор объектов с зацикленными ссылками стал недостижимым (напр. все двусвязные списки из >1 ноды будут утекать. Т.к. в структуре A ⇆ B и на A и на B всегда есть как минимум одна ссылка. Даже когда кроме их самих никто на них не ссылается).

У GC принцип работы другой — он просто обходит всю компоненту связности графа объектов, начиная с «корневого» объекта, и затем убивает все объекты, которые во время этого обхода оказались недостижимыми (на самом деле обходится не весь граф, есть разделение поколений объектов и другие оптимизации, но сам принцип остается прежним — обходим (под-)граф и удаляем все, к чему не дошли).

В Python используются оба этих механизма.

Вы меня запутали ) GC — garbage collector, то есть сборка мусора

Нет, GC- сборщик мусора, то есть компонент рантайма, который периодически выходит на уборку.

При подсчете ссылок, не нужный объект умирает в момент обнуления счетчика, тогда как GC убивает в непредсказуемый момент времени после окончания использования объекта.

Вероятно опечатка) В эппловких языках нет GC, но есть подсчет ссылок. А скажем, в джаве есть GC, а подсчета ссылок нет.

В Python есть и то и другое. Можно рассматривать подсчет ссылок как одну из оптимизаций GC, но в общем случае это независимые вещи, которые прекрасно работают отдельно друг от друга, что видно из примеров выше.

GC — garbage collector — это модуль рантайма, т.к. сборщик мусора
GC — как garbage collection — это процесс (в смысле как явление, а не в смысле потока рантайма), который он обеспечивает.

В Python есть механизм подсчёта ссылок — это основной способ управления памятью и жизнью объектов. И есть GC, который основан на поколениях: https://docs.python.org/3/library/gc.html

Он используется для очистки объектов с циклическими ссылками. Его, кстати, можно отключить или наоборот вызвать очистку явно.

А ещё в Python есть модуль weakref для создания слабых ссылок, но не уверен, что этот механизм будет работать со штуками из recordclass.

Можно создавать классы с поддержкой weakref, но без участия в механизме циклической сборки мусора:

В Python есть основной механизм подсчета ссылок на объект. Если объект таков, что циклические ссылки на него в графе зависимостей между объектами не возникают, то после того, как счетчик ссылок (находится в заголовке объекта PyObject_HEAD ) обнуляется, что означает что объект более никем не используется, то автоматически утилизируется из памяти. Тут правда есть нюансы, связанные с распределителем памяти объектов в Python, но оставим это за скобками. Дополнительно есть механизм для утилизации для объектов, в которым возможны циклические ссылки. В объекте-типе для классов установлен специальный флаг, который сигнализирует, что объект должен быть утилизирован через механизм циклической сборки мусора, который включает в себя обход таких объектов с целью ликвидации циклов в графе зависимостей между объектами. Для простых объектов типа str, long, date/time такой флаг не выставлен и они утилизируются через механизм подсчета ссылок. Контейнерные типы list, dict, любой класс созданный через обычное определение class, и даже немутируемый tuple имеют такой флаг. Однако не всегда маркирование класса автоматически, как потенциальный для возникновения циклических ссылок, оправдано. Например, объекты, которые представляют простые структуры, которые в графе зависимостей между объектами по-существу являются терминальными. Корректное использование таких классов не приводит к возникновению циклических ссылок. Поэтому здесь механизм циклической сборки мусора избыточен и может быть и может быть исключен.

Задавшему вопрос отдельная благодарность за возможность прояснить ситуацию.

Вы правы, это вышло за скобки. Я не преследовал цель сделать полный обзор. Но отметил наиболее часто используемые. Что касается array.array для большого числа значений, выигрыш по памяти есть, так же как и в случае с numpy . Но остается нагрузка в связи с необходимостью преобразования С-шных типов в Python-овские и наоборот. Если выигрыш в памяти важнее, чем потеря производительности в связи с boxing/unboxing, то да действительно это работает. Что касается ctypes.Structure , у меня нет опыта работы с ctypes. Однако, исторически ctypes создавался для того, чтобы обеспечивать доступ к структурам, которые изначально живут в бинарных модулях (dll/so), которые создавались при помощи C/C++ или следовали соответствующим конвенциям.
Проблема boxing/unboxing здесь остается.

В статье основной акцент старался сделать на том, как в «чистом» Python добиться уменьшения потребления памяти при создании объектов, которые тоже состоят из Python-овских объектов.

Для экземпляров классов, порожденных recordclass и унаследованных от dataobject pympler не может вычислить правильный размер экземпляра. Похоже, что для экземпляров классов со __slots__ тоже почему-то дает завышенное значение.

Поэтому для того, чтобы pympler мог давать верный размер для объектов, порожденных подклассами dataobject , его нужно сначала «научить» )

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

DBGrid

Есть пример в Delphi Technical Information… Его можно посмотреть по адресу http://loki.borland.com/winbin/bds.exe?getdoc+2976+Delphi

Данный пример позволяет производить множественный выбор записей

в табличной сетке и отображать второе поле

Метод DisableControls применяется для того, чтобы

DBGrid не обновлялся во время изменения набора данных.

Последняя позиция набора данных сохраняется как

Метод IndexOf вызывается для проверки

Решение использовать метод IndexOf, а не метод

procedure TForm1.SelectClick(Sender: TObject);

with DBgrid1.SelectedRows do if Count <> 0 then begin

for x:= 0 to Count — 1 do begin

Массив Edit-компонентов

Примечание: узнать доступные свойства компонента можно непосредственно в инспекторе объектов и (или) в текстовом режиме вашей формы (щелкните на форме правой кнопкой мыши и выберите пункт View as Text)

Label

3D-рамка для текстовых компонентов

Один из примеров создания текстового компонента с трехмерной декоративной контурной рамкой (для создания компонента потребовалось около получаса. Он демонстрирует только принцип получения рамки. Я не стал колдовать над свойствами типа ParentFont…, т.к. это заняло бы еще немало времени и места).

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

procedure SetAlignment(taIn : TAlignment);

procedure SetCaption(const strIn: String);

constructor Create(compOwn: TComponent); override;

property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;

property Caption: String read FCaption write SetCaption;

property Font: TFont read FFont write SetFont;

property Offset: Byte read FOffset write SetOffset;

property OnChange: TNotifyEvent read FOnChange write FOnChange;

with compOwn as TForm do FFont.Assign(Font);

wYPos:= (Height – Canvas.TextHeight(Caption)) div 2;

taRightJustify: wXPos:= Width – Canvas.TextWidth(Caption) – Offset;

taCenter: wXPos := (Width – Canvas.TextWidth(Caption)) div 2;

if Assigned(FOnChange) then FOnChange(Self);

ScrollBox

Синхронизация двух компонентов Scrollbox

Решить задачу помогут обработчики событий OnScroll (в данном примере два компонента ScrollBox (ScrollBar1 и ScrollBar2) расположены на форме TMainForm):

procedure TMainForm.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer);

procedure TMainForm.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer);

Splitter

Конструирование Splitter

У меня есть форма с расположенными на ней компонентами TreeView и Memo. Значение свойства align обоих компонентов позволяет им занимать всю форму. Я хотел бы расположить между ними движок типа Splitter, пропорционально меняющий их размеры (один шире, другой меньше и наоборот), но к сожалению я обладаю лишь дистрибутивом Delphi2 (Splitter вошел в палитру только в Delphi3). Какой компонент мог бы сымитировать поведение Splitter и как это реализовать?

Предположим, Ваш TreeView расположен в левой, а Memo в правой части формы. Вам нужно сделать следующее:

• Установите свойство Align компонента TreeView на alLeft.

• Вырежьте (Ctrl-X) компонент TMemo из вашей формы.

• Добавьте компонент Panel и присвойте его свойству Align значение alClient.

• Внутри панели разместите другой компонент Panel.

• Установите его ширину, равной 8 пикселам, свойству Align присвойте значение alLeft.

• Скопируйте вырезанный компонент TMemo в панель Panel1 и присвойте свойству Align значение alClient.

Panel2 – движок: теперь вам необходимо добавить процедуры, приведенные ниже. Ваш код будет выглядеть приблизительно так:

procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

procedure TForm1.Panel2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

procedure TForm1.Panel2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

procedure TForm1.Panel2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

// Предохранение от странных ошибок перерисовки при изменении размеров:

Код может быть модифицирован для получения горизонтального движка – идея, надеюсь, понятна…

StatusBar

Обработчик события OwnerDraw в компоненте StatusBar

Обработчик должен выглядеть примерно так:

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect);

with statusbar1.Canvas do begin

TextOut(Rect.Left, Rect.Top, ‘Панель ‘+IntToStr(Panel.Index));

StringGr >Манипулирование вышеуказанным атрибутом возможно в обработчике события OnSelectCell:

if Col mod 2 = 0 then grd.Options:= grd.Options + [goEditing]

else grd.Options:= grd.Options – [goEditing];

Помещение изображения в ячейку StringGrid

Возможно ли поместить изображение в одну из ячеек компонента StringGrid?

Такое позволяет обработчик события OnDrawCell. Приводим скелет кода, демонстрирующий принцип вывода изображения в ячейке компонента:

with StringGrid1.Canvas do begin

Draw(Rect.Left, Rect.Top, Image1.Picture.Graphic);

Достичь цели позволяют методы Draw() и StretchDraw() объекта TCanvas. В приведенном примере переменная Image1 класса TImage содержит заранее загруженное изображение.

Сохранение и чтение Tstringgrid

Как мне сохранить целый Stringgrid со всеми ячейками в файле?

TabbedNotebook

Добавление элементов управления в TTabbedNotebook и TNotebook

Я несколько раз видел в конференциях вопросы типа «как мне добавить элементы управления в TTabbedNotebook или TNotebook во время выполнения программы?». Теперь, когда у меня выдалось несколько свободных минут, я попытаюсь осветить этот вопрос как можно подробнее:

Добавление элементов управления в TTabbedNotebook во время проектирования – красивая и простая задача. Все, что Вам нужно – это установить свойство PageIndex или ActivePage на необходимую страницу и начать заполнять ее элементами управления.

Добавление элементов управление во время выполнения приложения также очень просто. Тем не менее, в прилагаемой документации по Delphi вы не найдете рецептов типа Что-и-Как. Видимо для того, чтобы окончательно запутать начинающих программистов, фирма-изготовитель даже не удосужилась включить исходный код TTabbedNotebook в VCL-библиотеку. Таким образом, TTabbedNotebook остается для некоторых тайной за семью печатями. К счастью, я имею некоторый опыт, коим и хочу поделиться.

Первым шагом к раскрытию тайны послужит просмотр файла \DELPHI\DOC\TABNOTBK.INT, интерфейсной секции модуля TABNOTBK.PAS, в котором определен класс TTabbedNotebook. Беглый просмотр позволяет обнаружить класс TTabPage, описанный как хранилище элементов управления отдельной страницы TTabbedNotebook.

Вторым шагом в исследовании TTabbedNotebook может стать факт наличия свойством Pages типа TStrings. В связи с этим отметим, что Delphi-классы TStrings и TStringList соорганизуются с двумя свойствами: Strings и Objects. Другими словами, для каждой строки в TStrings есть указатель на соответствующий Objects. Во многих случаях этот дополнительный указатель игнорируется, нам же он очень пригодится.

После небольшого эксперимента выясняем, что свойство Objects указывает на нашу копию TTabPage и ссылается на имя страницы в свойстве Strings. Блестяще! Всегда полезно знать что ищешь. Теперь посмотрим что мы можем сделать:

procedure AddButton(tabNotebook : TTabbedNotebook);

500+ FAQ по Delphi

Перейти на: Главную | Индексную | Предыдущую | Следующую страницу

Узин проекты деревянных домов деревянный дом
Как сделать прямоугольник для выделения части картинки для редактирования?

Самый простой способ — воспользоваться функцией Windows API DrawFocusRect. Функция DrawFocusRect использует операцию XOR при рисовании — таким образом вывод прямоугольника дважды с одними и теми же координатами стирает прямоугольник, и прямоугольник всегда будет виден, на фоне какого бы цвета он не выводился.
Пример:

type
TForm1 = class(TForm)
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private

Capturing : bool;
Captured : bool;
StartPlace : TPoint;
EndPlace : TPoint;
public

end;

var
Form1: TForm1;

function MakeRect(Pt1 : TPoint; Pt2 : TPoint) : TRect;
begin
if pt1.x Можно ли использовать иконку как картинку на кнопке TSpeedButton?

Можно.
uses ShellApi;

procedure TForm1.FormShow(Sender: TObject);
var
Icon: TIcon;
begin
Icon := TIcon.Create;
Icon.Handle := ExtractIcon(0,’C:\WINDOWS\NOTEPAD.EXE’,1);
SpeedButton1.Glyph.W > SpeedButton1.Glyph.Height := Icon.Height;
SpeedButton1.Glyph.Canvas.Draw(0, 0, Icon);
Icon.Free;
end;
Как поместить прозрачную фоновую каринку на компонент CoolBar?

procedure TForm1.Button1Click(Sender: TObject);
var
Bm1 : TBitmap;
Bm2 : TBitmap;
begin
Bm1 := TBitmap.Create;
Bm2 := TBitmap.Create;
Bm1.LoadFromFile(‘c:\download\test.bmp’);
Bm2.W > Bm2.Height := Bm1.Height;
bm2.Canvas.Brush.Color := CoolBar1.Color;
bm2.Canvas.BrushCopy(Rect(0, 0, bm2.Width, bm2.Height), Bm1,
Rect(0, 0, Bm1.width, Bm1.Height), ClWhite);
bm1.Free;
CoolBar1.Bitmap.Assign(bm2);
bm2.Free;
end;
Ползунок компонента TScrollBar все время мигает. Как это отключить?

Установите свойтсво ScrollBar.TabStop в False.
Как программно перевести DBgrid в режим редактирования и установить курсор в окошке редактирования в требуемую позицию?

Переведите таблицу в режим редактирования, затем получите дескриптор (handle) окна редактирования и перешлите ей сообщение EM_SETSEL. В качестве параметров вы должны переслать начальную позицию курсора, и конечную позицию, определяющую конец выделения текста цветом. В приведенном примере курсор помещается во вторую позицию, текст внутри ячейки не выделяется.

procedure TForm1.Button1Click(Sender: TObject);
var
h : THandle;
begin
Application.ProcessMessages;
DbGrid1.SetFocus;
DbGr > Application.ProcessMessages;
h:= Windows.GetFocus;
SendMessage(h, EM_SETSEL, 2, 2);
end;
Как поместить курсор в определенную позицию edit’а и подобных ему элементов управления?

Можно использовать методы Delphi SelStart() и SelectLength().
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.SetFocus;
<переводим курсор во вторую позицию>
Edit1.SelStart := 2;
<не выделяем никакого текста>
Edit1.SelLength := 0;
end;
Как среагировать на минимизацию-максимизацию формы перед тем как произойдет изменение размера формы?

В примере перехватывается сообщение WM_SYSCOMMAND. Если это сообщение говорит о
минимизации или максимизации формы — пищит динамик.

type
TForm1 = class(TForm)
private

procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
public

end;

var
Form1: TForm1;

procedure TForm1.WMSysCommand;
begin
if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0)
else
inherited;
end;
Можно ли сделать так — одна форма показывает другую и остается позади нее, но фокус ввода не переходит к новой форме, а остается у старой?

В примере показывается не автосоздаваемая (non auto-created) форма, но фокус ввода ей
не передается.

procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Application);
Form2.Visible := FALSE;
ShowWindow(Form2.Handle, SW_SHOWNA);
end;
На некоторых laptop компьютерах может не быть флоппи дисковода. Можно ли удалять из списка TDriveComboBox диски которые отключены?

В примере TDriveComboBox не показывает дисководы, которые не готовы. (not ready).
Учтите что на многих компьютерах будет ощутимая задержка при поверке plug&play
флоппи дисковода.

procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
OldErrorMode : Word;
OldDirectory : string;
begin
OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
GetDir(0, OldDirectory);
i := 0;
while i 0 then
DriveComboBox1.Items.Delete(i)
else
inc(i);
end;
ChDir(OldDirectory);
SetErrorMode(OldErrorMode);
end;
Как сообщить всем формам моего приложения (в том числе и не видимым в данный момент) об изминении каких-то глобальных значений?

Один из способов — создать пользовательское сообщение и использовать метод preform
чтобы разослать его всем формам из массива Screen.Forms.

const
UM_MyGlobalMessage = WM_USER + 1;

type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private

procedure UMMyGlobalMessage(var AMessage: TMessage); message
UM_MyGlobalMessage;
public

end;

var
Form1: TForm1;

procedure TForm1.FormShow(Sender: TObject);
begin
Form2.Show;
end;

procedure TForm1.UMMyGlobalMessage(var AMessage: TMessage);
begin
Label1.Left := AMessage.WParam;
Label1.Top := AMessage.LParam;
Form1.Caption := ‘Got It!’;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
f: integer;
begin
for f := 0 to Screen.FormCount — 1 do
Screen.Forms[f].Perform(UM_MyGlobalMessage, 42, 42);
end;

const
UM_MyGlobalMessage = WM_USER + 1;
type
TForm2 = class(TForm)
Label1: TLabel;
private

procedure UMMyGlobalMessage(var AMessage: TMessage);
message UM_MyGlobalMessage;
public

end;

var
Form2: TForm2;

procedure TForm2.UMMyGlobalMessage(var AMessage: TMessage);
begin
Label1.Left := AMessage.WParam;
Label1.Top := AMessage.LParam;
Form2.Caption := ‘Got It!’;
end;
Как обновить список дисков компонента TDriveComboBox, учитывая, что могут быть подключены/отключены сетевые диски и произведена «горячая замена» plug&play дисков?

Следующий пример вызывает защищенный (protected) метод класса TDriveComboBox
BuildList() для регеирации списка дисков. (использовая так наз. «class cracer»)

type
TNewDriveComboBox = class(TDriveComboBox) //это наш «class cracer»
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Drive : char;
begin
Drive := DriveComboBox1.Drive;
TNewDriveComboBox(DriveComboBox1).BuildList;
//вызываем защищенный метод родительского класса
DriveComboBox1.Drive := Drive;
end;
Как программно заставить выпасть меню?

В примере показано как показать меню и выбрать в нем какой-то пункт, эмулируя нажатие «быстрой кдавиши» пункта меню. Если у Вашего пункта меню нет «быстрой клавиши» Вы можете посылать комбинации VK_MENU, VK_LEFT, VK_DOWN, и VK_RETURN, чтобы программно «путешествовать» по меню.
Пример:

procedure TForm1.Button1Click(Sender: TObject);
begin
//Allow button to finish painting in response to the click
Application.ProcessMessages;

keybd_Event(VK_MENU, 0, 0, 0);

keybd_Event(ord(‘F’), 0, 0, 0);

keybd_Event(ord(‘F’), 0, KEYEVENTF_KEYUP, 0);

keybd_Event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);

keybd_Event(ord(‘S’), 0, 0, 0);

keybd_Event(ord(‘S’), 0, KEYEVENTF_KEYUP, 0);
end;
Как сделать клавишу-акселератор (keyboard shortcut) компонету у которого нет заголовка?

Возможный вариант — присвоить ссылку на этот компонент свойству FocusControl TLabel’а. В примере используется невидимый Label для создания «быстрой» клавиши (Alt+M) компонента Memo. Чтобы использовать пример, разместите на форме компонет TMemo, Label и несколько других компонентов, которые могут принимать фокус ввода. Запустите программу, перевидите фокус ввода куда-нибудь вне Memo и нажмите Alt+M — фокус ввода вернется в Memo.
Пример:

procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Visible := false;
Label1.Caption := ‘&M’;
Label1.FocusControl := Memo1;
end;
Можно ли как-то уменьшить мерцание при перерисовке компонента?

Если добавить флаг csOpaque (непрозрачный) к свойству ControlStyle компонента
— то фон компонента перерисовываться не будет.

constructor TMyControl.Create;
begin
inherited;
ControlStyle := ControlStyle + [csOpaque];
end;
Как запретить изменение размера моего компонента в design-time?

Поместите в конструктор компонента код, устанавливающий размеры по умолчанию.
Переопределите метод SetBounds и проверяйте в нем «componentstate». Если компонет
находится режиме «design-time» (csDesigning in ComponentState) просто передавайте
значения ширины и высоты (width и heights) компонента по умолчанию (в нашем
примере 50) методу класса-предка.

procedure TVu.SetBounds(ALeft : integer; ATop : integer; AWidth : integer;
AHeight : integer);
begin
if csdesigning in componentstate then
begin
AW > AHeight := 50;
inherited; //вызываем унаследованный от предка метод
end;
end;
Можно ли уменьшить потребляемые компонентами TNotebook и TTabbedNotebook ресурсы?

Да. Можно уничтожать обьекты, расположенные не на текущей странице TNotebook или
TTabbedNotebook. В примере вызывается защищенный (Protected) метод путем создания
так называемый «class cracer’ов».

type TMyTabbedNotebook = class(TTabbedNotebook); //это наш «class cracer»
type TMyNotebook = class(TNotebook);

Советы по Delphi Советы по работе с системой

Название Советы по Delphi Советы по работе с системой
страница 46/46
Дата конвертации 04.01.2013
Размер 0.52 Mb.
Тип Тексты

begin
if csdesigning in componentstate then begin AW > AHeight := 50;
inherited; //вызываем унаследованный от предка метод end;
end;

Вопрос:
Можно ли уменьшить потребляемые компонентами TNotebook и TTabbedNotebook ресурсы?
Ответ:
Да. Можно уничтожать обьекты, расположенные не на текущей странице TNotebook или TTabbedNotebook. В примере вызывается защищенный (Protected) метод путем создания так называемый «class cracer’ов».
type TMyTabbedNotebook = >

procedure TForm1.TabbedNotebook1Change(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
begin
with TabbedNotebook1 do //вызываем защищенный метод родительского класса TMyTabbedNotebook(TWinControl(Pages.Objects[PageIndex])).DestroyHandle;
end;

procedure TForm1.TabSet1Change(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
begin
with Notebook1 do //вызываем защищенный метод родительского класса TMyNotebook(TWinControl(Pages.Objects[PageIndex])).DestroyHandle;
NoteBook1.PageIndex := NewTab;
AllowChange := true
end;

Вопрос:
Функция keybd_event() принимает значения до 244 — как мне отправить нажатие клавиши с кодом #255 в элемент управления Windows?
Ответ:
Это может понадобится для иностранных языков или для специальных символов. (например, в русских шрифтах символ с кодом #255 — я прописное). Приведенный в примере метод не стоит использовать в случае, если символ может быть передан обычным способом (функцией keybd_event()).
procedure TForm1.Button1Click(Sender: TObject);
var KeyData : packed record RepeatCount : word;
ScanCode : byte;
Bits : byte;
end;
begin

Application.ProcessMessages;
Edit1.SetFocus;
// SimulateKeyStroke(VK_RIGHT, 0);
keybd_event(VK_RIGHT, 0,0,0);
Application.ProcessMessages;
FillChar(KeyData, sizeof(KeyData), #0);
KeyData.ScanCode := 255;
KeyData.RepeatCount := 1;
SendMessage(Edit1.Handle, WM_KEYDOWN, 255,LongInt(KeyData));
KeyData.Bits := KeyData.Bits or (1 shl 30);
KeyData.Bits := KeyData.Bits or (1 shl 31);
SendMessage(Edit1.Handle, WM_KEYUP, 255, LongInt(KeyData));
KeyData.Bits := KeyData.Bits and not (1 shl 30);
KeyData.Bits := KeyData.Bits and not (1 shl 31);
SendMessage(Edit1.Handle, WM_CHAR, 255, LongInt(KeyData));
Application.ProcessMessages;
end;

Вопрос:
Некоторые компоненты не меняют курсор мыши до тех пор пока пользователь не сдвинет мышь. Как эмулировать движение мыши?
Ответ:
В примере мышка слегка «подталкивается» без участия пользователя.
procedure TForm1.Button1Click(Sender: TObject);
var pt : TPoint;
begin
Application.ProcessMessages;
Screen.Cursor := CrHourglass;
GetCursorPos(pt);
SetCursorPos(pt.x + 1, pt.y + 1);
Application.ProcessMessages;
SetCursorPos(pt.x — 1, pt.y — 1);
end;

Вопрос:
Как зарегистрировать расширение файла за своим приложением и контекстное меню, связанное с этим типом?
Ответ:
Пример регистрирует расширение файла(.myext) — файлы этого типа будут открываться приложением MyApp.Exe. Также регнстрируется одно действие (action) по умолчанию для файлов этого типа и два дополнительных пункта контекстного меню, связанного с этим типом файлов. Возможно, потребуется перезайти в систему чтобы изменения вступили в силу.
Пример:
uses Registry;

procedure TForm1.Button1Click(Sender: TObject);
var R : TRegIniFile;
begin
R := TRegIniFile.Create(»);
with R do begin
RootKey := HKEY_CLASSES_ROOT;
WriteString(‘.myext’,»,’MyExt’);
WriteString(‘MyExt’,»,’Some description of MyExt files’);
WriteString(‘MyExt\DefaultIcon’,»,’C:\MyApp.Exe,0′);
WriteString(‘MyExt\Shell’,»,’This_Is_Our_Default_Action’);
WriteString(‘MyExt\Shell\First_Action’, »,’This is our first action’);
WriteString(‘MyExt\Shell\First_Action\command’,», ‘C:\MyApp.Exe /LotsOfParamaters %1’);
WriteString(‘MyExt\Shell\This_Is_Our_Default_Action’,», ‘This is our default action’);
WriteString(‘MyExt\Shell\This_Is_Our_Default_Action\command’, »,’C:\MyApp.Exe %1′);
WriteString(‘MyExt\Shell\Second_Action’, »,’This is our second action’);
WriteString(‘MyExt\Shell\Second_Action\command’, »,’C:\MyApp.Exe /TonsOfParameters %1′);
Free;
end;
end;

использовались только версии ODBC 2.0 и Access 2.0.

Local InterBase — однопользовательский SQL сервер базы данных. Версия, включенная в Delphi Desktop, предназначается для использования разработчиками, которые хотят разрабатывать SQL приложения (для последующего переноса их в среду клиент/сервер) без покупки собственной (дорогой) платформы сервера. Однако, Delphi Desktop не включает права распространения на Local InterBase. Если вы хотите распространять однопользовательское приложение, которое его использует, вы должны заплатить дополнительно за deployment kit.

Версия ReportSmith из Delphi Desktop специально обнаруживает и исключает из списка возможных соединений любой ODBC драйвер к удаленному серверу данных. Да, вы не ослышались. Даже если вы купили ODBC драйвер третьей фирмы, и даже если вы можете прекрасно общаться с этим драйвером из Delphi, ReportSmith еще не будет с ним работать. Если вы хотите сделать это без покупки Delphi Client/Server, вы может купить ReportSmith/SQL отдельно за $300 (и тем не менее приобретете ReportSmith версии 2.0, а не 2.5, как в поставке Delphi Client/Server).

Добавление элементов управления в TTabbedNotebook и TNotebook — часть 2

Операция по заполнению элементами управления компонента TNotebook почти такая же, как и в TTabbedNotebook — разница лишь в типе класса — TPage вместо TTabPage. Тем не менее, если вы заглянете в DELPHI\DOC\EXTCTRLS.INT, декларацию класса TPage вы там не найдете. По неизвестной причине Borland не включил определение TPage и в DOC-файлы, поставляемые с Delphi. Декларация TPage в EXTCTRLS.PAS (можно найти в библиотеке VCL-исходников), правда, расположена в интерфейсной части модуля. Мы восполним пропущенную информацию о классе TPage:

TPage = class(TCustomControl)privateprocedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;protectedprocedure ReadState(Reader: TReader); override;procedure Paint; override;publicconstructor Create(AOwner: TComponent); override;publishedproperty Caption;property Height stored False;property TabOrder stored False;property Visible stored False;property Width stored False;end;

Теперь, по аналогии с вышеприведенной процедурой, попробуем добавить кнопку на TNotebook. Все, что мы должны сделать — заменить «TTabbedNotebook» на «TNotebook» и «TTabPage» на «TPage». Вот что должно получиться:

Илон Маск рекомендует:  Что такое код getthresholdstatus
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL