在N8的桌面上制作Qt应用程序的Home Screen widget
引言[edit | edit source]
想让自己做的Qt应用程序在N8的桌面上也有一席之地吗?想让自己做的Qt应用程序能够随着开机自动启动吗?
听起来很有诱惑力的样子。
目前Qt for Symbain中还没有提供Homescreen API,不过更加遗憾的是Symbain^3 SDK 中已经不提供Homescreen Publishing Api了。 庆幸的是N8真机上还有hswidgetpublisher.lib的库。因此如果没有什么特殊需要,我们可以直接在N97 SDK 上开发我们的Qt程序(N97 SDK 上有Homescreen Publishing Api),然后直接在N8上运行。
本文向大家提供了一个Qt wrapper (用Qt封装了Symbain Homescreen Publishing Api)和一个应用实例。大家可以按照例子程序的样子,制作自己程序的Home Screen widget。 源码和例子程序可通过本文末尾所附链接下载。
准备开发环境[edit | edit source]
首先需要有一个N97 SDK,然后是Qt for Symbain的某个版本。具体安装流程请参阅Qt 开发中的相关文章。 本文样例程序所用开发环境为N97 SDK 1.0,Qt for Symbain 4.6.3。
加入API源码[edit | edit source]
解压附件之后,大家会发现一个叫HomeScreenWidget的文件,此文件夹中的四个文件都属于wrapper部分,也就是API部分。大家将其加入自己的工程就可以直接使用了。大家也可以对其进行修改,从而满足自己特殊的需求。
具体的注意事项以及函数功能,在源文件中都做了注释,请大家直接看源代码,代码还是相当清晰明了的。
下面只挑一些重点为大家解释一下:
在正确的时间publishHsWidget[edit | edit source]
看代码之前,大家先明确一个问题,在N8上必须要在home screen widget 被添加到桌面之后再调用publishHsWidget才会成功,否则必然会失败。但是在N97上这样做却是可以的。
但无论如何在home screen widget 被添加到桌面之后再调用publishHsWidget是最安全可靠的,在N8 和N97上都是成功的。
//------------------------------------------------------------------
//Defines the events that may take place for a homescreen widget.
/*
enum EEvent
{
EUnknown = 0, ///< Unknown event: Means that event has not been defined.
EActivate = 1, ///< Activation event: Means that widget has been added to HS as content.
EDeactivate = 2, ///< Deactivation event: Means that widget has been removed frm.
ESuspend = 3, ///< Suspension event: Means that HS reading widget data is suspended.
EResume = 4 ///< Resume event. Means that HS reading widget data is resumed.
};
- ///-----------------------------------------------------------------
void HomeScreenWidget::Private::handleEvent(std::string widgetName, Hs::IHsDataObserver::EEvent event)
{
Q_UNUSED(widgetName);
switch(event)
{
case Hs::IHsDataObserver::EActivate:
{
//we'd better or must publishHsWidget here.
//only this moment and afer this moment publishHsWidget can be succefull on N8,
//otherwise it must be failed, because of
//"translation from std exception "class exception" to -2"
//"CActiveScheduler::RunIfReady() returned error: -2"
m_publisher->publishHsWidget(hsWidget());
emit activated();
break;
}
case Hs::IHsDataObserver::EDeactivate:
emit deactivated();
break;
case Hs::IHsDataObserver::ESuspend:
emit suspended();
break;
case Hs::IHsDataObserver::EResume:
{
m_publisher->publishHsWidget(hsWidget());
emit resumed();
break;
}
default:
break;
}
}
这是一个通过Observer模式实现的回调函数。事件到达之后会来到这里进行处理。
其中EActivate的意思是说此时Widget已经被添加到桌面(Home Screen)了,这里要特别注意的是,如果我们的目标设备是N8,我们最好或者是必须在这里调用m_publisher->publishHsWidget(hsWidget());
因为其一:如果我们不在这里进行publish,而是在Widget还没有被用户添加到桌面之前,那么在N8上必然要出现如下的错误:
translation from std exception "class exception" to -2
CActiveScheduler::RunIfReady() returned error: -2
其二:如果我们不在这里进行publish,那么也就失去了制作Home Screen widget的意义。因为我们通常希望的是当我们自己的Qt程序一运行,或者运行之后又退出了,那么用户经过如此试用之后发现我们的程序还不错,想添加到自己的桌面上,当用户把我们的HomeScreen widget添加到桌面的时候,用户希望看到的是一个已经制作好了的、已经可以显示图片和文字的HomeScreen widget。如果不在这里publish的话,那么用户看到的将是一片空白(就是一个灰条,上面什么都没有,即使在程序初始化的时候已经set了图片和文字)。
使Home Screen widget 响应点击事件[edit | edit source]
//-------------------------------------------------------------------
//To be noted that if the publisher application is not running the Homescreen
//application will start the publisher. The subsequent events will be sent to
//the now running publisher application.
//-------------------------------------------------------------------
void HomeScreenWidget::Private::handleItemEvent(std::string widgetName, std::string item, Hs::IHsDataObserver::EItemEvent event)
{
// add this to bring application to foreground
TApaTask task( CEikonEnv::Static()->WsSession() );
task.SetWgId(CEikonEnv::Static()->RootWin().Identifier());
task.BringToForeground();
Q_UNUSED(widgetName);
if(event != Hs::IHsDataObserver::ESelect)
{
qWarning() << (Q_FUNC_INFO) << "Unknown event" << static_cast<int>(event) << "on item" << QString::fromStdString(item);
return;
}
if(item == "image1") { emit itemActivated(HomeScreenWidget::ImageItem); return; }
if(item == "text1") { emit itemActivated(HomeScreenWidget::LineItem1); return; }
if(item == "text2") { emit itemActivated(HomeScreenWidget::LineItem2); return; }
if(item == "text3") { emit itemActivated(HomeScreenWidget::LineItem3); return; }
}
当Home Screen widget的某个item被选中的时候就会来到这个事件处理函数中。通常情况下我们希望的是跳转到或者启动这个Home Screen widget所关联的应用程序,因此我们在这里加上如上文所示的三行代码就可以了。
此外需要注意的是,如果应用程序此时没有启动,那么点击后widget会启动应用程序,并且接下来的事件就会被发送到这里。
启动时注册[edit | edit source]
通常情况下我们需要在程序启动的时候注册Home Screen widget,从而使得该widget可以被用户添加到Home Screen,如果该widget已经存在,则m_publisher会指向这个widget。
此外publisher也就是应用程序,是由其UID3所唯一标识的。
HomeScreenWidget::HomeScreenWidget(WidgetType widgetType, const QString& title, const QString& id, QObject *parent)
- QObject(parent)
, d(new Private(this))
{
d->m_widgetType = widgetType;
d->m_title = title;
d->m_id = id;
d->m_publisher = new Hs::HsWidgetPublisher(d);
connect(d, SIGNAL(activated()), SIGNAL(activated()));
connect(d, SIGNAL(deactivated()), SIGNAL(deactivated()));
connect(d, SIGNAL(suspended()), SIGNAL(suspended()));
connect(d, SIGNAL(resumed()), SIGNAL(resumed()));
connect(d, SIGNAL(itemActivated(HomeScreenWidget::Item)), SIGNAL(itemActivated(HomeScreenWidget::Item)));
//we should RegisterWidget at start up. the purpose is to make the widget available to the user for adding it to the home screen
//and let m_publisher ponit to the HS widget
RegisterWidget();
}
// -----------------------------------------------------------------------------
// RegisterWidget()
// Once registered the widget will become available to the user for adding it to
// the home screen. If the widget Id is already registered the m_publisher
// will now point to it. Also, note that the Home Screen Publishing API will
// record this application's UID3 as the publiser of this widget and based
// on this information the application will be started in the background if at
// any given time an event is due to be sent to it but the application is found
// not to be running.
// -----------------------------------------------------------------------------
void HomeScreenWidget::RegisterWidget()
{
d->RegisterWidget();
}
void HomeScreenWidget::Private::RegisterWidget()
{
m_publisher->createHsWidget(templateName(), m_title.toUtf8().constData(), m_id.toUtf8().constData());
}
在应用程序中使用API[edit | edit source]
在我们自己的Qt应用程序中使用这个API是非常简单的。
我们通常只需要在我们的构造函数中添加下面几行代码就可以为我们的程序创建一个Home Screen widget了:
m_hsWidget = new HomeScreenWidget(HomeScreenWidget::ImageWithTwoLines, "N8 Qt HSwidget", "0xe94c0fd3", this);
m_hsWidget->setImage("e:/images/logo.png");
m_hsWidget->setText(HomeScreenWidget::LineItem1, ui->line1->text());
m_hsWidget->setText(HomeScreenWidget::LineItem2, ui->line2->text());
HomeScreenWidget的第一个参数代表需要创建的widget的类型,共有5种类型可供选择:WideImage、ImageWithOneLine、ImageWithTwoLines、ImageWithThreeLines、ThreeTextLines。
HomeScreenWidget的第二个参数是给所创建的widget所取的名字,当我们在主屏中添加widget的时候就会看到备选项中有这个名字,比如例子程序中的叫“N8 Qt HSwidget”。
HomeScreenWidget的第三个参数是我们应用程序的UID3,也正是这个UID3把Home Screen widget和我们的应用程序关联了起来。
此外例子程序中还提供了一些额外功能,供大家测试使用。
同样的,在应用程序中我们绝对不能在Home Screen widget没有被添加到主屏上的时候进行update,也就是publishHsWidget。如何获得Home Screen widget是否在主屏上的信息呢?我们可以利用API所提供的一些signal来做。比如样例程序中使用了:
connect(m_hsWidget, SIGNAL(activated()), this, SLOT(enableUpdate()));
connect(m_hsWidget, SIGNAL(deactivated()), this, SLOT(disableUpdate()));
于是在程序运行当中就可以随时捕获到Home Screen widget的更新状态。
其他需要注意的地方[edit | edit source]
如果是在N97上测试,大家最好将程序编译成Release版的(或者如果非要编译Debug版的话就将程序的UID3的首位更改为‘A’),否则可能会出现程序无法启动的情况,在N8上就没有这种限制了。
应用程序截图[edit | edit source]
本代码已通过在N8和N97上的测试。
下面是样例程序在N8上的一些运行效果图,供大家参考:
N8 Qt HSwidget没有被添加到主屏上:
File:CannotUpdate.JPG
N8 Qt HSwidget现在在主屏上:
File:CanUpdate.JPG
主屏上的N8 Qt HSwidget:
File:Widget.JPG
下载源码和样例程序[edit | edit source]
相关链接[edit | edit source]
- Qt 开发
- 感谢Posting to the N97 home screen from Qt/S60提供的程序,不过该程序只能在N97上正常运行,在N8上运行会有一些问题。