Как предотвратить блокировку пользовательского интерфейса при отображении второй формы? - PullRequest
2 голосов
/ 02 мая 2009

У меня есть программа чата, написанная на Delphi7. В качестве специального «эффекта» мы показываем несколько пулевых отверстий при воспроизведении определенного звукового файла выстрела. Мы сделали это, нарисовав новую форму в виде файла изображения bmp с пулевым отверстием, с временной задержкой в ​​несколько секунд, чтобы он был виден, а затем исчез.

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

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

Ответы [ 7 ]

3 голосов
/ 02 мая 2009

Трудно сказать, не видя код и не зная точно, как вы открываете / загружаете вторую форму, но звучит так, как будто вы открываете их с помощью ShowModal, который блокирует родительскую форму, пока модальная форма не вернет результат.

Если это так, то вы можете просто открыть его с помощью метода Show, а затем снова установить фокус на основную форму следующим образом.

procedure TForm1.Button1Click(Sender: TObject);
   var obj:TForm2;
begin
    obj := TForm2.Create(nil);
    try
        obj.FormStyle := fsStayOnTop;
        obj.show;
        Self.SetFocus; //set focus back to the form1
    except
        FreeAndNil(obj);
    end;
end;

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

2 голосов
/ 02 мая 2009

Наложение графики на форму не совсем тривиально, но я думаю, что именно для этого предназначена TCustomTransparentPanel (имя из памяти).

Но в любом случае, это не должно замедлять или останавливать программу.

1 голос
/ 04 мая 2009

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

  1. Когда должна появиться пуля, вы делаете изображение видимым и выводите на передний план
  2. Запустить таймер на две секунды и дать команду элементу управления изображением обновить
  3. Когда таймер сработает, скройте изображение маркера

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

  • Через 0 секунд сделать изображение видимым
  • Через 1,5 секунды заменить изображение на блеклую версию картинки
  • Через 2 секунды скройте картинку

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

0 голосов
/ 06 мая 2009

См. http://msdn.microsoft.com/en-us/library/dd183353(VS.85).aspx, это хороший пример API-вызовов для альфа-смешивания растровых изображений вместе. Для каждого кадра анимации вам, вероятно, потребуется получить копию изображения, представляющего ваш главный экран, а затем смешать его с соответствующими символами на соответствующем уровне прозрачности.

Как уже сообщалось ранее, вы можете выполнять Application.ProcessMessages несколько раз, хотя я предпочитаю делать это задом наперед и использовать PostMessage для запуска следующего кадра анимации.

Вы будете использовать ProcessMessages в цикле, но этот вызов может вызвать другие вещи, пока вы находитесь в этом цикле - перемещение окна, сворачивание, закрытие или запуск события анимации снова - до завершения первой анимации. Это все нормально, если вы помните, что не всегда работаете в рамках только вашего цикла.

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

0 голосов
/ 05 мая 2009

Если анимация пулевых отверстий записана в виде цикла, который выполняется до тех пор, пока не будет выполнено, то это может быть проблемой. Если это так, попробуйте вставить Application.ProcessMessages где-нибудь в цикле, чтобы позволить другим вещам происходить во время анимации.

0 голосов
/ 05 мая 2009

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

Определение формы:

  TForm1 = class(TForm)
    btnTurnOn: TButton;
    ListBox1: TListBox;
    btnTurnOff: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnTurnOnClick(Sender: TObject);
    procedure btnTurnOffClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    F:TForm;
    Bullet:TBitmap;
    x,y:integer;

    procedure SubFormPaint(Sender: TObject);
  end;

Код:

procedure TForm1.btnTurnOnClick(Sender: TObject);
begin
if F=nil then
   begin
   F:=TForm.Create(self);
   F.Parent:=self;
   F.FormStyle:=fsStayOnTop;
   F.BorderStyle:=bsNone;
   F.Left:=x;
   F.Top:=y;
   F.Width:=Bullet.Width;
   F.Height:=Bullet.Height;
   F.OnPaint:=Self.SubFormPaint;
   F.Show;
   end
else
   begin
   inc(x,5);
   inc(y,5);
   F.Left:=x;
   F.Top:=y;
   F.Invalidate;
   end;
end;

procedure TForm1.btnTurnOffClick(Sender: TObject);
begin
F.Free;
F:=nil;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
F:=nil;
Bullet:=TBitmap.Create;
Bullet.LoadFromFile('C:\source\glyfx\glyfx\Emoticon\BMP\16x16\wink_16.bmp');
x:=1;
y:=1;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
Bullet.Free;
end;

procedure TForm1.SubFormPaint(Sender: TObject);
begin
if F<>nil then
   F.Canvas.Draw(1,1,Bullet);
end;
0 голосов
/ 03 мая 2009

Я считаю, что необходимо использовать метод SetWinRegion, чтобы нарисовать контур вокруг "пулевого отверстия". Таким образом их можно будет щелкнуть через, но сами отверстия будут плавать сверху (при условии, что используется предыдущий ответ fsStayOnTop).

Даже флэш-изображение потребовало бы формы некоторого типа, чтобы действовать в качестве контейнера для изображения. Все сводится к созданию окна и удалению изображения в это окно. Он не должен «блокировать» экран, если вы установите его всегда сверху и просто «ПОКАЗАТЬ» его (не ShowModal), он должен появиться и всплыть. Затем я бы использовал таймер, чтобы контролировать, когда он будет уничтожен. Преимущество SetWinRegion заключается в том, что вы можете создать окно неправильной формы, и единственное место, в котором пользователь не сможет щелкнуть, - это часть вашего окна, в которой находится фактическая форма (внутри области). *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...