当前位置:  编程技术>移动开发
本页文章导读:
    ▪资料保存树形结构数据        文件保存树形结构数据本文主要研究了一下如何把树形结构的数据保存到文件并读取出来。为了更形象说明用了一个界面程序显示,程序用了model/view框架。 数据类 DataItem 就是保存在树形结.........
    ▪ EGOTableViewPullRefresh动态刷新旋钮        EGOTableViewPullRefresh动态刷新按钮EGOTableViewPullRefresh 是fork EGOTableViewPullRefresh开源类库进行的改进,添加了上提加载更多效果。同时也可以通过一个按钮的触发刷新事件,但是刷新的时候不能跳.........
    ▪ 日就月将:ScrollView嵌套ListView只显示一行       日积月累:ScrollView嵌套ListView只显示一行 在开发的过程当中,由于手机屏幕的大小的限制,我们经常需要使用滑动的方式,来显示更多的内容。在最近的工作中,遇见一个需求,需要将ListVie.........

[1]资料保存树形结构数据
    来源: 互联网  发布时间: 2014-02-18
文件保存树形结构数据

本文主要研究了一下如何把树形结构的数据保存到文件并读取出来。为了更形象说明用了一个界面程序显示,程序用了model/view框架。

数据类
DataItem 就是保存在树形结构的基本数据。其最重要的保存数据的函数是SerialzeData
class DataItem
{
public:

	DataItem(int id = 100,QString name = "root");
	~DataItem();

	void SetRoot(DataItem *root);
	void SerialzeData(bool isSave,QDataStream &stream);
	void Clear();
	void Init();
	//protected:
	int GetID()
	{
		return ID;
	}

	QString GetName()
	{
		return Name;
	}

	void SetID(int id)
	{
		ID = id;
	}

	void SetName(QString name)
	{
		Name = name;
	}

	int  GetSize()
	{
		return dataVec.size();
	}

	void AddItem(DataItem *pItem);

	void DeleteItem(DataItem *pItem);

	void DeleteItem(int index);

	DataItem *GetItem(int index);

    DataItem *GetParent()
	{
		return pRoot;
	}

	int indexOf(DataItem* pItem);
private:
	int ID;
	QString Name;
	vector<DataItem*>  dataVec;
	DataItem *pRoot;
};
DataItem::DataItem( int id,QString name ):ID(id),Name(name),pRoot(NULL)
{
	//pRoot = new DataItem(100,"Root");
}

DataItem::~DataItem()
{

}
//SerialzeData 原来是,保存数据时,先保存每个项的数据,在后面保存该项的子节点个数,并递归保存各个子节点数据
void DataItem::SerialzeData( bool isSave,QDataStream &stream )
{
	if (isSave)
	{
		stream<<GetID()<<GetName();  //save ID and Name 
		stream<<dataVec.size();     //save  the number of child
		for(int i = 0; i < dataVec.size(); ++i)
		{
			dataVec[i]->SerialzeData(isSave,stream);
		}
	}
	else
	{
		int id;
		int size;
		QString name;
		stream>>id>>name;  //Get ID and Name 
		SetID(id);
		SetName(name);
		stream>>size;     //Get  the number of child
		for(int i = 0; i < size; ++i)
		{
			DataItem *pItem = new DataItem(0,"name");
			pItem->SerialzeData(isSave,stream);
			AddItem(pItem);
		}
	}
}

void DataItem::AddItem( DataItem *pItem )
{
	pItem->SetRoot(this);
	dataVec.push_back(pItem);
}

void DataItem::DeleteItem( DataItem *pItem )
{
	vector<DataItem*>::iterator it = dataVec.begin();
	for (it; it != dataVec.end(); ++it)
	{
		if (*it == pItem)
		{
			dataVec.erase(it);
			break;
		}
	}
}

void DataItem::DeleteItem( int index )
{
	if (index < dataVec.size())
	{
		vector<DataItem*>::iterator it = dataVec.begin();
		it = it + index;
		dataVec.erase(it);
	}
}

void DataItem::Init()
{
	for (int i = 0; i < 5; ++i)
	{
		DataItem *pItem = new DataItem(i,QString("child%1").arg(i));
		pRoot->AddItem(pItem);
		for (int j = 0; j < 2; ++j)
		{
			DataItem *pChild = new DataItem(j,QString("grandchild%0 -%1").arg(i).arg(j));
			pItem->AddItem(pChild);
		}
	}
}

void DataItem::SetRoot( DataItem *root )
{
	pRoot = root;
}

void DataItem::Clear()
{
	dataVec.clear();
}

DataItem * DataItem::GetItem( int index )
{
      if (index < dataVec.size())
		{
			return dataVec[index];
		}
		else
		{
			return NULL;
		}
}

int DataItem::indexOf( DataItem* pItem )
{
	int index = -1;
	for (int i = 0; i < dataVec.size(); ++i)
	{
		if (dataVec[i] == pItem)
		{
			index = i;
			break;
		}
	}
	return index;
}

数据模型
TreeDataModel的底层数据就是上面定义的DataItem。用这种视图/模型的编程方式可以尽量减少数据与界面的耦合性。由于继承了QAbstractItemModel。所以必须重写其中的五个纯虚函数columnCount (),data(),index (),parent ()和rowCount()。

class TreeDataModel:public QAbstractItemModel
{
	Q_OBJECT
public:
	TreeDataModel(QObject *parent = NULL);
	~TreeDataModel();

	void SetRoot(DataItem *pRoot)
	{
		m_pTreeData = pRoot;
	}
	QModelIndex	parent ( const QModelIndex & index ) const;
	 QVariant	data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
	 QVariant	headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
	 QModelIndex	index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
	 int	columnCount ( const QModelIndex & parent = QModelIndex() ) const;
	 int	rowCount ( const QModelIndex & parent = QModelIndex() ) const;
	 DataItem* dataFromIndex(const QModelIndex &index) const;

	 void SaveData(QDataStream &out);
	 void LoadData(QDataStream &in);
protected:
private:
	DataItem  *m_pTreeData;
};

TreeDataModel::TreeDataModel( QObject *parent /*= NULL*/ ):QAbstractItemModel(parent)
{
	m_pTreeData = NULL;
}

TreeDataModel::~TreeDataModel()
{

}

QVariant TreeDataModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const
{
	DataItem *pItem = dataFromIndex(index);
	if ((pItem)&&(role == Qt::DisplayRole))
	{
		switch (index.column())
		{
		case 0:
			return pItem->GetID();
		case 1:
			return pItem->GetName();
		}
	}
	return QVariant();

}

QVariant TreeDataModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */ ) const
{
	if ((section <2) && (orientation == Qt::Horizontal)&& (role == Qt::DisplayRole))
	{
		switch (section)
		{
		case 0:
			return tr("编号");

		case 1:
			return tr("名称");
		default:
			return QVariant();
		}
	}
	else
	{
		return QVariant();
	}
}

QModelIndex TreeDataModel::index( int row, int column, const QModelIndex & parent /*= QModelIndex() */ ) const
{
	if (!m_pTreeData ||row < 0 || column < 0)
	{
		return QModelIndex();
	}
	else
	{
		DataItem *pItem = dataFromIndex(parent);
		if (pItem)
		{
			DataItem *pChild = pItem->GetItem(row);
			if (pChild)
			{
				return createIndex(row,column,pChild);
			}
		}
		return QModelIndex();
	}
}

int TreeDataModel::columnCount( const QModelIndex & parent /*= QModelIndex() */ ) const
{
	return 2;
}

int TreeDataModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const
{
	DataItem *pItem = dataFromIndex(parent);
	if (pItem)
	{
		return pItem->GetSize();
	}
	return 0;
}

DataItem* TreeDataModel::dataFromIndex( const QModelIndex &index ) const
{
	if (index.isValid())
	{
		return static_cast<DataItem*>(index.internalPointer());
	} 
	else
	{
		return m_pTreeData;               //这里不要返回NULL
	}
}

QModelIndex TreeDataModel::parent( const QModelIndex & index ) const
{
	if (index.isValid())
	{
		DataItem *pItem = dataFromIndex(index);
		if (pItem)
		{
			DataItem *pParent = pItem->GetParent();
			if (pParent)
			{
				DataItem *pGrandParent = pParent->GetParent();
				if (pGrandParent)
				{
					int row = pGrandParent->indexOf(pParent);
					return createIndex(row,index.column(),pParent);
				}
			}
		}
	}
	return QModelIndex();
}

void TreeDataModel::SaveData( QDataStream &out )
{
	m_pTreeData->SerialzeData(true,out);
}

void TreeDataModel::LoadData( QDataStream &in )
{
	m_pTreeData->SerialzeData(false,in);
}

主框架类
这个类主要实现左边的树形把数据保存到文件中,然后在右边的树形结构加载显示出来。
class MainWidget:public QWidget
{
	Q_OBJECT
public:
	MainWidget(QWidget *patent = NULL);
	~MainWidget();

protected slots:
	void leftSelectBtnSlot();
	void rightSelectBtnSlot();
	void saveBtnSlot();
	void loadBtnSlot();

private:
	QSplitter         *m_pSplitter;
	QTreeView         *m_pLeftTreeView;
	QTreeView         *m_pRightTreeView;
	QPushButton       *m_pLeftSaveBtn;
	QPushButton       *m_pRightLoadBtn;
	QPushButton       *m_pLeftSelectBtn;
	QPushButton       *m_pRightSelectBtn;
	QLineEdit         *m_pLeftLEdit;
	QLineEdit         *m_pRightLEdit;
	QGridLayout       *m_pLeftLayout;
	QGridLayout       *m_pRightLayout;

	TreeDataModel     *m_pLeftModel;
	TreeDataModel     *m_pRightModel;


};


MainWidget::MainWidget( QWidget *patent /*= NULL*/ ):QWidget(patent)
{
	m_pLeftModel = new TreeDataModel();
	m_pRightModel = new TreeDataModel();

	m_pSplitter = new QSplitter(this);
	QFrame *pLeftFrame = new QFrame(this);
	QFrame *pRightFrame = new QFrame(this);
	m_pLeftLayout = new QGridLayout(pLeftFrame);
	m_pRightLayout = new QGridLayout(pRightFrame);
	m_pLeftLEdit = new QLineEdit(this);
	m_pRightLEdit = new QLineEdit(this);
	m_pLeftSaveBtn = new QPushButton(tr("保存"),this);
	m_pRightLoadBtn = new QPushButton(tr("加载"),this);
	m_pLeftTreeView = new QTreeView(this);
	m_pRightTreeView = new QTreeView(this);
	m_pLeftSelectBtn = new QPushButton(tr("选择文件"),this);
	m_pRightSelectBtn = new QPushButton(tr("选择文件"),this);
	m_pRightLEdit->setReadOnly(true);

	
	m_pLeftLayout->addWidget(m_pLeftSelectBtn,0,0,1,1);
	m_pLeftLayout->addWidget(m_pLeftLEdit,0,1,1,1);
	m_pLeftLayout->addWidget(m_pLeftSaveBtn,0,2,1,1);
	m_pLeftLayout->addWidget(m_pLeftTreeView,1,0,3,3);

	m_pRightLayout->addWidget(m_pRightSelectBtn,0,0,1,1);
	m_pRightLayout->addWidget(m_pRightLEdit,0,1,1,1);
	m_pRightLayout->addWidget(m_pRightLoadBtn,0,2,1,1);
	m_pRightLayout->addWidget(m_pRightTreeView,1,0,3,3);

	m_pLeftTreeView->setModel(m_pLeftModel);
	m_pRightTreeView->setModel(m_pRightModel);
	DataItem *pTreeData = new DataItem();
	pTreeData->SetRoot(pTreeData);
	pTreeData->Init();
	
	m_pLeftModel->SetRoot(pTreeData);
	//m_pRightModel->SetRoot(pTreeData);

	m_pSplitter->addWidget(pLeftFrame);
	m_pSplitter->addWidget(pRightFrame);

	connect(m_pLeftSelectBtn,SIGNAL(clicked()),this,SLOT(leftSelectBtnSlot()));
	connect(m_pRightSelectBtn,SIGNAL(clicked()),this,SLOT(rightSelectBtnSlot()));
	connect(m_pLeftSaveBtn,SIGNAL(clicked()),this,SLOT(saveBtnSlot()));
	connect(m_pRightLoadBtn,SIGNAL(clicked()),this,SLOT(loadBtnSlot()));
	this->setFixedSize(QSize(650,250));
}

MainWidget::~MainWidget()
{

}

void MainWidget::leftSelectBtnSlot()     //这里只是选择了一个文件夹路径,在保存之前还需要加文件名
{
	QFileDialog Dialog(this,tr("选择目录"),"","");
	Dialog.setFileMode(QFileDialog::Directory);
	//Dialog.setNameFilter("*.data");
	if (Dialog.exec())
	{
		QStringList dirs = Dialog.selectedFiles();
		if (dirs.size() > 0)
		{
			m_pLeftLEdit->setText(QDir::toNativeSeparators(dirs.at(0)));    
		}
	} 
}

void MainWidget::rightSelectBtnSlot()      //选择之前保存的.data文件进行加载显示
{
	QFileDialog Dialog(this,tr("选择文件"),"","");
	Dialog.setFileMode(QFileDialog::ExistingFile);
	Dialog.setNameFilter("*.data");
	if (Dialog.exec())
	{
		QStringList files = Dialog.selectedFiles();
		if (files.size() > 0)
		{
			m_pRightLEdit->setText(QDir::toNativeSeparators(files.at(0)));
		}
	} 
}

void MainWidget::saveBtnSlot()
{
	QString filePath = m_pLeftLEdit->text();
	if ((filePath.isEmpty()) || filePath.endsWith("\\") || filePath.endsWith("/"))   //必须得添加文件名,文件名规定后缀为.data
	{
		QMessageBox::information(this,tr("提示"),tr("请输入文件名"),QMessageBox::Ok);
		return;
	}
	else if(filePath.endsWith("data"))
	{
		QFile file(filePath);
		if (file.open(QIODevice::WriteOnly))
		{
			QDataStream outStream(&file);
			m_pLeftModel->SaveData(outStream);
		}
	}
}

void MainWidget::loadBtnSlot()
{
	QString filePath = m_pRightLEdit->text();
	if((!filePath.isEmpty()) &&filePath.endsWith("data"))
	{
		DataItem *pTreeData = new DataItem();
		//pTreeData->SetRoot(pTreeData);
		m_pRightModel->SetRoot(pTreeData);

		QFile file(filePath);
		if (file.open(QIODevice::ReadOnly))
		{
			QDataStream inStream(&file);
			m_pRightModel->LoadData(inStream);
			m_pRightTreeView->setModel(m_pRightModel);
			m_pRightTreeView->reset();                  //必须的,不然不会刷新
		}
	}
}

运行结果如下图




    
[2] EGOTableViewPullRefresh动态刷新旋钮
    来源: 互联网  发布时间: 2014-02-18
EGOTableViewPullRefresh动态刷新按钮

EGOTableViewPullRefresh 是fork EGOTableViewPullRefresh开源类库进行的改进,添加了上提加载更多效果。同时也可以通过一个按钮的触发刷新事件,但是刷新的时候不能跳到top,为了动态展示,再刷新的时候按钮旋转,然后跳转回到顶部!如下如图


   


关于EGOTableViewPullRefresh可以参照http://blog.csdn.net/duxinfeng2010/article/details/9007311,翻译过的用法,在这个Demo基础上进行修改,点击Demo下载;

1、给工程添加一个导航栏,在application: didFinishLaunchingWithOptions:方法中


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
//    [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"navbar.png"] forBarMetrics:UIBarMetricsDefault];
    
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.viewController];
    self.window.rootViewController = nav;
    [self.window makeKeyAndVisible];
    return YES;
}



2、在ViewDidLoad方法中,修改背景图片,添加刷新按钮


- (void)viewDidLoad
{
    [super viewDidLoad];
    self.navigationController.navigationBar.tintColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"navbar.png"]];
    
    self.pullTableView.pullArrowImage = [UIImage imageNamed:@"blackArrow"];
//    self.pullTableView.pullBackgroundColor = [UIColor yellowColor];
    self.pullTableView.pullTextColor = [UIColor blackColor];
    
    CGRect rect = CGRectMake(0, 0, 44, 44);
    UIButton *refreshBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    refreshBtn.frame = rect;
    [refreshBtn setBackgroundImage:[UIImage imageNamed:@"button_refresh"] forState:UIControlStateNormal];
    [refreshBtn addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *refreshItem = [[UIBarButtonItem alloc] initWithCustomView:refreshBtn];
    self.navigationItem.leftBarButtonItem = refreshItem;
    
}

3、添加刷新按钮事件,和按钮旋转方法

//按钮旋转
- (void)startAnimation:(UIButton *)button{
    CABasicAnimation *rotate =
    [CABasicAnimation animationWithKeyPath:@"transform.rotation"];    
    [rotate setByValue:[NSNumber numberWithFloat:M_PI*4]];
    rotate.duration = 3.0;
    rotate.timingFunction =
    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [button.layer addAnimation:rotate
                        forKey:@"myRotationAnimation"];
    
}

-(void)refresh:(UIButton *)button
{
    [self startAnimation:button];
//    判断一下table是否处于刷新状态,如果没有则执行本次刷新
    if (!self.pullTableView.pullTableIsRefreshing) {
        self.pullTableView.pullTableIsRefreshing = YES;
//        设置回到top时候table的位置
        [self.pullTableView setContentOffset:CGPointMake(0, -60) animated:YES];
        [self performSelector:@selector(refreshTable) withObject:nil afterDelay:3.0];
    }
    
}


源码下载地址:https://github.com/XFZLDXF/RefreshButtonDemo





    
[3] 日就月将:ScrollView嵌套ListView只显示一行
    来源: 互联网  发布时间: 2014-02-18
日积月累:ScrollView嵌套ListView只显示一行

在开发的过程当中,由于手机屏幕的大小的限制,我们经常需要使用滑动的方式,来显示更多的内容。在最近的工作中,遇见一个需求,需要将ListView嵌套到ScrollView中显示。于是乎有了如下布局: 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#FFE1FF" 
    android:orientation="vertical" > 
    <ScrollView 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" > 
        <LinearLayout 
            android:layout_width="match_parent" 
            android:layout_height="match_parent" > 
            <ListView 
                android:id="@+id/listView1" 
                android:layout_width="match_parent" 
                android:layout_height="match_parent" 
                android:fadingEdge="vertical" 
                android:fadingEdgeLength="5dp" /> 
        </LinearLayout> 
    </ScrollView> 
</LinearLayout> 

运行程序,如下结果,无论你如何调整layout_width,layout_height属性,ListView列表只显示一列! 


在查阅的各种文档和资料后,发现在ScrollView中嵌套ListView空间,无法正确的计算ListView的大小,故可以通过代码,根据当前的ListView的列表项计算列表的尺寸。实现代码如下: 

public class MainActivity extends Activity { 
    private ListView listView; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        listView = (ListView) findViewById(R.id.listView1); 
        String[] adapterData = new String[] { "Afghanistan", "Albania",… … "Bosnia"}; 
        listView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,adapterData)); 
        setListViewHeightBasedOnChildren(listView); 
    } 
    public void setListViewHeightBasedOnChildren(ListView listView) { 
        // 获取ListView对应的Adapter 
        ListAdapter listAdapter = listView.getAdapter(); 
        if (listAdapter == null) { 
            return; 
        } 
 
        int totalHeight = 0; 
        for (int i = 0, len = listAdapter.getCount(); i < len; i++) { 
            // listAdapter.getCount()返回数据项的数目 
            View listItem = listAdapter.getView(i, null, listView); 
            // 计算子项View 的宽高 
            listItem.measure(0, 0);  
            // 统计所有子项的总高度 
            totalHeight += listItem.getMeasuredHeight();  
        } 
 
        ViewGroup.LayoutParams params = listView.getLayoutParams(); 
        params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1)); 
        // listView.getDividerHeight()获取子项间分隔符占用的高度 
        // params.height最后得到整个ListView完整显示需要的高度 
        listView.setLayoutParams(params); 
    } 
} 
运行结果,OK问题搞定,打完收工! 


 


    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android实现侦听电池状态显示、电量及充电动... iis7站长之家
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3