1
0
mirror of https://gitee.com/drabel/LibQQt.git synced 2025-01-04 10:18:44 +08:00

add qqt widget click helper

This commit is contained in:
AbelTian 2018-05-17 14:35:17 +08:00
parent e009d47699
commit 11767f7b75
17 changed files with 507 additions and 58 deletions

View File

@ -6,4 +6,4 @@ TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = src/qqt.pro
#SUBDIRS += QQtExample.pro
SUBDIRS += QQtExample.pro

View File

@ -114,3 +114,4 @@ greaterThan(QT_MAJOR_VERSION , 4):SUBDIRS += demo/VegeTablesPrice
#SUBDIRS += demo/TouchMonitor
#SUBDIRS += demo/TouchMonitorServer
SUBDIRS += test/QQtWidgetClickHelperTest

View File

@ -103,11 +103,6 @@ contains (CONFIG, QQT_SOURCE_BUILDIN) {
#App修改源代码,Creator会自动qmake,启动qmake步骤PRILINK+POSTLINK
#App修改pro,必须手动qmake,Creator才会qmake,启动qmake步骤PRILINK+POSTLINK
#App必须注意,此处不再持续编译QQt.
#QQt持续编译配置开关
#CONFIG += continued_build
contains(CONFIG, continued_build){
system("touch $${QQT_SOURCE_ROOT}/frame/qqtapplication.cpp")
}
include ($${QQT_SOURCE_ROOT}/qqt_install.pri)
#in this pri use QQT_SDK_ROOT QQT_SDK_PWD QQT_LIB_PWD

View File

@ -1,4 +1,4 @@
#ifndef QQTCORE_H
#ifndef QQTCORE_H
#define QQTCORE_H
#include <QWidget>
@ -118,12 +118,13 @@ QQTSHARED_EXPORT void QQtSleep ( int millsecond );
#define pline() qDebug() << __FILE__ << __LINE__/*QString("%1").arg(__LINE__, 3, 10)*/ << __func__
#define perr(req, rsl) if(req == rsl) pline() << hex << rsl
#define ptime() pline() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz")
#define p2line() qDebug() << QString(__FILE__).split('/').last() << QString("%1").arg(__LINE__, 3, 10) << __func__
//-----------------------
#define perr(req, rsl) if(req == rsl) pline() << hex << rsl
#define pmeta(inst) pline() << inst->metaObject()->className()
#define pdebug() qDebug()
#define pdebugo() qDebug().nospace()
//-----------------------
#define pdebug_nospace() qDebug().nospace()
#define packline() pline() << qDebug().nospace()
QQTSHARED_EXPORT QByteArray& operator<< ( QByteArray& l, const quint8& r );

2
src/core/qqtevent.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "qqtevent.h"

66
src/core/qqtevent.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef QQTEVENT_H
#define QQTEVENT_H
#include <QEvent>
#include "qqt-qt.h"
#include <qqt-local.h>
class QQTSHARED_EXPORT QQtMouseEvent : public QMouseEvent
{
public:
QQtMouseEvent() :
QMouseEvent ( MouseButtonPress, QPointF(), QPointF(), QPointF(),
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier, Qt::MouseEventNotSynthesized ) {
}
virtual ~QQtMouseEvent() {}
public:
//设置
QQtMouseEvent& operator= ( const QMouseEvent& other ) {
QQtMouseEvent& ref = *this;
ref.setType ( other.type() );
ref.localPos() = other.localPos();
ref.windowPos() = other.windowPos();
ref.screenPos() = other.screenPos();
#ifndef QT_NO_INTEGER_EVENT_COORDINATES
ref.pos() = other.pos();
ref.globalPos() = other.globalPos();
#endif
ref.button() = other.button();
ref.buttons() = other.buttons();
ref.setModifiers ( other.modifiers() );
//source 无解
return ref;
}
//读取
#ifndef QT_NO_INTEGER_EVENT_COORDINATES
inline QPoint& pos() { return _l; }
inline QPoint& globalPos() { return _s; }
inline int& x() { return _l.rx(); }
inline int& y() { return _l.ry(); }
inline int& globalX() { return _s.rx(); }
inline int& globalY() { return _s.ry(); }
#endif
QPointF& localPos() { return l; }
QPointF& windowPos() { return w; }
QPointF& screenPos() { return s; }
inline Qt::MouseButton& button() { return b; }
inline Qt::MouseButtons& buttons() { return mouseState; }
//inline Qt::MouseEventSource& source() { return sou}
//inline Qt::MouseEventFlags& flags();
inline void setType ( const Type& _t ) { t = _t; }
protected:
QPoint _l, _w, _s;
};
#endif // QQTEVENT_H

View File

@ -161,6 +161,18 @@ DISTFILES += \
linux_write_ini.sh \
win_read_ini.bat
#################################################################
##QQt Lib工程持续编译
#################################################################
#如果不touch一下,资源文件改变不会引发编译,可是我们需要编译一下,不开持续编译,岂不是漏失?
#修改pro,如果不需要编译源文件,还是编译了一下,岂不是多余?
#权衡利弊,在qqt工程里开启开关.保证用户在编译源代码的时候,任何改动一定持续生效.
#依赖touch命令 :|
#QQt持续编译配置开关
CONFIG += continued_build
contains(CONFIG, continued_build){
system("touch $${PWD}/frame/qqtapplication.cpp")
}
#################################################################
##project environ

View File

@ -36,10 +36,12 @@ contains (QKIT_PRIVATE, WIN32||WIN64) {
#core
SOURCES += \
$$PWD/core/qqtcore.cpp \
$$PWD/core/qqtevent.cpp \
$$PWD/core/qqtdictionary.cpp \
$$PWD/core/qqtobjectmanager.cpp
HEADERS += \
$$PWD/core/qqtcore.h \
$$PWD/core/qqtevent.h \
$$PWD/core/qqtdictionary.h \
$$PWD/core/qqtobjectmanager.h

View File

@ -9,6 +9,7 @@ QQtWidget::QQtWidget ( QWidget* parent ) :
mClickHelper = new QQtWidgetClickHelper ( this );
installClickHelper();
mDefaultClickHelper = mClickHelper;
}
QQtWidget::~QQtWidget()
@ -224,3 +225,14 @@ void QQtWidget::installClickHelper()
connect ( mClickHelper, SIGNAL ( doubleClickWithPoint ( QPoint ) ), this, SIGNAL ( doubleClickWithPoint ( QPoint ) ) );
}
void QQtWidget::uninstallClickHelper()
{
disconnect ( mClickHelper, SIGNAL ( click() ), this, SIGNAL ( click() ) );
disconnect ( mClickHelper, SIGNAL ( longClick() ), this, SIGNAL ( longClick() ) );
disconnect ( mClickHelper, SIGNAL ( doubleClick() ), this, SIGNAL ( doubleClick() ) );
disconnect ( mClickHelper, SIGNAL ( clickWithPoint ( QPoint ) ), this, SIGNAL ( clickWithPoint ( QPoint ) ) );
disconnect ( mClickHelper, SIGNAL ( longClickWithPoint ( QPoint ) ), this, SIGNAL ( longClickWithPoint ( QPoint ) ) );
disconnect ( mClickHelper, SIGNAL ( doubleClickWithPoint ( QPoint ) ), this,
SIGNAL ( doubleClickWithPoint ( QPoint ) ) );
}

View File

@ -1,15 +1,15 @@
#ifndef QQTWIDGET_H
#define QQTWIDGET_H
#include <qqt-local.h>
#include <qqtcore.h>
#include <QWidget>
#include <QTimer>
#include <QImage>
#include <qqtwidgetclickhelper.h>
#include <qqt-local.h>
#include <qqtcore.h>
/*
* QSS美化QQtWidget图片背景不能共存
* QSS部分影响QQtWidgetSize等
@ -83,14 +83,32 @@ protected:
virtual void mouseDoubleClickEvent ( QMouseEvent* event ) override;
private:
void installClickHelper();
QQtWidgetClickHelper* mClickHelper;
quint32 m_style;
/*pixmap是必要的。绘图用pixmap。*/
/*内部没有使用QPixmap存储因为如果缩放widgetpixmap就没办法了img有*/
/*内部对QIcon的使用删除了icon不是必要的。*/
QImage mImage;
/**
*
*/
public:
inline void setClickHelper ( QQtWidgetClickHelper* helper = 0 ) {
uninstallClickHelper();
if ( helper == 0 )
mClickHelper = mDefaultClickHelper;
else
mClickHelper = helper;
installClickHelper();
}
inline const QQtWidgetClickHelper* clickHelper() const {
return mClickHelper;
}
private:
void installClickHelper();
void uninstallClickHelper();
QQtWidgetClickHelper* mClickHelper;
QQtWidgetClickHelper* mDefaultClickHelper;
};
#endif // QPICWIDGET_H

View File

@ -1,11 +1,22 @@
#include "qqtwidgetclickhelper.h"
#include "qqtcore.h"
QQtWidgetClickHelper::QQtWidgetClickHelper ( QObject* parent ) :
QObject ( parent )
{
mDoubleClickInterval = 300;
mLongClickInterval = 1200;
mDoubleClickInterval = doubleClickInterval;
mLongClickInterval = longClickInterval;
t1 = QTime::currentTime();
t2 = QTime::currentTime();
nClickNum = 0;
nLongClickNum = 0;
nDoubleClickNum = 0;
nTotalClickNum = 0;
mMouseEvent = new QQtMouseEvent;
mClickType = QQtNullClick;
m_click_timer = new QTimer ( this );
m_click_timer->setSingleShot ( false );
@ -30,15 +41,15 @@ QQtWidgetClickHelper::~QQtWidgetClickHelper()
{
}
#if 1
#define pdebug() ptime()
#if 0
#define p2debug() p2line()
#else
#define pdebug()
#define p2debug() QNoDebug()
#endif
void QQtWidgetClickHelper::mousePressEvent ( QMouseEvent* event , QWidget* userWidget )
{
pdebug();
p2debug() << event->pos() << userWidget;
//保存位置 这个记录什么用?
mPoint = event->pos();
@ -50,7 +61,22 @@ void QQtWidgetClickHelper::mousePressEvent ( QMouseEvent* event , QWidget* userW
void QQtWidgetClickHelper::mouseReleaseEvent ( QMouseEvent* event, QWidget* userWidget )
{
pdebug();
p2debug() << event->pos() << userWidget;
//doubleClick检测不依赖press,所以只要发release就会有doubleClick发生.
//检测方式: 两次release的间隔小于doubleClickInterval那么触发doubleClick.
//这一次 current click
t1 = QTime::currentTime();
//这里有小技巧: 这里没有加 && mClickType != QQtClick
//难道不会和click时钟混淆吗?不会,因为click时钟那边用的startTime和nowTime两个变量, t2比startTime还早,t1比nowTime还晚,t1-t2绝对比nowTime-startTime还长.
//如果是click,绝对不会混淆成doubleClick.
//正好mDoubleClickInterval ms代表双击 不代表单击.
if ( t2.msecsTo ( t1 ) >= 0 && t2.msecsTo ( t1 ) <= mDoubleClickInterval )
{
//双击发生
mClickType = QQtDoubleClick;
}
//上一次 prev click
t2 = QTime::currentTime();
//梳理状态
m_long_click_timer->stop();
@ -58,6 +84,9 @@ void QQtWidgetClickHelper::mouseReleaseEvent ( QMouseEvent* event, QWidget* user
if ( mClickType == QQtLongClick )
{
//计算点击数目
checkClickNum();
//修改状态
mClickType = QQtNullClick;
@ -65,21 +94,27 @@ void QQtWidgetClickHelper::mouseReleaseEvent ( QMouseEvent* event, QWidget* user
//条件是用户传入了这个Widget为真.
if ( userWidget )
{
p2debug() << userWidget << userWidget->rect() << event->pos() << userWidget->rect().contains ( event->pos() );
if ( !userWidget->rect().contains ( event->pos() ) )
{
pdebug() << "send long click canceled." ;
p2debug() << "send long click canceled." ;
return;
}
}
//发送长信号
pdebug() << "send long click " ;
p2debug() << "send long click " ;
emit longClick();
emit longClickWithPoint ( event->pos() );
emit longClickWithPointF ( event->localPos() );
return;
}
else if ( mClickType == QQtDoubleClick )
{
//计算点击数目
checkClickNum();
//修改状态
mClickType = QQtNullClick;
@ -87,23 +122,62 @@ void QQtWidgetClickHelper::mouseReleaseEvent ( QMouseEvent* event, QWidget* user
//条件是用户传入了这个Widget为真.
if ( userWidget )
{
p2debug() << userWidget << userWidget->rect() << event->pos() << userWidget->rect().contains ( event->pos() );
if ( !userWidget->rect().contains ( event->pos() ) )
{
pdebug() << "send double click canceled." ;
p2debug() << "send double click canceled." ;
return;
}
}
//发送信号
pdebug() << "send double click." ;
//发送双击信号
p2debug() << "send double click." ;
emit doubleClick();
emit doubleClickWithPoint ( event->pos() );
emit doubleClickWithPointF ( event->localPos() );
return;
}
else if ( mClickType == QQtClick )
{
//计算点击数目
checkClickNum();
//修改状态
mClickType = QQtNullClick;
//如果手移开了,那么不发送.
//条件是用户传入了这个Widget为真.
if ( userWidget )
{
p2debug() << userWidget << userWidget->rect() << event->pos() << userWidget->rect().contains ( event->pos() );
if ( !userWidget->rect().contains ( event->pos() ) )
{
p2debug() << "send click canceled." ;
return;
}
}
//发送单击信号
p2debug() << "send click." ;
emit click();
emit clickWithPoint ( event->pos() );
emit clickWithPointF ( event->localPos() );
return;
}
//枷锁? 不,每一次双击肯定会冲掉单击检测.双击来了,单击检测取消.双击来了,不必要单击了,那不是单击.
//双击来了,单击检测会被自动取消,发射双击信号以后,这一次单击\双击检测完成.
//同样的,单击来了,单击发生,单击\双击监测完成.开始新的检测.
//保存数据.
mUserWidget = userWidget;
*mMouseEvent = *event;
startClickTime = QTime::currentTime();
//启动click检测timer.
m_click_timer->start();
startClickTime = QTime::currentTime();
//修改状态
mClickType = QQtNullClick;
@ -115,9 +189,10 @@ void QQtWidgetClickHelper::mouseReleaseEvent ( QMouseEvent* event, QWidget* user
void QQtWidgetClickHelper::mouseDoubleClickEvent ( QMouseEvent* event , QWidget* userWidget )
{
ptime();
p2debug() << event->pos() << userWidget;
//这里关闭状态修改,会和内部的检测冲突,分不清是单击还是双击.
//修改状态
mClickType = QQtDoubleClick;
//mClickType = QQtDoubleClick;
//保存位置 这个保存没有意义?
mPoint = event->pos();
@ -127,15 +202,11 @@ void QQtWidgetClickHelper::slotClickTimeout()
{
QTime nowTime = QTime::currentTime();
int t0 = startClickTime.msecsTo ( nowTime );
pdebug() << t0 << qApp->doubleClickInterval();
if ( t0 > 300/*qApp->doubleClickInterval()*/ )
p2debug() << t0 << mDoubleClickInterval << qApp->doubleClickInterval();
if ( t0 > mDoubleClickInterval/*qApp->doubleClickInterval()*/ )
{
mClickType = QQtClick;
pdebug() << "send click." ;
emit click();
emit clickWithPoint ( mPoint );
m_click_timer->stop();
mClickType = QQtNullClick;
mouseReleaseEvent ( mMouseEvent, mUserWidget );
return;
}
}
@ -152,3 +223,48 @@ void QQtWidgetClickHelper::slotDoubleClickTimeout()
}
void QQtWidgetClickHelper::checkClickNum()
{
switch ( mClickType )
{
case QQtClick:
{
nClickNum++;
if ( nClickNum >= 0xFFFFFFFF )
{
p2debug() << "out......";
nClickNum = 0;
}
}
break;
case QQtDoubleClick:
{
nDoubleClickNum++;
if ( nDoubleClickNum >= 0xFFFFFFFF )
{
p2debug() << "out......";
nDoubleClickNum = 0;
}
}
break;
case QQtLongClick:
{
nLongClickNum++;
if ( nLongClickNum >= 0xFFFFFFFF )
{
p2debug() << "out......";
nLongClickNum = 0;
}
}
break;
default:
break;
}
nTotalClickNum = nClickNum + nLongClickNum + nDoubleClickNum;
if ( nTotalClickNum >= 0xFFFFFFFFFFFFFFFF )
{
p2debug() << "out......";
nTotalClickNum = 0;
}
}

View File

@ -3,9 +3,9 @@
#include <qqt-local.h>
#include <qqtcore.h>
#include <qqtevent.h>
#include <QTimer>
#include <QMouseEvent>
/**
* QQtWidgetClickHelper
@ -19,26 +19,20 @@
* click只发送click.
* click为准
*
* DoubleClick间隔默认掌握在Qt手中,.
*
*
* releaseEvent是核心.
* release,,.
* press击发,,,release也不会发射信号.
* 使pressEvent,.
* 使DoubleClickEvent,.
*
* DoubleClick检测是独立于系统的,,widget一个时延系统也没问题.
*
*/
class QQTSHARED_EXPORT QQtWidgetClickHelper : public QObject
{
Q_OBJECT
public:
typedef enum
{
QQtNullClick = 0,
QQtClick,
QQtDoubleClick,
QQtLongClick,
QQtMaxClick
} QQtClickType;
Q_ENUMS ( QQtClickType )
public:
explicit QQtWidgetClickHelper ( QObject* parent = 0 );
virtual ~QQtWidgetClickHelper();
@ -60,24 +54,65 @@ signals:
void doubleClickWithPoint ( QPoint point );
void longClickWithPoint ( QPoint point );
void clickWithPointF ( QPointF point );
void doubleClickWithPointF ( QPointF point );
void longClickWithPointF ( QPointF point );
//optional
public:
//设置双击检测时延 default:200ms
//这个语法比较难,只有整型有特权.
static const int doubleClickInterval = 400;
static const int longClickInterval = 1200;
//设置双击检测时延 default: doubleClickInterval ms
//不会影响系统默认时延
void setDoubleClickInterval ( int millSecond = 300 );
void setDoubleClickInterval ( int millSecond = doubleClickInterval ) {
mDoubleClickInterval = millSecond;
}
int getDoubleClickInterval() const {
return mDoubleClickInterval;
}
//设置longClick超时 default:1200ms
void setLongClickInterval ( int millSecond = 1200 );
void setLongClickInterval ( int millSecond = longClickInterval ) {
mLongClickInterval = millSecond;
m_long_click_timer->setInterval ( mLongClickInterval );
}
int getLongClickInterval() const {
return mLongClickInterval;
}
quint32 clickNum() const { return nClickNum; }
quint32 doubleClickNum() const { return nDoubleClickNum; }
quint32 longClickNum() const { return nLongClickNum; }
quint64 totalClickNum() const { return nTotalClickNum; }
/**
*
*/
public:
Q_ENUMS ( QQtClickType )
Q_PROPERTY ( int mDoubleClickInterval READ getDoubleClickInterval WRITE setDoubleClickInterval )
Q_PROPERTY ( int mLongClickInterval READ getLongClickInterval WRITE setLongClickInterval )
typedef enum
{
QQtNullClick = 0,
QQtClick,
QQtDoubleClick,
QQtLongClick,
QQtMaxClick
} QQtClickType;
public slots:
void slotClickTimeout();
void slotLongClickTimeout();
void slotDoubleClickTimeout();
private:
//用于记录点击到了什么状态.
QQtClickType mClickType;
//clickTimer
@ -97,6 +132,19 @@ private:
//click 检测使用
QTime startClickTime;
QTime t1;
QTime t2;
//click 用
QWidget* mUserWidget;
QQtMouseEvent* mMouseEvent;
//click num
void checkClickNum();
quint32 nClickNum;
quint32 nDoubleClickNum;
quint32 nLongClickNum;
quint64 nTotalClickNum;
};
#endif // QQTWIDGETCLICKHELPER_H

View File

@ -0,0 +1,34 @@
#-------------------------------------------------
#
# Project created by QtCreator 2018-03-28T19:21:56
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QQtWidgetClickHelperTest
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
system(touch main.cpp)
include (../../src/app_base_manager.pri)

View File

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QQtApplication>
int main ( int argc, char* argv[] )
{
QQtApplication a ( argc, argv );
MainWindow w;
w.show();
return a.exec();
}

View File

@ -0,0 +1,40 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qqtcore.h"
MainWindow::MainWindow ( QWidget* parent ) :
QMainWindow ( parent ),
ui ( new Ui::MainWindow )
{
ui->setupUi ( this );
ui->widget;
ui->widget->setPixmap ( "" );
connect ( ui->widget, SIGNAL ( click() ),
this, SLOT ( setSum() ) );
connect ( ui->widget, SIGNAL ( doubleClick() ),
this, SLOT ( set2Sum() ) );
connect ( ui->widget, SIGNAL ( longClick() ),
this, SLOT ( set3Sum() ) );
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setSum()
{
sender();
ui->textBrowser->append ( QString ( "%1 click" ).arg ( ui->widget->clickHelper()->totalClickNum() ) );;
}
void MainWindow::set2Sum()
{
ui->textBrowser->append ( QString ( "%1 double click" ).arg ( ui->widget->clickHelper()->totalClickNum() ) );;
}
void MainWindow::set3Sum()
{
ui->textBrowser->append ( QString ( "%1 long click" ).arg ( ui->widget->clickHelper()->totalClickNum() ) );;
}

View File

@ -0,0 +1,27 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow ( QWidget* parent = 0 );
~MainWindow();
public slots:
void setSum();
void set2Sum();
void set3Sum();
private:
Ui::MainWindow* ui;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>816</width>
<height>519</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTextBrowser" name="textBrowser"/>
</item>
<item>
<widget class="QQtWidget" name="widget" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>816</width>
<height>39</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QQtWidget</class>
<extends>QWidget</extends>
<header>qqtwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>