如何使用TableView

本文介绍如何利用UITableView替代UILabel展示数据列表,包括UITableView的基本配置、数据源设置及代理方法的实现,通过实例演示如何构建简单的食品列表应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

去我的目录

还记得上一篇中的FoodList么?我们简单的用了一个UILabel把所有的食物列举出来,不得不说,这太丑陋了。

iPhone为我们提供了一个强有力的控件,来帮助我们显示数据,就是TableView!

下面这个gmail的界面就是使用TableView制作的。

gmail

好了,言归正传,我们来看看如何在FoodList这个程序中使用TableView来显示所有的食物列表。

 

首先,我们来复习一下Protocol。所谓的Protocol就是接口,类似于Java中的Interface或者C++ 中的纯虚类。如果我们自己定义的类声明遵循某个Protocol的话,那么就意味着要去实现这个Protocol中的方法。比如,在Objective-C中,常常看到这样的类声明:

@interface class1 : baseClass <Protocol1, Protocol2> {

}

这就是说,Class1声明遵循两个Protocol,所以在它的实现中,就必须实现Protocol1和Protocol2中的相应的方法。

 

其次,再来复习一下delegate的概念。在“我们的第一个iPhone程序 ”中,我曾经提到过delegate的概念。下面再来简要的介绍一下:假如我们有两个类,A和B。B声明自己是A的delegate(代表),那么就意味着B要实现一些A中的方法,使得A在工作的时候,当它(A)需要调用某些方法的时候,可以去询问它的代言人─B。

这种模式在iPhone程序设计中非常的常见。继续用上面的例子做比方:往往A类都是iPhone提供的SDK,它隐藏了很多的实现细节,可是为了给程序员提供足够的灵活性,A又提供了一些接口方法,程序员通过实现这些接口方法,可以控制A类的某些行为。而实现这些接口方法往往都是通过delegate来完成的。一般来说,都是声明一个类B,使它成为A的delegate,然后在B中实现某些接口方法。这样,在A工作的时候,它就会去调用B中的对应的函数,来完成程序员指定的任务。

我们再看一个具体的例子:- (void)applicationDidFinishLaunching:(UIApplication *)application {}

上面这个函数是UIApplicationDelegate 中的方法。每当我们创建一个自己的工程的时候,都会在ProjectName AppDelegate(注:ProjectName就是我们给工程起的名字)这个类里面看到这个方法。实际上,ProjectNameAppDelegate就是UIApplication的一个delegate;当UIApplication完成装载资源的任务后,它就会去调用它的delegate─ProjectNameAppDelegate─中的这个函数。

 

好了,在熟悉完上面的两个概念之后,我们就可以开始编码了。我们在上次程序的基础上进行修改。这里,我们仅仅需要把原来用UILabel展示的数据变成用UITableView来展示,所以在代码方面需要做修改的,就仅仅是FoodListController这个类。

在FoodListController.h中:

#import <UIKit/UIKit.h>
@interface FoodListController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
// IBOutlet UILabel * label;
    IBOutlet UITableView * table;
    NSMutableArray * list;
}

//@property (nonatomic, retain) IBOutlet UILabel * label;
@property (nonatomic, retain) IBOutlet UITableView * table;
@property (nonatomic, retain) NSMutableArray * list;


- (IBAction) switchToWelcome;

@end

在这里,新声明了一个UITableView的对象和一个NSMutableArray对象。UITableView是要和Table View控件对应起来的,而NSMutableArray是存放被显示数据的地方(在这里就是存放我们的Food List)。

NSMutableArray可以理解为C++ 中的vector,可以动态的加入元素、删除元素等。

同时,我们将FoodListController这个类声明为遵循UITableViewDelegate和UITableViewDataSource这两个协议。其中,UITableViewDelegate是用来控制Table View的显示以及与用户之间的交互,而UITableViewDataSource则为Table View提供了后台的数据。

FoodListController这个类,就变成了UITableView的Delegate类。

 

在FoodListController.m中:

@implementation FoodListController
//@synthesize label;
@synthesize table;
@synthesize list;

... ...

- (void)viewDidLoad {
    list = [[NSMutableArray alloc] init];
    [list addObject:@"beef"];
    [list addObject:@"pork"];
    [list addObject:@"fish"];
    [list addObject:@"tomato"];
    [list addObject:@"salad"];

//  NSString * list = [[NSString alloc] initWithFormat:@"beef/npork/nfish/ntomato/npotato/nsalad/n"];
//  label.text = list;
//  [list release];
    [super viewDidLoad];
}

... ...

- (void)dealloc {
// [label release];
    [list release];
    [super dealloc];
}


- (NSInteger) numberOfSectionsInTableView : (UITableView*)tableView {
    return 1;
}
- (NSInteger) tableView: (UITableView*)tableView numberOfRowsInSection: (NSInteger)section {
    return [list count];
}
- (NSString*) tableView: (UITableView*)tableView titleForHeaderInSection: (NSInteger)section {
    return @"Food List";
}
- (UITableViewCell*) tableView: (UITableView*)tableView cellForRowAtIndexPath: (NSIndexPath*)indexPath {

// NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
   
    static NSString * identifier = @"identifier";
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if( cell == nil )
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier: identifier] autorelease];
    cell.text = [list objectAtIndex:row];
    return cell;
}

 

在viewDidLoad中,我们初始化了list的内容,用于Table的显示。

然后下面的4个方法:numberOfSectionsInTableView,tableView: numberOfRowsInSection,tableView: titleForHeaderInSection,tableView: cellForRowAtIndexPath,就是我们实现的delegate的方法。iPhone程序在现实Table View的时候,会在恰当的时候调用这几个方法。具体怎么调用我们不需要关系(这是被隐藏起来的实现细节),我们作为程序员只需要在delegate中实现这些方法,完成我们所需要的功能。下面一一来解释:

1)numberOfSectionsInTableView:这个方法的参数是UITableView*,也就是说,我们允许在一个View中有若干个Table View,可以为每个Table View分别设定section的数量。那么什么是section呢?参见下图。下图的Table View中一共有2个section。

table sections

这里,我们只需要一个section,所以函数直接返回1。

2)tableView: numberOfRowsInSection:这里有两个参数,第一个是UITableView*,第二个是section的index。也就是说它可以指定某个table view中的某个section的行数。这里,由于我们只有一个table view,并且在这个table view里面只有一个section,所以直接返回food list的长度。

3)tableView: titleForHeaderInSection:这里有两个参数,第一个是UITableView*,第二个是section的index。也就是说它可以指定某个table view中的某个section的标题。这里我们直接返回"Food List"。

4)tableView: cellForRowAtIndexPath:这个函数是用来返回Table View中每一行(每一个cell)的内容。它有两个参数,第一个是UITableView*,第二个是IndexPath*。IndexPath包含了该行所在的section的序号和它的行序号。我们可以通过[indexPath section]和[indexPath row]就可以得到该单元所在的section序号和行序号。

因为每一行唯一的区别就是显示的文本不同,所以为了节约资源,iPhone允许我们重用UITableViewCell的资源。

首先,使用[tableView dequeueReusableCellWithIdentifier: identifier] 来查看一下UITableViewCell是否已经存在了。如果还没有存在,cell == nil ,那么我们需要构造一个;如果已经存在了,那么我们需要做的就是根据它的行号,设置所需要显示的文本内容。

 

好了,到这里,我们就完成了编码的工作。下面我们双击FoodListView.xib,来修改这里的内容。原来,我们在这里放置了一个UILabel的控件,现在,我们将它替换成UITableView。如下图所示:

table view

接下来,我们要将UITableView的delegate和data source都指定为File's Owner。如下图所示

connect delegate

这样,程序在运行时,就会知道要去FoodListController中寻找接口函数了。

最后,再将UITableView * table和控件联系起来。

 

好了!编译运行吧!你应该能看到:

screen shot UILabel View

怎么样,这个效果比之前我们看到的UILabel要好很多吧:)

之后,我们还会看到如何和UITableView进行一些交互,如何实现search的功能等等。

 

<think>好的,我现在需要帮助用户了解如何在Qt中使用tableView与数据库进行交互,特别是示例教程。首先,我需要回想一下Qt中处理数据库和tableView的基本流程。记得Qt通常使用模型/视图架构,所以tableView作为视图,需要与数据模型连接。而数据库操作一般会用到QSql相关的类,比如QSqlDatabase、QSqlQuery,以及QSqlTableModel或者QSqlQueryModel作为模型。 首先,用户提到的引用[1]和[2]中提到了使用QStandardItemModel来填充tableView,但用户现在的问题是关于数据库的,所以应该使用QSql相关的模型。这可能涉及到如何连接数据库、执行查询,并将结果展示在tableView中。需要确认Qt支持的数据库类型,比如SQLite、MySQL等,这里可能以SQLite为例,因为不需要额外配置服务器,适合示例。 接下来,步骤可能包括: 1. 连接数据库:使用QSqlDatabase建立连接,设置数据库类型、主机名、数据库名、用户名和密码等。 2. 创建模型:使用QSqlTableModel或者QSqlQueryModel来获取数据。QSqlTableModel更适合可编辑的表格,而QSqlQueryModel适合只读的情况。 3. 将模型设置到tableView视图中。 4. 可能的查询操作,比如筛选、排序等,通过模型的方法来实现。 然后,我需要考虑示例代码的结构,确保代码正确,比如正确的头文件包含、错误处理(比如检查数据库是否成功打开)、模型的正确使用。同时,用户可能需要了解如何执行查询并更新视图,所以可能需要包括一个按钮触发查询操作,使用QSqlQuery执行自定义SQL,然后更新模型。 需要注意的事项包括:在.pro文件中添加sql模块,即QT += sql;数据库驱动是否可用,比如SQLite的驱动是否编译进Qt;以及模型的数据如何刷新显示。 可能的问题点:用户可能在连接数据库时遇到问题,比如路径错误或者驱动未加载,所以在代码中应该包括检查数据库是否成功打开的语句,并输出错误信息。另外,使用QSqlQueryModel时,可能需要手动设置表头,因为自动生成的列名可能不符合需求。 然后,根据这些步骤,整理出一个示例流程,分步骤说明,并附上代码。同时,生成的相关问题需要围绕数据库操作和tableView的深入使用,比如如何编辑并保存数据到数据库、如何处理大量数据的分页,以及如何自定义显示格式等。 最后,确保所有数学公式或行内代码使用正确的格式,比如数据库名称用$符号包裹,但可能这里不需要数学公式,主要注意代码块和步骤的结构清晰。同时,引用用户提供的引用内容,但根据问题,引用[1]和[2]是关于QStandardItemModel的,可能和数据库模型无关,但可能用户想结合两者,不过根据问题,应该直接使用QSql模型,所以引用可能作为补充,但主要回答应围绕数据库操作。不过根据用户提供的引用,他们可能已经了解QStandardItemModel,现在想迁移到数据库,所以需要说明两者的区别,并给出数据库示例。 现在需要把这些思路整理成一个结构化的回答,分步骤说明如何操作,并给出示例代码,确保代码正确且关键部分有注释。同时,生成的相关问题要针对用户可能进一步想了解的内容,比如数据提交、事务处理、模型子类化等。</think>### 在 Qt 中使用 TableView 与数据库交互的步骤及示例 #### 1. **配置数据库连接** 首先需在 `.pro` 文件中添加 SQL 模块支持: ```qmake QT += sql ``` 然后在代码中建立数据库连接(以 SQLite 为例): ```cpp #include <QSqlDatabase> #include <QSqlError> QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("example.db"); // 数据库文件路径 if (!db.open()) { qDebug() << "数据库连接失败:" << db.lastError().text(); return; } ``` #### 2. **创建数据模型** 使用 `QSqlTableModel` 或 `QSqlQueryModel` 加载数据。`QSqlTableModel` 支持编辑和自动刷新: ```cpp #include <QSqlTableModel> QSqlTableModel *model = new QSqlTableModel(this); model->setTable("students"); // 数据库表名 model->select(); // 加载数据 model->setEditStrategy(QSqlTableModel::OnManualSubmit); // 手动提交修改 ``` #### 3. **绑定模型到 TableView** 将模型关联到 `QTableView`: ```cpp #include <QTableView> QTableView *tableView = new QTableView(this); tableView->setModel(model); tableView->show(); ``` #### 4. **执行查询与更新** 通过按钮触发查询并更新视图(示例使用 `QSqlQuery`): ```cpp void MainWindow::on_searchButton_clicked() { QString name = ui->lineEdit->text(); QSqlQuery query; query.prepare("SELECT * FROM students WHERE name LIKE ?"); query.addBindValue("%" + name + "%"); if (query.exec()) { QSqlQueryModel *queryModel = new QSqlQueryModel(this); queryModel->setQuery(query); tableView->setModel(queryModel); // 更新模型 } } ``` #### 完整示例代码 ```cpp #include <QtWidgets> #include <QtSql> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 连接数据库 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("test.db"); if (!db.open()) { qDebug() << "Error:" << db.lastError().text(); return -1; } // 创建模型 QSqlTableModel model; model.setTable("employees"); model.select(); // 设置 TableView QTableView view; view.setModel(&model); view.show(); return app.exec(); } ``` #### 关键特性说明 - **数据编辑**:若需保存修改,调用 `model.submitAll()`。 - **表头自定义**:通过 `model.setHeaderData(0, Qt::Horizontal, "ID")` 修改列标题。 - **事务支持**:使用 `db.transaction()` 和 `db.commit()` 实现批量操作[^2]。 ---
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值