Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Акселераторы






Акселератор позволяет выбирать пункт меню просто сочетанием клавиш. Это очень удобно и быстро. Таблица акселераторов является ресурсом, имя которого совпадает с именем того меню (ресурса), пункты которого она определяет.

Вот пример такой таблицы. Определяется один акселератор на пункт меню MENUP, имеющий идентификатор 4.

 

MENUP ACCELERATORS

{

VK_F5, 4, VIRTKEY

}

 

А вот общий вид таблицы акселераторов:

 

Имя ACCLERATORS

{

Клавиша 1, Идентификатор пункта меню (1) [, тип][, параметр]

Клавиша 2, Идентификатор пункта меню (2) [, тип][, параметр]

Клавиша 3, Идентификатор пункта меню (3) [, тип][, параметр]

Клавиша N, Идентификатор пункта меню (N) [, тип][, параметр]

}

 

Клавиша – это любой символ в кавычках, либо ASCII-код символа, либо виртуальная клавиша. Если вначале стоит код символа, то тип задается как ASCII. Если используется виртуальная клавиша, то тип определяется как VIRTUAL. Все названия (макроимена) виртуальных клавиш можно найти в include – файлах (windows.h).

Параметр может принимать одно из следующих значений: NOINVERT, ALT, CONTROL, SHIFT. Значение NOINVERT означает, что не подсвечивается выбранный при помощи акселератора пункт меню. Значение ALT, SHIFT, CONTROL означают, что, кроме клавиши, определенной в акселераторе, должна быть нажата одна из управляющих клавиш. Кроме этого, если клавиша определяется в кавычках, то нажатие при этом клавиши CONTROL определяется знаком ^: ^A.

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

1. должна быть загружена таблица акселераторов. Для этого используется функция LoadAccelerators;

2. сообщения, пришедшие от акселератора, следует преобразовать в сообщение WM_COMMAND. Здесь нам пригодится функция TranslateAccelerator.

Функция TranslateAccelerator преобразует сообщения WM_KEYDOWN и WM_SYSKEYDOWN в сообщения WM_COMMAND и WM_SYSCOMMAND соответственно. При этом в старшем слове параметра WPARAM помещается 1 как отличие для акселератора. В младшем слове, как вы помните, содержится идентификатор пункт меню. Сообщение WM_SYSCOMMAND генерируется для пунктов системного меню или меню окна.

Функция TranslateAccelerator возвращает ненулевое значение, если было произведено преобразование сообщения акселератора, в противном случае возвращает 0.

 

API – функции

1. Функция LoadIconA

Загружает указанный ресурс пиктограммы из исполняемого файла, связанного с экземпляром приложения.

HICON LoadIcon (

HINSTANCE hInstance, //дескриптор экземпляра приложения

LPCTSTR lpIconName //строка с именем пиктограммы или

); //идентификатор ресурса

 

2. Функция Shell_NotifyIconA

Посылает сообщение системе добавить, изменить или удалить иконку в системной области (System Tray).

WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(

DWORD dwMessage, //идентификатор сообщения

PNOTIFYICONDATA pnid //точка входа в структуру

);

 

3. Функция LoadMenu

Загружает меню из ресурса в контекст приложения

HMENU LoadMenu(

HINSTANCE hInstance, //дескриптор приложения

LPCTSTR lpMenuName); //имя ресурса

 

4. Функция SetMenu

Назначает новое меню указанному окну.

BOOL SetMenu(

HWND hWnd, //дескриптор окна

HMENU hMenu //дескриптор меню

);

 

5. Функция DrawMenuBar

Перерисовывает меню указанного окна

BOOL DrawMenuBar(

HWND hWnd //дескриптор окна

);

 

6. Функция LoadCursorA

Загружает системный курсор или курсор определенный в файле ресурсов

HMENU LoadCursor(

HINSTANCE hInstance, //дескриптор приложения

LPCTSTR lpCursorName //строка с именем курсора или

); //идентификатор ресурса

 

7. Функция LoadBitmapA

Загружает битовую картинку определенную в файле ресурсов

HMENU LoadBitmap(

HINSTANCE hInstance, //дескриптор приложения

LPCTSTR lpBitmapName //строка с именем битовой картинки

); //или идентификатор ресурса

 

 

8. Функция LoadStringA

Загружает строку, определенную в файле ресурсов

HMENU LoadString (

HINSTANCE hInstance, //дескриптор приложения

LPCTSTR lpStringName //строка с именем строки или

); //идентификатор ресурса

 

9. Функция SetFocus

Устанавливает фокус на заданное окно

 

10. Функция DestroyMenu

Удаляет меню из памяти

 

11. Функция GetMenuItemInfo

Получает информацию о выбранном пункте меню

 

Вопросы для подготовки к сдаче лабораторной работы.

 

1. Что понимается под термином ресурс в операционной системе Windows.?

2. Каким образом в программе хранятся ресурсы?

3. Какие виды ресурсов вы знаете?

4. Язык описания ресурсов, приведите пример описания.

5. Особенности хранения меню в ресурсах программы.

6. Особенности хранения строк в ресурсах.

7. Особенности хранения изображений в ресурсах.

8. Каким образом извлекаются данные из ресурсов.

9. В каких случаях ресурсы загружаются в память?

10. Какие API функции используются для извлечения ресурсов?

Лабораторная работа №5

«Создание многопоточных приложений в ОС Windows»
Концепция потоков

Поток (thread) — это объект операционной системы, который представляет собой последовательность (поток выполнения) команд программы внутри определенного процесса. Понятию поток соответствует последовательный переход процессора от одной команды к другой. Каждое приложение Win32 имеет, по крайней мере, один поток, обычно называемый первичным, или главным, но приложения имеют право создавать дополнительные потоки, предназначенные для выполнения других задач.

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

Потоки никогда не поддерживались в среде 16-разрядной Windows. Это означает, что ни одна 32-разрядная программа Delphi, написанная с использованием потоков, никогда не будет совместимой с Delphi 1. Данный момент обязательно нужно учитывать при разработ­ке приложений, предназначенных для работы на обеих платформах.

Типы многозадачности

 

Понятие потока во многом отличается от многозадачности, поддерживаемой в среде 16-разрядной Windows. Возможно, Вам приходилось слышать, что Win32 называ­ют операционной системой с приоритетной (preemptive), или вытесняющей, многозадачностью, а Windows 3.1 — средой с кооперативной многозадачностью (cooperative multitasking).

В чем же разница? В среде приоритетной многозадачности управление возложено на операционную систему — именно она отвечает за то, какой поток должен выполняться в данный момент времени (и обладать более высоким приоритетом). Когда первый поток приостанавливается системой ради передачи второму потоку нескольких циклов работы процессора, то о первом потоке говорят, что он выгружен. И если к тому же окажется, что первый поток выполняет бесконечный цикл, то, как правило, это не приводит к трагической ситуации, поскольку операционная система будет продолжать выделение процессорного времени для всех других потоков.

В среде Windows 3.1 ответственность за возвращение управления операционной системе по завершении выполнения приложения лежит целиком на разработчике. Поэтому, когда приложению не удается корректно завершить работу и вернуть управление операционной системе, кажется, что операционная система " зависает" — все хорошо знакомы с такой печальной ситуацией. Если вдуматься, то это может пока­заться даже забавным — устойчивость работы всей системы 16-разрядной Windows полностью зависит от поведения всех ее приложений, которые должны самостоятельно защитить себя от попадания в бесконечные циклы, замкнутую цепь рекурсии и другие неприятные ситуации. А поскольку все приложения для достижения корректной работы системы должны работать согласованно, этот тип многозадачности называется кооперативным.

Использование многопоточности в приложениях Delphi

 

Итак, давайте определимся, что под словом " поток" мы подразумеваем именно Thread, который еще имеет название " нить". Нередко встречаются на форумах мнения, что потоки не нужны вообще, любую программу можно написать так, что она будет замечательно работать и без них. Конечно, если не делать ничего серьёзней " Hello World" это так и есть, но если постепенно набирать опыт, рано или поздно любой начинающий программист упрётся в возможности " плоского" кода, возникнет необходимость распараллелить задачи. А некоторые задачи вообще нельзя реализовать без использования потоков, например работа с сокетами, COM-портом, длительное ожидание каких-либо событий, и т.д.

Всем известно, что Windows система многозадачная. Попросту говоря, это означает, что несколько программ могут работать одновременно под управлением ОС. Все мы открывали диспетчер задач и видели список процессов. Процесс - это экземпляр выполняемого приложения. На самом деле сам по себе он ничего не выполняет, он создаётся при запуске приложения, содержит в себе служебную информацию, через которую система с ним работает, так же ему выделяется необходимая память под код и данные. Для того, чтобы программа заработала, в нём создаётся поток. Любой процесс содержит в себе хотя бы один поток, и именно он отвечает за выполнение кода и получает на это процессорное время. Этим и достигается мнимая параллельность работы программ, или, как её еще называют, псевдопараллельность. Почему мнимая? Да потому, что реально процессор в каждый момент времени может выполнять только один участок кода. Windows раздаёт процессорное время всем потокам в системе по очереди, тем самым создаётся впечатление, что они работают одновременно. Реально работающие параллельно потоки могут быть только на машинах с двумя и более процессорами.

Для создания дополнительных потоков в Delphi существует базовый класс TThread, от него мы и будем наследоваться при реализации своих потоков. Для того, чтобы создать " скелет" нового класса, можно выбрать в меню File - New - Thread Object, Delphi создаст новый модуль с заготовкой этого класса. Для наглядности, опишем его в модуле формы. Как Вы видите, в этой заготовке добавлен один метод - Execute. Именно его нам и нужно переопределить, код внутри него и будет работать в отдельном потоке. И так, попробуем написать пример - запустим в потоке бесконечный цикл:

TNewThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;


var
Form1: TForm1;

implementation

{$R *.dfm}

{ TNewThread }

procedure TNewThread.Execute;
begin
while true do {ничего не делаем};
end;

procedure TForm1.Button1Click(Sender: TObject);
var
NewThread: TNewThread;
begin
NewThread: =TNewThread.Create(true);
NewThread.FreeOnTerminate: =true;
NewThread.Priority: =tpLower;
NewThread.Resume;
end;

Запустите пример на выполнение и нажмите кнопку. Вроде ничего не происходит - форма не зависла, реагирует на перемещения. На самом деле это не так - откройте диспетчер задач и вы увидите, что процессор загружен полностью. Сейчас в процессе вашего приложения работает два потока - один был создан изначально, при запуске приложения. Второй, который так грузит процессор - мы создали по нажатию кнопки. Итак, давайте разберём, что же означает код в Button1Click:

 

NewThread: =TNewThread.Create(true);

тут мы создали экземпляр класса TNewThread. Конструктор Create имеет всего один параметр - CreateSuspended типа boolean, который указывает, запустить новый поток сразу после создания (если false), или дождаться команды (если true).

 

New.FreeOnTerminate: = true;

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

 

NewThread.Priority: =tpLower;

Свойство Priority, если вы еще не догадались из названия, устанавливает приоритет потока. Каждый поток в системе имеет свой приоритет. Если процессорного времени не хватает, система начинает распределять его согласно приоритетам потоков. Свойство Priority может принимать следующие значения:

  • tpTimeCritical - критический
  • tpHighest - очень высокий
  • tpHigher - высокий
  • tpNormal - средний
  • tpLower - низкий
  • tpLowest - очень низкий
  • tpIdle - поток работает во время простоя системы

Ставить высокие приоритеты потокам не стоит, если этого не требует задача, так как это сильно нагружает систему.

 

NewThread.Resume;

Ну и собственно, запуск потока.

Это был пример создания потоков. Но не всё так просто. Казалось бы - пишем любой код внутри метода Execute и всё, а нет, потоки имеют одно неприятное свойство - они ничего не знают друг о друге. Это значит, допустим, Вы пытаетесь из другого потока изменить свойство какого-нибудь компонента на форме. Как известно, VCL однопоточная, весь код внутри приложения выполняется последовательно. Допустим, в процессе работы изменились какие-то данные внутри классов VCL, система отбирает время у основного потока, передаёт по кругу остальным потокам и возвращает обратно, при этом выполнение кода продолжается с того места, где приостановилось. Если мы из своего потока что-то меняем, к примеру, на форме, задействуется много механизмов внутри VCL (напомним, выполнение основного потока пока " приостановлено"), соответственно за это время успеют измениться какие-либо данные. И тут вдруг время снова отдаётся основному потоку, он спокойно продолжает своё выполнение, но данные уже изменены! К чему это может привести - предугадать нельзя. Вы можете проверить это тысячу раз, и ничего не произойдёт, а на тысяча первый программа рухнет. И это относится не только к взаимодействию дополнительных потоков с главным, но и к взаимодействию потоков между собой. Писать такие ненадёжные программы конечно нельзя.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.