Модераторы: Snowy, MetalFan, bems, Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Нажатие нескольких клавиш. Многопоточность 
V
    Опции темы
boobie
Дата 23.5.2013, 08:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Здравствуйте! Как заставить программу понимать одновременное нажате двух и более клавиш? Т.е. задача, например, такая: 9 (например) Label-ов, при нажатии на клавишу "1" - происходит 
Код

label1.Caption:=label1.Caption+'1';

при нажатии  на "2":
Код

label2.Caption:=label2.Caption+'2';

и так далее... При одновременном нажатии на 1 и 3 и 6, например, к соответствующему label-у "прибавляется" 1, 3, 6.
Вот код моего решения на примере двух label-ов:
Код

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, unit2, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  p1,p2:classpot;
implementation

{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
p1.Terminate;
p2.Terminate;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
p1:=classpot.Create(true);
p2:=classpot.Create(true);

p1.i:=1;
p2.i:=2;

p1.Priority:=tpnormal;
p2.Priority:=tpnormal;

p1.Start;
p2.Start;
end;
end.

Код

unit Unit2;

interface

uses
  System.Classes, winapi.windows;

type
  classpot = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  public
    i:integer;
  end;

implementation

uses Unit1;

{ classpot }

procedure classpot.Execute;
begin
  { Place thread code here }
while terminated=false do
begin
if i=1 then
  if getasynckeystate($31)<>0 then
  form1.label1.Caption:=form1.label1.Caption+'1';
  sleep(200);
if i=2 then
  if getasynckeystate($32)<>0 then
  form1.label2.Caption:=form1.label2.Caption+'2';
  sleep(200);
end;
end;

end.

Я создал 2 потока, каждый поток использует функцию getasynckeystate() чтобы определить клавишу, нажатую в данный момент. Если нажата нужная - выполняем изменение строки.
1. Можно ли как-нибудь обойтись без getasynckeystate(), а только силами TForm1.FormKeyPress(Sender: TObject; var Key: Char)? Как сделать так, чтобы данная процедура стала как-бы многопоточной?
2. Обработать нажатие более 3 клавищ в данном случае не получится?
PM   Вверх
kami
Дата 23.5.2013, 09:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



SetWindowsHookEx + WH_KEYBOARD_LL + google должно помочь smile
Потоки не нужны. Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.

Добавлено через 1 минуту и 34 секунды
Цитата(kami @  23.5.2013,  09:12 Найти цитируемый пост)
SetWindowsHookEx 

это в том случае, если нужно ловить клавиши вне зависимости от активности своего окна.
PM MAIL WWW   Вверх
boobie
Дата 23.5.2013, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Я изучаю работу потоков... Сам придумываю такие вот задачки...
Цитата

Потоки не нужны. Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.

КАК? ПОЧЕМУ? И что, простейшие программки (любую простенькую игрушку, типа "Морской бой" или простейшую коммерческую прогу) писать на WinApi? На**** зачем тогда VCL нужна в таком виде?
PM   Вверх
kami
Дата 23.5.2013, 10:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(boobie @  23.5.2013,  09:28 Найти цитируемый пост)
КАК? ПОЧЕМУ? 

Я, наверное, не совсем корректно написал.
Потоки не нужны в рамках рассматриваемой задачи, тут вполне справится VCL-поток самостоятельно.
Если же рассматривать работу потоков "в общем", то мое высказывание 
Цитата(kami @  23.5.2013,  09:12 Найти цитируемый пост)
Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.

остается в силе.
В потоке можно осуществлять дополнительные действия, производить вычисления и т.д.
Результат работы потока (промежуточный или окончательный) в основной поток нужно сообщать (или забирать самостоятельно) каким-либо из потокобезопасных методов. Простейшим для начала будет TThread.Synchronize. Но он далеко не единственный и далеко не оптимальный. Хотя - смотря какая задача.

Добавлено через 1 минуту и 34 секунды
Цитата(boobie @  23.5.2013,  09:28 Найти цитируемый пост)
писать на WinApi?

Не надо так категорично smile VCL действительно придумали не зря, и не зря в нем есть Tthread  smile 
PM MAIL WWW   Вверх
Poseidon
Дата 23.5.2013, 10:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 9
Всего: 133



Цитата(boobie @ 23.5.2013,  09:28)
Я изучаю работу потоков... Сам придумываю такие вот задачки...
Цитата

Потоки не нужны. Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.

КАК? ПОЧЕМУ?

Начните изучение потоков вот с этой статьи: Многопоточность - как это делается в Дельфи


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
boobie
Дата 23.5.2013, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Т.е. для обращения к компонентам VCL нужно использовать один из способов синхронизации потоков? Исользовать метод Synchronize, критическую секцию или что-нибудь в этом роде?
Получается, что вся проблема состоит в синхронизации потоков? И только по этой причине нельзя использовать визуальные компоненты в многопоточном приложении?

Способов синхронизации потоков достаточно много...

Цитата

Начните изучение потоков вот с этой статьи.

Да, похоже это единственная статья о многопоточности на весь рунет.  smile Я ее прочитал. Не заметил, чтобы там говорилось о 
Цитата

Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.


Это сообщение отредактировал(а) boobie - 23.5.2013, 10:53
PM   Вверх
kami
Дата 23.5.2013, 12:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(boobie @  23.5.2013,  10:48 Найти цитируемый пост)
критическую секцию или что-нибудь в этом роде?

нет. Критические секции в этом случае, как и (например) мьютексы не пойдут. К визуальным компонентам можно обращаться только из своего, VCL- потока. Т.е. - Synchronize или (к примеру) собственные аналоги на Send|PostMessage. Я в последнее время перешел на SendMessageTimeout с SMTO_BLOCK.
PM MAIL WWW   Вверх
boobie
Дата 23.5.2013, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



kami, спасибо, теперь понятно. Т.е. Synchronize необходим для любого обращения к визуальному компоненту из потока. Критические секции, семафоры и мьютексы - синхронизация потоков.
Цитата

Я в последнее время перешел на SendMessageTimeout с SMTO_BLOCK. 

WinApi? Чем Synchronize так плох?

PM   Вверх
kami
Дата 23.5.2013, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(boobie @  23.5.2013,  12:32 Найти цитируемый пост)
Чем Synchronize так плох?

Он не позволяет передать параметры вызываемому.
А в SendMessage я могу запихать всё, что угодно, включая объекты.
Цитата(boobie @  23.5.2013,  12:32 Найти цитируемый пост)
WinApi? 

Смесь smile

Добавлено через 4 минуты и 51 секунду
Цитата(kami @  23.5.2013,  12:42 Найти цитируемый пост)
Он не позволяет передать параметры вызываемому.

да, и самое главное забыл - SMTO_BLOCK не допустит вложенного вызова, а с синхронайзом такое возможно.
PM MAIL WWW   Вверх
boobie
Дата 23.5.2013, 14:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Хорошо. А как заставить каждый поток обрабатывать нажатие клавиш? Только с помощью getasynckeystate() и других winapi функций?

Дело в том, что потоки будут обрабатывать любое нажате клавиши, вне зависимости от фокуса ввода.

Это сообщение отредактировал(а) boobie - 23.5.2013, 14:11
PM   Вверх
Poseidon
Дата 23.5.2013, 14:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 9
Всего: 133



Цитата(boobie @ 23.5.2013,  10:48)
Цитата

Начните изучение потоков вот с этой статьи.

Да, похоже это единственная статья о многопоточности на весь рунет.  smile Я ее прочитал. Не заметил, чтобы там говорилось о 
Цитата

Обращение к визуальным компонентам из потока = глюк, баг и иже с ними.


Очень плохо прочли, либо не внимательно. Еще раз просмотрите главу 3. И очень внимательно раздел "Дополнительные проблемы с VCL."

Судя по вопросам, Вы эту статью бегло просмотрели, а не прочли. Досканальное изучение этой статьи отбросит 99% возможных вопросов по потокам. И не нужно будет выдумывать нереальных задач. 


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
boobie
Дата 23.5.2013, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Да, только после публикации темы понял зачем нужен метод Synchronize.
Вот код с учетом ошибок и примененным методом Synchronize:
Код

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;


type
  clpot = class(TThread)

  private
    { Private declarations }
  protected
    procedure Execute; override;
    procedure uplabel;
  public
    lbl:tlabel;
    i:integer;
  end;

implementation


uses unit1;
{ clpot }
procedure clpot.uplabel();
begin
if i=1 then
lbl.Caption:=lbl.Caption+inttostr(1);
if i=2 then
lbl.Caption:=lbl.Caption+inttostr(2);
end;
procedure clpot.Execute;
begin
while terminated=false do
begin
if ((getasynckeystate($31)<>0) and (i=1)) or ((getasynckeystate($32)<>0) and (i=2)) then
begin
  synchronize(uplabel);
  sleep(200);
end;
end;
end;

end.

Код формы:
Код

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, unit2, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  p1,p2:clpot;
implementation

{$R *.dfm}



procedure TForm1.FormCreate(Sender: TObject);
begin
p1:=clpot.Create(true);
p2:=clpot.Create(true);

p1.lbl:=label1;
p2.lbl:=label2;

p1.i:=1;
p2.i:=2;

p1.Priority:=tpnormal;
p2.Priority:=tpnormal;

p1.Start;
p2.Start;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
p1.Terminate;
p2.Terminate;
end;

end.

Но вопросы остались без ответа smile
PM   Вверх
kami
Дата 24.5.2013, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(boobie @  23.5.2013,  14:57 Найти цитируемый пост)
Но вопросы остались без ответа

Без какого ответа? Да, в потоках неприменимы всякие OnKeyPress и т.п.
В той же статье пишется, что не стоит плодить потоки только ради потоков. 
Ну какой смысл в обработке несколькими потоками одного и того же? У каждого из них будет уникальный алгоритм обработки? Имхо, вполне достаточно будет VCL-потока и 
Цитата(kami @  23.5.2013,  09:12 Найти цитируемый пост)
SetWindowsHookEx + WH_KEYBOARD_LL + google

PM MAIL WWW   Вверх
boobie
Дата 25.5.2013, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Хорошо, все ясно. Просто я изучаю потоки, для наглядности решил сделать так...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1398 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.