探索Qt与KDE开发:从基础组件到CD数据库应用
1. QListView组件详解
QListView 组件功能强大且复杂,它既可以作为项目列表,也能呈现项目树结构。使用时,需要为列表中的每个项目创建 QListViewItem 实例,每个实例都有一个父项。若以组件本身为父项,该项目将显示为顶级项目;若以另一个 QListViewItem 为父项,则显示为子项目。以下是其工作流程:
graph TD
A[创建QListViewItem实例] --> B{确定父项}
B -- 组件本身 --> C[显示为顶级项目]
B -- 其他QListViewItem --> D[显示为子项目]
编译并运行 ListView 示例后,可看到 QListView 组件的实际效果。子行相对于其父行会有缩进,默认情况下,指示隐藏或可折叠行的加减框并不显示,可通过
setRootIsDecorated
方法进行设置。
2. 对话框类型及使用
在开发中,除了通过子类化 QMainWindow 创建界面,对于短期使用的对话框,可使用 QDialog 组件。Qt 提供了三种类型的对话框:
| 对话框类型 | 特点 | 适用场景 |
| ---- | ---- | ---- |
| 模态对话框 | 阻止对其他窗口的输入,强制用户响应 | 获取用户即时响应、显示关键错误信息 |
| 非模态对话框 | 非阻塞窗口,可与应用中的其他窗口正常交互 | 搜索或输入窗口,方便与主窗口进行复制粘贴操作 |
| 半模态对话框 | 无自己的事件循环,可将控制权返回给应用,但仍阻止除对话框外的输入 | 显示耗时关键操作的进度条,允许用户取消操作 |
2.1 QDialog 基础使用
QDialog 是 Qt 中的基础对话框类,提供了
exec
和
show
方法来处理模态和非模态对话框,还包含一个可使用的 QLayout 以及多个用于响应按钮点击的信号和槽。以下是创建自定义对话框的示例代码:
#include <qdialog.h>
MyDialog::MyDialog(QWidget *parent, const char *name) : QDialog(parent, name)
{
QHBoxLayout *hbox = new QHBoxLayout(this);
hbox->addWidget(new Qlabel(“Enter your name”));
hbox->addWidget(new QLineEdit());
hbox->addWidget(ok_pushbutton);
hbox->addWidget(cancel_pushbutton);
connect (ok_pushbutton, SIGNAL(clicked()), this, SLOT(accept()));
connect (cancel_pushbutton, SIGNAL(clicked()), this, SLOT(reject()));
}
与 QMainWindow 不同,可直接将 MyDialog 指定为 QLayout 对象的父项,无需创建虚拟 QWidget。QDialog 有
accept
和
reject
两个槽,用于指示对话框的结果,该结果由
exec
方法返回。
2.2 模态对话框使用
使用模态对话框时,调用
exec
方法,根据激活的槽返回
QDialog::Accepted
或
QDialog::Rejected
:
MyDialog *dialog = new MyDialog(this, “mydialog”);
if (dialog->exec() == QDialog::Accepted)
{
// User clicked ‘Ok’
doSomething();
}
else
{
// user clicked ‘Cancel’ or dialog killed
doSomethingElse();
}
delete dialog;
exec
方法返回时,对话框会自动隐藏,但仍需从内存中删除该对象。需要注意的是,调用
exec
时会阻塞所有处理,因此若应用中有时间敏感的代码,使用非模态或半模态对话框更为合适。
2.3 非模态对话框使用
非模态对话框与普通主窗口类似,不同之处在于它会定位在其父窗口之上,共享任务栏条目,并在调用
accept
或
reject
槽时自动隐藏。显示非模态对话框可使用
show
方法:
MyDialog *dialog = new MyDialog(this, “mydialog”);
dialog->show();
为处理按钮点击事件,需要编写并连接相应的槽:
MyDialog::MyDialog(QWidget *parent, const char *name) : QDialog(parent, name)
{
...
connect (ok_pushbutton, SIGNAL(clicked()), this, SLOT(OkClicked()));
connect (cancel_pushbutton, SIGNAL(clicked()), this, SLOT(CancelClicked()));
}
MyDialog::OkClicked()
{
//Do some processing
}
MyDialog::CancelClicked()
{
//Do some other processing
}
按钮被按下时,对话框会像模态对话框一样自动隐藏。
2.4 半模态对话框使用
创建半模态对话框时,需在 QDialog 构造函数中设置模态标志,并使用
show
方法:
MySMDialog::MySMDialog(QWidget *parent, const char *name):QDialog(parent, name, TRUE)
{
...
}
MySMDialog *dialog = MySMDialog(this, “semimodal”);
dialog->show();
while (processing)
{
doSomeProcessing();
app->processEvents();
if (dialog->wasCancelled())
break;
}
在继续处理之前,需检查对话框是否已被取消。注意,
wasCancelled
方法并非 QDialog 的一部分,需要自行实现。
3. 预定义对话框使用
Qt 提供了一些预定义的 QDialog 子类,用于特定任务,如文件选择、文本输入、进度条和消息框等。使用这些组件可节省大量开发时间。
3.1 QMessageBox
QMessageBox 是一种模态对话框,用于显示带有图标和按钮的简单消息。图标取决于消息的严重程度,该类提供了静态方法来创建和显示三种类型的消息框:
#include <qmessagebox.h>
int information (QWidget *parent, const QString &caption, const QString &text,
int button0, int button1=0, int button2=0)
int warning (QWidget *parent, const QString &caption, const QString &text,
int button0, int button1, int button2=0)
int critical (QWidget *parent, const QString &caption, const QString &text,
int button0, int button1, int button2=0)
可从一系列标准按钮中选择按钮,并根据静态方法的返回值进行相应处理:
int result = QMessageBox::information(this,
“Engine Room Query”, “Do you wish to engage the HyperDrive?”,
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape);
switch (result) {
case QMessageBox::Yes:
hyperdrive->engage();
break;
case QMessageBox::No:
// do something else
break;
}
3.2 QInputDialog
QInputDialog 用于从用户处输入单个值,可输入文本、下拉列表中的选项、整数或浮点数。该类提供了静态方法,虽然参数较多,但大多数参数有默认值:
#include <qinputdialog.h>
QString getText (const QString &caption, const QString &label,
QLineEdit::EchoMode mode=QLineEdit::Normal,
const QString &text=QString::null, bool * ok = 0,
QWidget * parent = 0, const char * name = 0)
QString getItem (const QString &caption, const QString &label,
const QStringList &list, int current=0, bool editable=TRUE,
bool * ok=0, QWidget *parent = 0, const char *name=0)
int getInteger (const QString &caption, const QString &label, int num=0,
int from = -2147483647, int to = 2147483647, int step = 1,
bool * ok = 0, QWidget * parent = 0, const char * name = 0)
double getDouble (const QString &caption, const QString &label, double num = 0,
double from = -2147483647, double to = 2147483647,
int decimals = 1, bool * ok = 0, QWidget * parent = 0,
const char * name = 0 )
以下是输入单行文本的示例:
bool result;
QString text = QInputDialog::getText(“Question”, “What is your Quest?:”,
QLineEdit::Normal,
QString::null, &result, this, “input” );
if (result) {
doSomething(text);
} else {
// user pressed cancel
}
4. 使用 qmake 简化 Makefile 编写
编译同时使用 KDE 和 Qt 库的应用程序时,Makefile 会变得非常复杂,因为需要使用 moc 且库文件分散在各处。幸运的是,Qt 提供了 qmake 工具来自动创建 Makefile。qmake 以
.pro
文件为输入,该文件包含编译所需的基本信息,如源文件、头文件、目标二进制文件以及 KDE/Qt 库的位置。以下是一个典型的 KDE
.pro
文件示例:
TARGET = app
MOC_DIR = moc
OBJECTS_DIR = obj
INCLUDEPATH = /usr/include/kde
QMAKE_LIBDIR_X11 += /usr/lib
QMAKE_LIBS_X11 += -lkdeui -lkdecore
SOURCES = main.cpp window.cpp
HEADERS = window.h
使用以下命令生成 Makefile:
$ qmake file.pro –o Makefile
然后即可像往常一样运行
make
命令进行编译。对于任何复杂度的 KDE/Qt 程序,使用 qmake 可简化构建过程。
5. KDE 中的菜单和工具栏
KDE 提供了强大的组件来创建菜单和工具栏,与普通 Qt 或其他 GUI 工具包相比,可节省大量时间和精力。通常在 GUI 库中,菜单项和工具栏项是独立的元素,需要分别创建对象并跟踪更改。而 KDE 定义了 KAction 组件来表示应用程序可以执行的操作,如打开新文档、保存文件或显示帮助框等。
5.1 KAction 使用
KAction 可设置文本、键盘快捷键、图标和激活时调用的槽:
KAction *new_file = new KAction(“New”, “filenew”,
KstdAccel::shortcut(KstdAccel::New),
this, SLOT(newFile()), this, “newaction”);
然后可将 KAction 插入到菜单和工具栏中,无需进一步描述:
new_file->plug(a_menu);
new_file->plug(a_toolbar);
若需要禁用 KAction,只需调用
setEnabled(FALSE)
方法。
5.2 示例代码
以下是一个使用 KAction 创建菜单和工具栏的示例:
// KDEMenu.h
#include <kde/kmainwindow.h>
class KDEMenu : public KMainWindow
{
Q_OBJECT
public:
KDEMenu(const char * name = 0);
private slots:
void newFile();
void aboutApp();
};
// KDEMenu.cpp
#include “KDEMenu.h”
#include <kde/kapp.h>
#include <kde/kaction.h>
#include <kde/kstdaccel.h>
#include <kde/kmenubar.h>
#include <kde/kaboutdialog.h>
KDEMenu::KDEMenu(const char *name = 0) : KMainWindow (0L, name )
{
KAction *new_file = new KAction(“New”, “filenew”,
KstdAccel::shortcut(KstdAccel::New),
this, SLOT(newFile()), this, “newaction”);
KAction *quit_action = KStdAction::quit(KApplication::kApplication(),
SLOT(quit()), actionCollection());
KAction *help_action = KStdAction::aboutApp(this, SLOT(aboutApp()),
actionCollection());
QPopupMenu *file_menu = new QPopupMenu;
QPopupMenu *help_menu = new QPopupMenu;
menuBar()->insertItem(“&File”, file_menu);
menuBar()->insertItem(“&Help”, help_menu);
new_file->plug(file_menu);
file_menu->insertSeparator();
quit_action->plug(file_menu);
help_action->plug(help_menu);
new_file->plug(toolBar());
quit_action->plug(toolBar());
}
void KDEMenu::newFile()
{
// Create new File
}
void KDEMenu::aboutApp()
{
KAboutDialog *about = new KAboutDialog(this, “dialog”);
about->setAuthor(QString(“A. N. Author”), QString(“an@email.net”),
QString(“http://url.com”), QString(“work”));
about->setVersion(“1.0”);
about->show();
}
int main(int argc, char **argv)
{
KApplication app( argc, argv, “cdapp” );
KDEMenu *window = new KDEMenu(“kdemenu”);
app.setMainWidget(window);
window->show();
return app.exec();
}
还需要一个
menu.pro
文件用于 qmake:
TARGET = kdemenu
MOC_DIR = moc
OBJECTS_DIR = obj
INCLUDEPATH = /usr/include/kde
QMAKE_LIBDIR_X11 += -L$KDEDIR/lib
QMAKE_LIBS_X11 += -lkdeui -lkdecore
SOURCES = KDEMenu.cpp
HEADERS = KDEMenu.h
运行以下命令生成 Makefile 并编译运行:
$ qmake menu.pro –o Makefile
$ make
$ ./kdemenu
通过以上步骤,可利用 KDE 的强大功能创建出功能丰富、易于维护的菜单和工具栏。
探索Qt与KDE开发:从基础组件到CD数据库应用
6. CD数据库应用开发
接下来将使用 KDE/Qt 开发一个 CD 数据库应用程序,该应用程序需要实现以下功能:
- 从 GUI 登录数据库
- 搜索 CD
- 显示 CD 和曲目信息
- 向数据库添加 CD
- 显示关于窗口
6.1 主窗口开发
主窗口包含搜索输入框和搜索结果列表,以下是详细的开发步骤:
步骤 1:定义主窗口类
在
MainWindow.h
中定义主窗口类,需要包含
qlistview.h
和
qlineedit.h
头文件:
#include <kde/kmainwindow.h>
#include <qlistview.h>
#include <qlineedit.h>
class MainWindow : public KMainWindow
{
Q_OBJECT
public:
MainWindow (const char *name);
public slots:
void doSearch();
void AddCd();
private:
QListView *list;
QLineEdit *search_entry;
};
步骤 2:实现主窗口构造函数
在
MainWindow.cpp
中实现主窗口的构造函数,创建主窗口界面并连接信号和槽:
#include “MainWindow.h”
#include “AddCdDialog.h”
#include “app_mysql.h”
#include <qvbox.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qlistview.h>
#include <kde/kapp.h>
#include <kde/kmenubar.h>
#include <kde/klocale.h>
#include <kde/kpopupmenu.h>
#include <kde/kstatusbar.h>
#include <kde/kaction.h>
#include <kde/kstdaccel.h>
#include <string.h>
MainWindow::MainWindow ( const char * name ) : KMainWindow ( 0L, name )
{
setCaption(“CD Database”);
// 创建菜单和工具栏条目
KAction *addcd_action = new KAction(“&Add CD”, “filenew”,
KStdAccel::shortcut(KStdAccel::New),
this,
SLOT(AddCd()),
this);
KAction *quit_action = KStdAction::quit(KApplication::kApplication(),
SLOT(quit()), actionCollection());
QPopupMenu * file_menu = new QPopupMenu;
QPopupMenu * help_menu = new QPopupMenu;
menuBar()->insertItem(“&File”, file_menu);
menuBar()->insertItem(“&Help”, help_menu);
addcd_action->plug(file_menu);
file_menu->insertSeparator();
quit_action->plug(file_menu);
addcd_action->plug(toolBar());
quit_action->plug(toolBar());
// 使用 QBox 布局
QVBox *vbox = new QVBox (this);
QHBox *hbox = new QHBox (vbox);
QLabel *label = new QLabel(hbox);
label->setText( “Search Text:” );
search_entry = new QLineEdit ( hbox );
QPushButton *button = new QPushButton( “Search”, hbox);
// 创建 QListView 并设置列
list = new QListView( vbox, “name”, 0L);
list->setRootIsDecorated(TRUE);
list->addColumn(“Title”);
list->addColumn(“Artist”);
list->addColumn(“Catalogue”);
// 连接信号和槽
connect(button, SIGNAL (clicked()), this, SLOT (doSearch()));
connect(search_entry , SIGNAL(returnPressed()), this, SLOT(doSearch()));
statusBar()->message(“”);
setCentralWidget(vbox);
resize (300,400);
}
步骤 3:实现搜索功能
doSearch
槽函数实现了搜索功能,读取搜索字符串并获取匹配的 CD 和曲目信息:
void MainWindow::doSearch()
{
cd_search_st *cd_res = new cd_search_st;
current_cd_st *cd = new current_cd_st;
struct current_tracks_st ct;
int res1, i, j, res2, res3;
char track_title[110];
char search_text[100];
char statusBar_text[200];
QListViewItem *cd_item;
strcpy(search_text, search_entry->text());
// 获取匹配的 CD ID
res1 = find_cds(search_text, cd_res);
sprintf(statusBar_text, “ Displaying %d result(s) for search string ‘ %s ‘“,
res1, search_text);
statusBar()->message(statusBar_text);
i = 0;
list->clear();
// 遍历每个 CD ID
while (i < res1) {
res2 = get_cd(cd_res->cd_id[i], cd);
cd_item = new QListViewItem(list, cd->title, cd->artist_name, cd->catalogue);
res3 = get_cd_tracks(cd_res->cd_id[i++], &ct);
j = 0;
// 显示每个 CD 的曲目信息
while (j < res3) {
sprintf(track_title, “ Track %d. “, j+1);
strcat(track_title, ct.track[j++]);
new QListViewItem(cd_item, track_title);
}
}
}
步骤 4:实现添加 CD 功能
AddCd
槽函数在点击添加 CD 菜单项或工具栏按钮时被调用:
void MainWindow::AddCd()
{
AddCdDialog *dialog = new AddCdDialog(this);
dialog->show();
}
6.2 添加 CD 对话框开发
添加 CD 对话框用于向数据库中添加新的 CD,以下是开发步骤:
步骤 1:定义添加 CD 对话框类
在
AddCdDialog.h
中定义添加 CD 对话框类,继承自
KDialogBase
:
#include <kde/kdialogbase.h>
#include <qlineedit.h>
class AddCdDialog : public KDialogBase
{
Q_OBJECT
public:
AddCdDialog (QWidget *parent);
private:
QLineEdit *artist_entry, *title_entry, *catalogue_entry;
public slots:
void okClicked();
};
步骤 2:实现添加 CD 对话框构造函数
在
AddCdDialog.cpp
中实现对话框的构造函数,并在
okClicked
槽函数中调用添加 CD 的函数:
#include “AddCdDialog.h”
#include “app_mysql.h”
#include <qlayout.h>
#include <qlabel.h>
AddCdDialog::AddCdDialog( QWidget *parent)
: KDialogBase( parent, “AddCD”, false, “Add CD”,
KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true )
{
QWidget *widget = new QWidget(this);
setMainWidget(widget);
QGridLayout *grid = new QGridLayout(widget,3,2,10, 5,”grid”);
grid->addWidget(new QLabel(“Artist”, widget, “artistlabel”), 0, 0, 0);
grid->addWidget(new QLabel(“Title”, widget, “titlelabel”), 1, 0, 0);
grid->addWidget(new QLabel(“Catalogue”, widget, “cataloguelabel”), 2, 0, 0);
artist_entry = new QLineEdit( widget, “artist_entry”);
title_entry = new QLineEdit( widget, “title_entry”);
catalogue_entry = new QLineEdit( widget, “catalogue_entry”);
grid->addWidget(artist_entry, 0,1, 0);
grid->addWidget(title_entry, 1,1, 0);
grid->addWidget(catalogue_entry, 2,1, 0);
connect (this, SIGNAL(okClicked()), this, SLOT(okClicked()));
}
void AddCdDialog::okClicked()
{
char artist[200];
char title[200];
char catalogue[200];
int cd_id = 0;
strcpy(artist, artist_entry->text());
strcpy(title, title_entry->text());
strcpy(catalogue, catalogue_entry->text());
add_cd(artist, title, catalogue, &cd_id);
}
6.3 登录对话框开发
登录对话框用于用户输入数据库登录凭证,以下是开发步骤:
步骤 1:定义登录对话框类
在
LogonDialog.h
中定义登录对话框类,继承自
QDialog
:
#include <qdialog.h>
#include <qlineedit.h>
class LogonDialog : public QDialog
{
Q_OBJECT
public:
LogonDialog (QWidget *parent = 0, const char *name = 0);
QString getUsername();
QString getPassword();
private:
QLineEdit *username_entry, *password_entry;
};
步骤 2:实现登录对话框构造函数和方法
在
LogonDialog.cpp
中实现对话框的构造函数和获取用户名、密码的方法:
#include “LogonDialog.h”
#include “app_mysql.h”
#include <qpushbutton.h>
#include <qlayout.h>
#include <qlabel.h>
LogonDialog::LogonDialog( QWidget *parent, const char *name): QDialog(parent, name)
{
QGridLayout *grid = new QGridLayout(this, 3, 2, 10, 5,”grid”);
grid->addWidget(new QLabel(“Username”, this, “usernamelabel”), 0, 0, 0);
grid->addWidget(new QLabel(“Password”, this, “passwordlabel”), 1, 0, 0);
username_entry = new QLineEdit( this, “username_entry”);
password_entry = new QLineEdit( this, “password_entry”);
password_entry->setEchoMode(QLineEdit::Password);
grid->addWidget(username_entry, 0, 1, 0);
grid->addWidget(password_entry, 1, 1, 0);
QPushButton *button = new QPushButton (“Ok”, this, “button”);
grid->addWidget(button, 2, 1,Qt::AlignRight);
connect (button, SIGNAL(clicked()), this, SLOT(accept()));
}
QString LogonDialog::getUsername()
{
if (username_entry == NULL)
return NULL;
return username_entry->text();
}
QString LogonDialog::getPassword()
{
if (password_entry == NULL)
return NULL;
return password_entry->text();
}
6.4 主函数实现
在
main.cpp
中实现主函数,打开登录对话框并处理登录逻辑:
#include “MainWindow.h”
#include “app_mysql.h”
#include “LogonDialog.h”
#include <kde/kapp.h>
#include <qmessagebox.h>
int main( int argc, char **argv )
{
char username[100];
char password[100];
KApplication a( argc, argv, “cdapp” );
LogonDialog *dialog = new LogonDialog();
while (1)
{
if (dialog->exec() == QDialog::Accepted)
{
strcpy(username, dialog->getUsername());
strcpy(password, dialog->getPassword());
if (database_start(username, password))
break;
QMessageBox::information(0, “Title”,
“Could not Logon: Check username and/or password”,
QMessageBox::Ok);
continue;
}
else
{
if (QMessageBox::information(0, “Title”,
“Are you sure you want to quit?”,
QMessageBox::Yes, QMessageBox::No)
== QMessageBox::Yes)
return 0;
}
}
MainWindow *window = new MainWindow(“mainwindow”);
a.setMainWidget(window);
window->show();
return a.exec();
}
总结
通过以上步骤,我们完成了一个基于 Qt 和 KDE 的 CD 数据库应用程序的开发。从基础的 QListView 组件和对话框使用,到使用 qmake 简化编译过程,再到利用 KDE 的 KAction 组件创建菜单和工具栏,最后实现了 CD 数据库应用的各项功能。整个开发过程展示了 Qt 和 KDE 在 GUI 开发中的强大功能和便捷性,希望这些内容能帮助你更好地进行 Qt 和 KDE 开发。
以下是整个 CD 数据库应用的开发流程 mermaid 图:
graph LR
A[开始] --> B[创建主窗口]
B --> C[创建登录对话框]
C --> D{登录成功?}
D -- 是 --> E[显示主窗口]
D -- 否 --> C
E --> F[实现搜索功能]
E --> G[实现添加 CD 功能]
F --> H[显示搜索结果]
G --> I[添加 CD 到数据库]
H --> J[结束]
I --> J
这个流程图展示了 CD 数据库应用的主要开发流程,从登录到搜索、添加 CD 等功能的实现,最后结束应用。通过这个流程,你可以更清晰地了解整个应用的开发过程。
Qt与KDE开发:从组件到CD数据库应用
超级会员免费看
6367

被折叠的 条评论
为什么被折叠?



