跳转至

平铺视图控件 (STileView)

SOUI中的平铺视图控件,以网格形式展示项目,支持自适应布局和固定大小布局,适用于图片、图标等内容的网格展示。基于虚拟化技术实现,可以高效处理大量数据。

基本信息

  • 类名STileView
  • 控件标签tileview
  • 基类SPanel
  • 功能:提供网格形式的项目展示

属性说明

基本属性

属性名 类型 默认值 说明
marginSize int - 边框大小
wantTab bool - 是否处理tab按键(0-不处理,1-处理)
align int left left,center,right, 用于水平对齐方式

使用示例

基础平铺视图

<!-- 基础平铺视图 -->
<tileview pos="10,10,-10,-10" name="tile_basic"
          marginSize="10" wantTab="0">
    <template>
        <window>
            <img pos="10,10,-10,-40" name="img_icon"/>
            <text pos="10,-30,-10,-10" name="txt_name"
                  align="center"/>
        </window>
    </template>
</tileview>

自定义样式平铺视图

<!-- 自定义样式平铺视图 -->
<tileview pos="10,10,-10,-10" name="tile_custom"
          marginSize="15" wantTab="1">
    <template>
        <window colorBkgnd="#FFFFFF">
            <img pos="10,10,-10,130" name="img_cover"/>
            <text pos="10,135,-10,155" name="txt_title"
                  font="bold:1"/>
            <text pos="10,160,-10,175" name="txt_desc"
                  colorText="#666666"/>
        </window>
    </template>
</tileview>

带选择效果的平铺视图

<!-- 带选择效果的平铺视图 -->
<tileview pos="10,10,-10,-10" name="tile_select"
          marginSize="10" wantTab="0" selectionMode="1">
    <template>
        <window layout="vbox" padding="5" colorBkgnd="#F5F5F5">
            <img name="img_thumb" size="0,0" flex="1" 
                 scale="1" margin="0,0,0,5"/>
            <text name="txt_name" size="0,20" align="center"
                  font="size:14"/>
            <check name="chk_select" size="16,16" 
                   align="center" text="选择"/>
        </window>
    </template>
</tileview>

代码示例

#include <helper/SAdapterBase.h>

// 创建平铺视图适配器
class CTileAdapter : public SAdapterBase
{
protected:
    SArray<TileItemData> m_items;

public:
    // 获取项目数量,注意 WINAPI 调用约定
    virtual int WINAPI getCount()
    {
        return m_items.GetCount();
    }

    // 获取项目视图,注意 WINAPI 调用约定
    virtual void WINAPI getView(int position, SItemPanel* pItem,
                 SXmlNode xmlTemplate)
    {
        if(!pItem) return;

        // 初始化模板
        if(pItem->GetChildrenCount() == 0)
        {
            pItem->InitFromXml(&xmlTemplate);

            // 订阅复选框事件
            SWindow* pCheck = pItem->FindChildByName(L"chk_select");
            if(pCheck)
            {
                pCheck->GetEventSet()->subscribeEvent(
                    EventCmd::EventID,
                    Subscriber(&CTileAdapter::OnCheckChanged, this));
            }
        }

        const TileItemData &item = m_items[position];

        // 设置图标
        SImageWnd *pImg = 
            pItem->FindChildByName2<SImageWnd>(L"img_icon");
        if(pImg)
        {
            pImg->SetAttribute(L"skin", item.strIcon);
        }

        // 设置名称
        SWindow *pName = 
            pItem->FindChildByName(L"txt_name");
        if(pName)
        {
            pName->SetWindowText(item.strName);
        }
    }

    // 处理复选框变化
    bool OnCheckChanged(EventArgs* pEvt)
    {
        SWindow* pCheck = sobj_cast<SWindow>(pEvt->sender);
        if(pCheck)
        {
            SItemPanel* pItem = sobj_cast<SItemPanel>(pCheck->GetParent());
            if(pItem)
            {
                int nIndex = (int)pItem->GetItemIndex();
                bool bChecked = pCheck->GetCheck();
                // 处理选中状态变化
                HandleCheckChanged(nIndex, bChecked);
            }
        }
        return true;
    }

    // 添加项目
    void AddItem(const TileItemData &item)
    {
        m_items.Add(item);
        notifyDataSetChanged();
    }

    // 获取项目数据
    const TileItemData& GetItem(int nIndex) const
    {
        return m_items[nIndex];
    }
};

// 使用平铺视图
void InitTileView()
{
    // 获取平铺视图控件
    STileView *pTileView = 
        FindChildByName2<STileView>(L"tile_demo");
    if(pTileView)
    {
        // 创建适配器
        CTileAdapter *pAdapter = new CTileAdapter();

        // 添加测试数据
        for(int i = 0; i < 100; i++)
        {
            TileItemData item;
            item.strName.Format(L"项目 %d", i + 1);
            item.strIcon.Format(L"skin_icon_%d", i % 10);
            pAdapter->AddItem(item);
        }

        // 设置适配器
        pTileView->SetAdapter(pAdapter);
        pAdapter->Release();

        // 订阅选择变化事件
        pTileView->GetEventSet()->subscribeEvent(
            EventTileViewSelChanged::EventID,
            Subscriber(&CMainDlg::OnTileSelChanged, this));
    }
}

事件处理

平铺视图控件支持以下事件:

事件名 EventID 说明
EVT_LV_SELCHANGIING EventLVSelChangiing::EventID 选择改变前事件
EVT_LV_SELCHANGED EventLVSelChanged::EventID 选择改变事件
EVT_LV_ITEMCLICK EventLVItemClick::EventID 项目点击事件
// 事件处理示例
EVENT_MAP_BEGIN()
    EVENT_NAME_HANDLER(L"tile_basic", EventLVSelChanged::EventID, OnLVSelChanged)
    EVENT_NAME_HANDLER(L"tile_basic", EventLVItemClick::EventID, OnLVItemClick)
EVENT_MAP_END()

void OnLVSelChanged(IEvtArgs *pEvt)
{
    EventLVSelChanged *pRealEvt = sobj_cast<EventLVSelChanged>(pEvt);
    int nOldSel = pRealEvt->nOldSel;
    int nNewSel = pRealEvt->nNewSel;
    // 处理选择改变事件
}

void OnLVItemDbClick(IEvtArgs *pEvt)
{
    EventLVItemClick *pRealEvt = sobj_cast<EventLVItemClick>(pEvt);
    int nItem = pRealEvt->nItem;
    // 处理项目点击事件
}

代码操作

// 查找平铺视图控件
STileView *pTileView = FindChildByName2<STileView>(L"tile_basic");

// 设置适配器
pTileView->SetAdapter(pAdapter);

// 获取当前选中项
int nCurSel = pTileView->GetSel();

// 设置选中项
pTileView->SetSel(0);

// 获取项目数量
int nCount = pTileView->GetCount();

// 滚动到指定项
pTileView->EnsureVisible(15);


// 设置边距
pTileView->SetAttribute(L"marginSize", L"20");

实现图片浏览器示例

#include <helper/SAdapterBase.h>

// 图片项数据结构
struct ImageItemData
{
    SStringT strName;      // 图片名称
    SStringT strPath;      // 图片路径
    SStringT strThumbSkin; // 缩略图皮肤
    DWORD dwFileSize;      // 文件大小
    SYSTEMTIME stModified; // 修改时间
};

// 图片浏览器适配器
class CImageAdapter : public SAdapterBase
{
protected:
    SArray<ImageItemData> m_images;

public:
    // 获取项目数量,注意 WINAPI 调用约定
    virtual int WINAPI getCount()
    {
        return m_images.GetCount();
    }

    // 获取视图,注意 WINAPI 调用约定
    virtual void WINAPI getView(int position, SItemPanel* pItem, SXmlNode xmlTemplate)
    {
        if(pItem->GetChildrenCount() == 0)
        {
            pItem->InitFromXml(&xmlTemplate);
        }

        if(position >= 0 && position < m_images.GetCount())
        {
            const ImageItemData& imageData = m_images[position];

            // 设置缩略图
            SWindow* pThumb = pItem->FindChildByName(L"img_thumb");
            if(pThumb)
            {
                pThumb->SetAttribute(L"skin", imageData.strThumbSkin);
            }

            // 设置名称
            SWindow* pName = pItem->FindChildByName(L"txt_name");
            if(pName)
            {
                pName->SetWindowText(imageData.strName);
            }

            // 设置大小
            SWindow* pSize = pItem->FindChildByName(L"txt_size");
            if(pSize)
            {
                SStringT strSize;
                if(imageData.dwFileSize < 1024)
                    strSize.Format(L"%d B", imageData.dwFileSize);
                else if(imageData.dwFileSize < 1024 * 1024)
                    strSize.Format(L"%.1f KB", (float)imageData.dwFileSize / 1024);
                else
                    strSize.Format(L"%.1f MB", (float)imageData.dwFileSize / (1024 * 1024));
                pSize->SetWindowText(strSize);
            }

            // 设置修改时间
            SWindow* pDate = pItem->FindChildByName(L"txt_date");
            if(pDate)
            {
                SStringT strDate;
                strDate.Format(L"%04d-%02d-%02d", 
                    imageData.stModified.wYear,
                    imageData.stModified.wMonth,
                    imageData.stModified.wDay);
                pDate->SetWindowText(strDate);
            }
        }
    }

    // 添加图片
    void AddImage(const ImageItemData& image)
    {
        m_images.Add(image);
        notifyDataSetChanged();
    }

    // 获取指定位置的图片数据
    const ImageItemData& GetImage(int position)
    {
        return m_images[position];
    }

    // 清空所有图片
    void Clear()
    {
        m_images.RemoveAll();
        notifyDataSetChanged();
    }
};

// 图片浏览器初始化
void InitImageViewer()
{
    STileView* pTileView = FindChildByName2<STileView>(L"tile_images");
    if(pTileView)
    {
        CImageAdapter* pAdapter = new CImageAdapter();

        // 模拟添加图片数据
        for(int i = 0; i < 50; i++)
        {
            ImageItemData image;
            image.strName.Format(L"图片%d.jpg", i+1);
            image.strPath.Format(L"C:\\图片\\图片%d.jpg", i+1);
            image.strThumbSkin.Format(L"skin_thumb_%d", i % 10);
            image.dwFileSize = (i + 1) * 1024 * 50; // 模拟不同大小

            // 设置修改时间
            GetLocalTime(&image.stModified);
            image.stModified.wDay -= i % 30; // 模拟不同日期

            pAdapter->AddImage(image);
        }

        // 设置适配器
        pTileView->SetAdapter(pAdapter);
        pAdapter->Release();
    }
}

// 处理图片选择
void OnImageSelected(int nIndex)
{
    STileView* pTileView = FindChildByName2<STileView>(L"tile_images");
    if(pTileView)
    {
        CImageAdapter* pAdapter = (CImageAdapter*)pTileView->GetAdapter();
        if(pAdapter)
        {
            const ImageItemData& image = pAdapter->GetImage(nIndex);
            // 处理图片选择,例如显示大图
            ShowLargeImage(image.strPath);
        }
    }
}

// 显示大图(示例函数)
void ShowLargeImage(const SStringT& strImagePath)
{
    // 实现显示大图的逻辑
    // 例如打开一个新的窗口显示大图
}

最佳实践

  1. 间距控制:通过 marginSize 属性控制项目间距,确保布局美观
  2. 键盘导航:根据需要设置 wantTab 属性处理Tab键导航
  3. 尺寸设计:合理设计项目尺寸,确保内容完整显示且布局协调

常见问题

Q: 项目间距过大或过小怎么办?

A: 调整 marginSize 属性值,设置合适的边框大小。

Q: Tab键导航不工作怎么办?

A: 确保设置了 wantTab 为 1,并正确处理相关事件。

Q: 项目显示不完整怎么办?

A: 检查 template 中的 itemWidth 和 itemHeight 是否设置正确。

相关控件