четверг, 25 октября 2012 г.

Интеграция Silverlight в Qt приложения (пример использования)

В прошлой статье об интеграции Silverlight роликов в приложения на Qt, я описал библиотеку Qtitan Multimedia, с помощью которая оная интеграция и выполняется.
Ниже я приведу практический пример использования библиотеки Qtitan Multimedia.
Пример использования
В качестве примера создадим интерактивный баннер на Silverlight и подружим его с Qt приложением. Из приложения мы будем передавать наше имя в Silverlight и оно будет в нем использоваться. А в ролике мы предоставим возможность пользователю проголосовать за любимую технологию и передадим результаты голосования в приложение.

Для этого нам понадобятся:
  1. Microsoft Visual Studio с установленным пакетом Silverlight Tools.
  2. Qt последней версии. Можно использовать бесплатную OpenSource версию, собранную в debug и release версиях.
  3. Qtitan Multimedia. Можно использовать демо версию, которую можно скачать с сайта http://devmachines.com

Рекомендуемый порядок установки:

  1. Устанавливаем Microsoft Visual Studio.
  2. Устанавливаем  Silverlight Tools.
  3. Скачиваем и собираем Qt с помощью компилятора nmake от Visual Studio.
  4. Скачиваем и устанавливаем Qtitan. Устанавливать демо желательно в папку без пробелов, т.е. не в Program Files, а, например, в c:\qtitan.
Естественно, если у вас уже есть VS и собранная под нее Qt, то вам достаточно установить Silverlight Tools и Qtitan.

Создаем Silverlight ролик
Запускаем Microsoft Visual Web Developer 2008. Создадим новый проект через меню File->New Project... В диалоге New Project в списке Project types выберем Visual C# -> Silverlight.

Пример для VS 2008
Следующим шагом нас спросят, создавать ли тестовое приложение ASP.NET, в которое будет встраиваться ролик. Ответим положительно. Visual Studio будет создавать локальный веб-сервер на localhost, размещать на нем страничку со встроенным роликом так, что мы сразу сможем увидеть все сделанные изменения.
Итак,  у нас в солюшене два проекта, собственно сам ролик и тестовое приложение.

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


 <Grid x:Name="LayoutRoot">
   <Grid.Background>
     <LinearGradientBrush>
       <LinearGradientBrush.GradientStops>
         <GradientStop Offset="0" Color="Yellow" />
         <GradientStop Offset="1" Color="Red"/>
       </LinearGradientBrush.GradientStops>
     </LinearGradientBrush>
   </Grid.Background>
 </Grid>


И удалим свойство Background="White", задающее белый цвет для фона страницы. Теперь наша страница имеет градиентную заливку, от жёлтого к красному, в качестве фона.  Также мы зададим стандартный размер баннера 468 на 60 в теге UserControl.
Теперь вставим надпись, в которой будет отображаться имя пользователя, которое он нам сообщит из Qt приложения.
Справа разместим пару элементов управления Radio Button для голосования за любимую технологию.

Цель нашего баннера проста: поздороваться с пользователем и дать возможность проголосовать за любимую технологию. Выбор технологии будет отправлен в Qt приложение.
Ниже приведен полный XAML код нашего баннера.


<UserControl x:Class="Banner.Page"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Width="468" Height="60">
 <Grid x:Name="LayoutRoot">
   <Grid.Background>
     <LinearGradientBrush>
       <LinearGradientBrush.GradientStops>
         <GradientStop Offset="0" Color="Yellow" />
         <GradientStop Offset="1" Color="Red"/>
       </LinearGradientBrush.GradientStops>
     </LinearGradientBrush>
   </Grid.Background>
   <Grid.RowDefinitions>
     <RowDefinition Height = "25" />
     <RowDefinition Height = "15" />
     <RowDefinition Height = "20"/>
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
     <ColumnDefinition Width="150" />
     <ColumnDefinition Width="350"/>
   </Grid.ColumnDefinitions>
   <TextBlock Width="100"
         Height="20"
         Text="Hello,"
         Grid.Row="1" />
   <TextBlock x:Name="textName"
         Width="100"
         Height="30"
         Text="UserName"
         Grid.Row="2" />
   <TextBlock Text="Please vote for your favorite technology"
      Grid.Row="0"
         Grid.Column="1" />
   <RadioButton x:Name="radFlash"
          Content="Adobe Flash"
       Grid.Row="1" Grid.Column="1" />
   <RadioButton x:Name="radSilverlight"
          Content="Microsoft Silverlight" Grid.Row="2" Grid.Column="1" />
 </Grid>
</UserControl>


В этом коде мы добавляем сетку (Grid), размечаем ее и вставляем элементы управления.
Откомпилируем данный код нажав F5. В итоге будет создан файл banner.xap, который и есть наш Silverlight ролик. Размер его меньше 5 Кб. Позже мы поместим этот файл в ресурсы нашего Qt приложения.

Создаем Qt приложение
Начнем новый проект Banner. Создадим отдельную папку под проект и поместим в нее файл banner.pro:


TEMPLATE = app
CONFIG += msvc2008
QTITANDIR = $$(QTITANDIR)
include($$QTITANDIR/src/shared/shared.pri)
DESTDIR = $$QTITANDIR/lib
DLLDESTDIR = $$QTITANDIR/bin

CONFIG(msvc2008):DESTDIR = $$member(DESTDIR, 0)_msvc2008
CONFIG(msvc2008):DLLDESTDIR = $$member(DLLDESTDIR, 0)_msvc2008

HEADERS = mainwindow.h
SOURCES = main.cpp \
             mainwindow.cpp
RESOURCES   = banner.qrc

Проект составлен на основе примера, поставляемого с Qtitan. Вы можете найти примеры в папке Qtitan/demos/media. В данном случае мы используем пример hellosilverlight за основу нашего проекта.
Добавим наш Silverlight ролик banner.xap в качестве ресурса приложения.
Для этого в папке проекта создадим папку res и поместим в нее файл banner.xap. В папке проекта создадим файл banner.qrc:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
 <file>res/banner.xap</file>
</qresource>
</RCC>

Добавим в папку проекта файл main.cpp:
#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
 QApplication app(argc, argv);
 MainWindow window;
 window.show();
 return app.exec();
}
Это стандартный файл main.cpp, создающий экземпляр QApplication и вызывающий главное окно MainWindow приложения.
Теперь напишем файлы mainwindow.h и mainwindow.cpp.
В файл mainwindow.h подключим файл QtitanMM.h:
#include <QtitanMM.h>
И добавим указатель на Qtitan::Silverlight в защищенную часть класса MainWindow. Заготовка класса MainWindow пока выглядит так (файл mainwindow.h):



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLineEdit>
#include <QtitanMM.h>

class MainWindow : public QMainWindow
{
 Q_OBJECT
public:
 MainWindow(QWidget *parent = 0);
protected slots:
 void clickButton();
 void getUrl(NPluginStreamParameters& parameters);
protected:
 Qtitan::Silverlight * silverlight_;
 QLineEdit * edtName_;
};
#endif //MAINWINDOW_H

Начальная реализация класса (файл mainwindow.cpp):

#include <QtGui>
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
 // Центральный объект
 QWidget * widget = new QWidget(this);
 QVBoxLayout * vLayout = new QVBoxLayout;
 widget->setLayout(vLayout);
 setCentralWidget(widget);

 // Создаем виджет для ролика
 silverlight_ = new Qtitan::Silverlight(widget);
 // Устанавливаем размер
 silverlight_->setMinimumSize(468, 60);
 silverlight_->setSource("banner.xap");
 // Задаем соединение с роликом
 connect(silverlight_, SIGNAL(getUrl(NPluginStreamParameters&)),
   this, SLOT(getUrl(NPluginStreamParameters&)));
 // Активируем ролик
 silverlight_->setActive(true);
 // Проверяем результат активации
 if (!silverlight_->isActive())
 {
  // Если ролик неактивен собщаем об этом
  QMessageBox::about(this, tr("Hello, Silverlight!"),
tr("The Microsoft Silverlight is not installed at your PC."));
 }
 // Дополнительные элементы управления
 QLabel   * lblName = new QLabel("Name: ", this);
 edtName_ = new QLineEdit(this);
 QPushButton * btnName = new QPushButton("Name", this);
 btnName->setMaximumWidth(120);

 // Компонуем объекты
 QHBoxLayout * hLayout = new QHBoxLayout;
 hLayout->addWidget(lblName);
 hLayout->addWidget(edtName_);

 vLayout->addWidget(silverlight_);
 vLayout->addLayout(hLayout);
 vLayout->addWidget(btnName, 0, Qt::AlignRight);
 vLayout->addStretch();
 // Соединение на кнопку
 connect(btnName, SIGNAL(clicked()), this, SLOT(clickButton()));
}

void MainWindow::getUrl(NPluginStreamParameters& parameters)
{
 QFile* data = new QFile(":/res/banner.xap");
 data->open(QIODevice::ReadOnly);
 parameters.setIODevice(data);
}

Здесь мы создали проект нашего приложения: сверху баннер, чуть ниже поле ввода для ввода имени и кнопка Name, нажатие которой будет отправлять наше имя в баннер.
Особое внимание стоит уделить строке связывания компонента Qtitan::Silverlight непосредственно с роликом Silverlight. Связь осуществляется стандартным механизмом слот/сигнал:
 connect(silverlight_, SIGNAL(getUrl(NPluginStreamParameters&)),
   this, SLOT(getUrl(NPluginStreamParameters&)));


Через эту связь экземпляр Qtitan::Silverlight получает доступ к ресурсам нашего ролика.  Слот getUrl(NPluginStreamParameters&) получает ссылку на  объект, в который он передает данные ролика.

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


Теперь напишем обработчик для кнопки btnName, чтобы по нажатию введенный текст передавался бы в Silverlight ролик.
Добавим коннект для кнопки в конструктор MainWindow:

connect(btnName, SIGNAL(clicked()), this, SLOT(clickButton()));

И напишем код обработчика:

void MainWindow::clickButton()
{
 //Получаем доступ к функциям ролика
 QScriptValue silverlightObject = silverlight_->pluginScriptValue();
 //Вызываем функция ролика Silverlight и передаем ей в качестве параметра
 //текст из поля ввода edtName_
 QScriptValue content = silverlightObject.property("content");
 QScriptValue silverlightForm = content.property("BannerForm");
 QScriptValue func = silverlightForm.property("SetUserNameMethod");
 func.call(silverlightForm, QScriptValueList() << edtName_->text());
}

Здесь мы фактически вызываем JavaScript код silverlightObject.content.BannerForm.SetUserNameMethod("text");
И, в принципе, мы могли бы вызвать его сразу, используя метод evaluate() класса QScriptEngine.
Также не забудем объявить слот clickButton() в закрытой части класс MainWindow.


protected slots:
 void clickButton();


Чтобы данный код заработал, в ролике Silverlight должны быть зарегистрирован объект BannerForm и метод SetUserNameMethod.
Нам нужно вернуться в проект Silverlight ролика и открыть страницу Page.xaml.cs.
 


Отредактируем код страницы следующим образом.
Во-первых, добавим строку для доступа к браузеру
using System.Windows.Browser;
Во-вторых, перед объявлением класса Page вставим строку
[ScriptableType]
Это нужно для того, чтобы можно было зарегистрировать объект BannerForm.
Сама регистрация осуществляется в конструкторе класса Page.
HtmlPage.RegisterScriptableObject("BannerForm", this);
Кроме того нужно зарегистрировать метод SetUserNameMethod. Полный код страницы Page.xaml.cs приведен ниже.
 

using System.Windows.Browser;
namespace banner
{
 [ScriptableType]
 public partial class Page : UserControl
 {
   public Page()
   {
     InitializeComponent();
     HtmlPage.RegisterScriptableObject("BannerForm", this);
   }
   [ScriptableMember]
   public void SetUserNameMethod(string text)
   {
     textName.Text = text;
   }
 }
}

Откомпилируем проект и скопируем полученный файл banner.xap в ресурсы Qt приложения. Пересоберем приложение и запустим. Теперь, по нажатию кнопки, наше имя, введенное в поле ввода edtName_, будет передано в ролик и будет там отражено.

Теперь нам нужно получить результаты голосования из Silverlight ролика.
Снова нам придется вернуться к проекту Silverlight ролика и внести в него изменения.
Во-первых, нам нужно определить обработчики событий для элементов RadioButton.
Определим обработчики в XAML коде:


<RadioButton x:Name="radFlash"
   Content="Adobe Flash"
   Grid.Row="1" Grid.Column="1"
   Checked="Flash_Click"/>
<RadioButton x:Name="radSilverlight"
      Content="Microsoft Silverlight"
   Grid.Row="2" Grid.Column="1"
   Checked="Silverlight_Click"/>


И напишем для них код в файле Page.xaml.cs в теле класса Page:

private void Flash_Click(object sender, RoutedEventArgs e)
{
  HtmlPage.Window.Invoke("ShowCustomMessage", "I vote for Adobe Flash!");
}
private void Sliverlight_Click(object sender, RoutedEventArgs e)
{
  HtmlPage.Window.Invoke("ShowCustomMessage", "I vote for Microsoft Silverlight!");
}

Т.е. ролик обращается к некой функции ShowCustomMessage, которая выглядит для него как обычная функция JavaScript. На самом деле, эта функция определена в нашем Qt приложении и мы зарегистрируем ее в ролике прямо из него.
Скомпилируем ролик и добавим его в ресурсы приложения.
Откроем наш Qt проект и добавим в конструктор класса MainWindow строку регистрации функции ShowCustomMessage:


silverlight_->registrScriptableFunction("ShowCustomMessage", ShowCustomMessage);

И определим саму функцию ShowCustomMessage:

QScriptValue MainWindow::ShowCustomMessage(QScriptContext* context, QScriptEngine *)
{  
 QMessageBox::information(qApp->activeWindow(), "Vote"
context->argument(0).toString());
 return QScriptValue();

}


В заголовочном файле mainwindow.h функцию следует объявить статической:

static QScriptValue ShowCustomMessage(QScriptContext *, QScriptEngine *);

Запускаем наше приложение и голосуем за Silverlight!
Заключение
Вот так просто, используя Qtitan Multimedia, мы смогли организовать взаимодействие Qt приложения с роликом Silverlight.
В следующий раз я расскажу об интеграции в Qt приложение роликов Adobe Flash.
До скорых встреч.


Комментариев нет:

Отправить комментарий