一、主窗口框架
1.菜单栏和工具栏
(1)菜单栏
①Qt提供与菜单相关的类组件
②QMenuBar类、QMenu类和QAction类
●QMenuBar:QMenuBar类提供了一个水平的菜单栏,可以在此基础上添加不同的QMenu和QAction。一个主窗口只可以有一个菜单栏。
●QMenu:菜单栏里面菜单(如File、Edit、Format等菜单)或者带有三角形符号的菜单项(表示其下仍有子菜单),可以显示文本和图标,但是并不负责执行操作,有点类似label的作用。
●QAction: Qt 将用户与界面进行交互的元素抽象为一种“动作”,使用QAction类表示。QAction才是真正负责执行操作的部件。
联系:QMainWindow中可以直接获取它的默认存在的QMenuBar菜单栏对象,向其(QMenuBar菜单栏对象)添加QMenu类型的菜单对象,然后向弹出的菜单中添加QAction类型的动作对象。
代码:
QMenuBar* mb = menuBar(); //调用QMainWidow的成员函数menuBar 用该函数就可以得到QMainWindow里面的菜单栏对象即 主窗口里面的菜单栏对象
QMenu* menu = new QMenu("File(&F)");
QAction* action = new QAction("New",NULL);
menu->addAction(action); //将action加入菜单项中
mb->addMenu(menu); //将菜单项加入MenuBar中
③代码方式添加菜单
// 添加编辑菜单
QMenu *editMenu = ui->menuBar->addMenu(tr("编辑(&E)"));
// 添加打开菜单
QAction *action_Open = editMenu->addAction(
QIcon(“:/images/open.png"),tr("打开文件(&O)"));
// 设置快捷键
action_Open->setShortcut(QKeySequence("Ctrl+O"));
// 在工具栏中添加动作
ui->mainToolBar->addAction(action_Open);
(2)工具栏
工具栏QToolBar类提供了一个包含了一组控件的可以移动的面板。它默认只是显示一个动作的图标,这个可以在QToolBar的属性栏中进行更改。
在设计器中可以查看QToolBar的属性栏,其中toolButtonStyle属性设置图标和相应文本的显示及其相对位置等;movabel属性设置状态栏是否可以移动;
allowedArea设置允许停靠的位置;iconsize属性设置图标的大小;floatable属性设置是否可以悬浮。
例如:
QToolButton *toolBtn = new QToolButton(this); // 创建QToolButton
toolBtn->setText(tr("颜色"));
QMenu *colorMenu = new QMenu(this); // 创建一个菜单
colorMenu->addAction(tr("红色"));
colorMenu->addAction(tr("绿色"));
toolBtn->setMenu(colorMenu); // 添加菜单
toolBtn->setPopupMode(QToolButton::MenuButtonPopup); // 设置弹出模式
ui->mainToolBar->addWidget(toolBtn); // 向工具栏添加QToolButton按钮
QSpinBox *spinBox = new QSpinBox(this); // 创建QSpinBox
ui->mainToolBar->addWidget(spinBox); // 向工具栏添加QSpinBox部件
2.使用资源系统
可以让需要的文件(图片、文本等)包含到程序编程生成的可执行文件(例如exe文件)中。保证了程序中使用的文件不会丢失、不会因为存放路径而导致程序运行错误。
添加资源系统的过程:
在工程中添加资源文件:
①在工程名处右击鼠标,选择“添加新文件”。
②再将添加的文件类型选择为Qt资源文件。
③接下来,为新添加的资源文件命名。
注意,这个资源文件名不是你要添加的图片等资源的文件名,而是添加到工程中的资源文件名称(该文件用于管理随后要添加的真正的资源文件)。
④然后指定将该资源文件添加到哪个工程。如果同时打开了多个工程,在此可以进行选择。如果只打开了一个工程,保持默认即可。
在资源文件中添加资源:
①首先,在工程中选中资源文件,然后点击下方添加按钮的下拉箭头,再点击“添加前缀”。
②前缀的名称可以根据需要来取,一般建议指定为资源的类型,以便于区分。
③添加前缀之后,我们就可以添加文件了。
④找到要添加的资源文件,将它加入到工程中来。
为资源文件取别名:
要想对资源文件取别名,首先我们需要选中要取别名的文件,然后再为其取一个别名即可。
3.中心部件
在主窗口的中心区域可以放置一个中心部件,它一般是一个编辑器或者浏览器。这里支持单文档部件,也支持多文档部件。
一般的,会在这里放置一个部件,然后使用布局管理器使其充满整个中心区域,并可以随着窗口的大小变化而改变大小。
4.Dock部件
QDockWidget类提供了这样一个部件,它可以停靠在QMainWindow中也可以悬浮起来作为桌面顶级窗口,我们称它为Dock部件或者停靠窗口。
Dock部件一般用于存放其他一些部件来实现一些特殊功能,就像一个工具箱一样。它在主窗口中可以停靠在中心部件的四周,也可以悬浮起来,被拖动到任意的地方,还可以被关闭或隐藏起来。一个Dock部件包含一个标题栏和一个内容区域,可以向Dock部件中放入任何部件。
5.状态栏
QStatusBar类提供了一个水平条,用来显示状态信息。QMainWindow中默认提供了一个状态栏。
状态信息可以被分为三类:临时信息,如一般的提示信息;正常信息,如显示页数和行号;永久信息,如显示版本号或者日期。
可以使用showMessage()函数来显示一个临时消息,它会出现在状态栏的最左边。一般用addWidget()函数添加一个QLabel到状态栏上用于显示正常信息,它会生成到状态栏的最左边,可能会被临时消息所掩盖。如果要显示永久信息,要使用addPermanentWidget()函数来添加一个如QLabel一样的可以显示信息的部件,它会生成在状态栏的最右端,不会被临时消息所掩盖。
在状态栏的最右端,还有一个QSizeGrip部件,用来调整窗口的大小,可以使用setSizeGripEnabled()函数来禁用它。
6.自定义菜单
Qt中的QWidgetAction类可以实现自定义菜单的功能。为了实现自定义菜单,需要新建一个类,它继承自QWidgetAction类,并且在其中重新实现createWidget()函数。
补充:
(1)emit
当对象改变信号与槽状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。
代码示例:
signals:
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
private slots:
void findClicked();
void enableFindButton(const QString &text);
void FindDialog::findClicked()
{
Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseInsensitive : Qt::CaseSensitive;
if(backwardCheckBox->isChecked())
{
emit findPrevious(text, cs);
}
else
{
void findNext(const QString &str, Qt::CaseSensitivity cs);
emit findNext(text, cs);
}
}
//emit是将信号findNext或信号findPrevious发射出去。
//说白了,就是调用findPrevious或者findNext信号对应的槽函数,emit之前,在某个地方,肯定有connect把信号和槽进行关联,
//关联了之后,emit某个信号,就相当于调用这个信号connect时所关联的槽函数
(2)Qt之创建自定义类型
在开始之前,需要确保创建的这个自定义类型符合QMetaType的规定的所有要求。换句话说,它必须提供:
●一个公有的默认构造函数
●一个公有的拷贝构造函数
●一个公有的析构函数
下面的Message类的定义包含了这些成员:
class Message
{
public:
Message();
Message(const Message &other);
~Message();
Message(const QString &body, const QStringList &headers);
QString body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};
这个类同时还提供了一个经常使用的构造函数,以及两个用于获取私有数据的共有成员函数。
二、富文本处理
富文本(Rich Text)或者叫做富文本格式,简单来说就是在文档中可以使用多种格式,比如字体颜色、图片和表格等等。
(1)富文本文档结构
在Qt中提供了对富文本处理的支持。Qt中对富文本的处理分为了编辑操作和只读操作两种方式。
●编辑操作是使用基于光标的一些接口函数,这样更好的模拟了用户的编辑操作,更加容易理解,而且不会丢失底层的文档框架。
●而对于文档结构的概览,使用了只读的分层次的接口函数,它们有利于文档的检索和输出。
对于文档的读取和编辑要使用不同方面的两组接口。
●文档的光标主要基于QTextCursor类
●文档的框架主要基于QTextDocument类
一个富文本文档的结构被分为了几种元素来表示:
●框架(QTextFrame)
●文本块(QTextBlock)
●表格(QTextTable)
●列表(QTextList)
每种元素的格式又使用相应的format类来表示:
●框架格式(QTextFrameFormat)
●文本块格式(QTextBlockFormat)
●表格格式(QTextTableFormat)
●列表格式(QTextListFormat)
这些格式一般在编辑文档时使用,所以它们常和QTextCursor类配合使用。
因为QTextEdit类就是一个富文本编辑器,所以在构建QTextEdit类的对象时就已经构建了一个QTextDocument类对象和一个QTextCursor类对象,只需调用它们进行相应的操作即可。
一个空的文档包含了一个根框架(Root frame),这个根框架又包含了一个空的文本块(Block)。框架将一个文档分为多个部分,在根框架里可以再添加文本块、子框架和表格等。
①设置根框架
QTextDocument *document = ui->textEdit->document(); //获取文档对象
QTextFrame *rootFrame = document->rootFrame(); // 获取根框架
QTextFrameFormat format; // 创建框架格式
format.setBorderBrush(Qt::red); // 边界颜色
format.setBorder(3); // 边界宽度
rootFrame->setFrameFormat(format); // 框架使用格式
②添加子框架
QTextFrameFormat frameFormat;
frameFormat.setBackground(Qt::lightGray); // 设置背景颜色
frameFormat.setMargin(10); // 设置边距
frameFormat.setPadding(5); // 设置填衬
frameFormat.setBorder(2);
frameFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Dotted); //设置边框样式
QTextCursor cursor = ui->textEdit->textCursor(); // 获取光标
cursor.insertFrame(frameFormat); // 在光标处插入框架
(2)文本块
文本块QTextBlock类为文本文档QTextDocument提供了一个文本片(QTextFragment)的容器。
一个文本块可以看做是一个段落,但是它不能使用回车换行,因为一个回车换行就表示创建一个新的文本块。QTextBlock提供了只读接口,它是前面提到的文档分层次的接口的一部分,如果QTextFrame看做是一层,那么其中的QTextBlock就是另一层。
文本块的格式由QTextBlockFormat类来处理,它主要涉及对齐方式,文本块四周的边白,缩进等内容。而文本块中的文本内容的格式,
比如字体大小、加粗、下划线等内容,则由QTextCharFormat类来设置。
①遍历框架
QTextDocument *document = ui->textEdit->document();
QTextFrame *frame = document->rootFrame();
QTextFrame::iterator it; // 建立QTextFrame类的迭代器
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();// 获取当前框架的指针
QTextBlock childBlock = it.currentBlock(); // 获取当前文本块
if (childFrame)
qDebug() << "frame";
else if (childBlock.isValid())
qDebug() << "block:" << childBlock.text();
}
②遍历子框架
QTextDocument *document = ui->textEdit->document();
QTextBlock block = document->firstBlock(); // 获取文档的第一个文本块
for (int i = 0; i < document->blockCount(); i++) {
qDebug() << tr("文本块%1,文本块首行行号为:%2,长度为:%3,内容为:").arg(i).arg(block.firstLineNumber()).arg(block.length())<< block.text();
block = block.next(); // 获取下一个文本块
}
③编辑文本块及其内容的格式
QTextCursor cursor = ui->textEdit->textCursor();
QTextBlockFormat blockFormat; // 文本块格式
blockFormat.setAlignment(Qt::AlignCenter); // 水平居中
cursor.insertBlock(blockFormat); // 使用文本块格式
QTextCharFormat charFormat;// 字符格式
charFormat.setBackground(Qt::lightGray); // 背景色
charFormat.setForeground(Qt::blue);// 字体颜色
// 使用宋体,12号,加粗,倾斜
charFormat.setFont(QFont(tr("宋体"), 12, QFont::Bold, true));
charFormat.setFontUnderline(true); // 使用下划线
cursor.setCharFormat(charFormat); // 使用字符格式
cursor.insertText(tr("测试字体")); // 插入文本
(3)表格、列表和图片
//插入表格
QTextCursor cursor = ui->textEdit->textCursor();
QTextTableFormat format; // 表格格式
format.setCellSpacing(2); // 表格外边白
format.setCellPadding(10); // 表格内边白
cursor.insertTable(2, 2, format); // 插入2行2列表格
//插入列表
QTextListFormat format; // 列表格式
format.setStyle(QTextListFormat::ListDecimal); // 数字编号
ui->textEdit->textCursor().insertList(format);
//插入图片
QTextImageFormat format; // 图片格式
format.setName("logo.png"); // 图片路径
ui->textEdit->textCursor().insertImage(format);
(4)查找功能
//查找文本
QDialog *dlg = new QDialog(this); // 创建对话框
lineEdit = new QLineEdit(dlg); // 创建行编辑器
QPushButton *btn = new QPushButton(dlg); // 创建按钮
btn->setText(tr("查找下一个"));
connect(btn,SIGNAL(clicked()),this,SLOT(findNext())); // 关联信号和槽
QVBoxLayout *layout = new QVBoxLayout; // 创建垂直布局管理器
layout->addWidget(lineEdit); // 添加部件
layout->addWidget(btn);
dlg->setLayout(layout); // 在对话框中使用布局管理器
dlg->show();
//查找下一个
QString string = lineEdit->text();
// 使用查找函数查找指定字符串,查找方式为向后查找
bool isfind = ui->textEdit->find(string, QTextDocument::FindBackward);
if(isfind){ // 如果查找成功,输出字符串所在行和列的编号
qDebug() << tr("行号:%1 列号:%2")
.arg(ui->textEdit->textCursor().blockNumber())
.arg(ui->textEdit->textCursor().columnNumber());
}
(5)语法高亮
在使用Qt Creator编辑代码时可以发现,输入关键字时会显示不同的颜色,这就是所谓的语法高亮。
在Qt的富文本处理中提供了QSyntaxHighlighter类来实现语法高亮。为了实现这个功能,需要创建QSyntaxHighlighter类的子类,然后重新实现highlightBlock()函数,使用时直接将QTextDocument类对象指针作为其父部件指针,这样就可以自动调用highlightBlock()函数了。
自定义的类为MySyntaxHighlighter,像这样来使用:
highlighter = new MySyntaxHighlighter(ui->textEdit->document());
重新实现highlightBlock()函数:
QTextCharFormat myFormat; // 字符格式
myFormat.setFontWeight(QFont::Bold);
myFormat.setForeground(Qt::green);
QString pattern = "\\bchar\\b"; // 要匹配的字符,这里是“char”单词
QRegExp expression(pattern); // 创建正则表达式
int index = text.indexOf(expression); // 从位置0开始匹配字符串
// 如果匹配成功,那么返回值为字符串的起始位置,它大于或等于0
while (index >= 0) {
int length = expression.matchedLength(); // 要匹配字符串的长度
setFormat(index, length, myFormat); // 对要匹配的字符串设置格式
index = text.indexOf(expression, index + length); // 继续匹配
}
//在这里主要是使用了正则表达式和QString类的indexOf()函数来进行字
(6)HTML
在富文本处理中还提供了对HTML子集的支持,可以在QLabel或者QTextEdit添加文本时使用HTML标签或者CSS属性,例如:
ui->textEdit->append(tr("<h1><font color=red>使用HTML</font></h1>"));
三、拖放操作
所用类及继承关系
拖放操作包括两个动作:拖动(drag)和放下(drop或称为放置)。当被拖动时拖动的数据会被存储为MIME类型(见第6章文件对话框)的对象,MIME类型使用QMimeData类来描述。
MIME类型通常由剪贴板和拖放系统使用,以识别不同类型的数据。
●拖动点(drag site):拖动的起始位置。
●放下点(drop site):被拖动的对象放下的位置,若部件不能接受拖动的对象,Qt会改变光标的形状(一个禁用形状)来向用户进行说明。
1.拖放的启动和结束
启动拖放:拖放通过调用QDrag::exec()函数而启动,该函数是一个阻塞函数(但不会阻塞主事件循环),这意味着在拖放操作结束之前,不会返回该函数,调用QDrag::exe()函数后,Qt拥有对拖动对象的所有权,并会在必要时将其删除。
结束拖放:当用户放下拖动或取消拖动操作时结束拖放。
2.拖放产生的过程及事件
启动拖放后,会使数据被拖动,这时需要按住鼠标按键才能拖动需要拖动的数据,松开鼠标按键时意味着拖动结束。在这期间会产生如下事件
默认情况下,部件不接受放下事件。使用QWidget::setAcceptDrops()函数可设置部件是否接受放下事件(即,拖放完成时发送的事件)。
只有在部件接受放下事件的情形下,才会产生以下事件。
①QDragEnterEvent:拖动进入事件。当拖动操作进入部件时,该事件被发送到部件,忽略该事件,将会导至后续的拖放事件不能被发送,此时在该部件上光标通常会在外观上显示为禁用的图形。
②QDragMoveEvnet:拖动移动事件。当拖动操作正在进行时,以及当具有焦点时按下键盘的修饰键(比如Ctrl)时,发送该事件,要使部件能接收到该事件,则该部件必须接受QDragEnterEvent事件。
③QDropEvent:放下事件。在完成拖放操作时发送该事件,即当用户在部件上放下一个对象时,发送此事件。要使部件能接收到该事件,则该部件必须接受QDragEnterEvent事件,且不能忽略QDragMoveEvnt事件。
④QDragLeaveEvent:当拖放操作离开部件时发送该事件,注意:要使部件能接收到该事件,必须要使拖动先进入该部件(即产生QDragEnterEvent事件),然后再离开该部件,才会产生QDragLeaveEvent事件。因很少使用该事件,因此本文不做重点介绍。
注:必须接受是指必须重新实现该事件的处理函数并接受该事件,不能忽略是指在处件事理函数中不明确调用ignore()函数忽略该事件。
3.编写拖放程序的步骤
●在需要接受放下数据的部件上调用QWidget::setAcceptDrops()函数以使该部件能接受拖放事件。
●启动拖放:通常在mousePressEvent()或mouseMoveEvent()函数中启动拖放,记住启动拖放就是调用QDrag对象的exec()函数,因此也可以在keyPressEvent()等函数中启动拖放(因很少这样做,所以本文不予介绍)。在此步把需要拖动的数据保存在QMimeData对象中。
●重新实现需要接受放下数据的部件的dragEnterEvent()事件处理函数。
●根据需要重新实现dragMoveEvent或dropEvent()函数
四、打印文档
打印设置
QPrinter类是打印设置的类。
1.OutputFormat
说明:
QPrinter输出文件的格式,QPrinter::PdfFormat会输入pdf文件格式,QPrinter::PostScriptFormat输入ps文件格式.中执行print()后生成的文件类型就是根据这个来的。
相关函数:
OutputFormat QPrinter::outputFormat () //当前格式
void QPrinter::setOutputFormat ( OutputFormat format )//设置格式
void QPrinter::setOutputFileName ( const QString & fileName )//文件名后缀设为ps即为ps格式,后缀为pdf即为pdf格式
2.其他部分参数
Orientation:纸张方向,有QPrinter::Portrait(纵向)和QPrinter::Landscape(横向)
void QPrinter::setOrientation ( Orientation orientation )
Orientation QPrinter::orientation ()
PaperSize: 纸张大小,有A4等
void QPrinter::setPaperSize ( PaperSize newPaperSize )
PaperSize QPrinter::paperSize ()
3.输出为文件:
可以作为输入的控件有以下几个:
①QWebView,QWebFrame,作为html文件格式的载体;
②QPlainTextEdit,QTextEdit, 单行/多行文本编辑区域;
③QPainter,用于绘图的类,可处理图片格式的文件;
④QPrintPreviewWidget,专门用于打印预览的控件;
⑤QTextDocument,文档类型的文件处理;
以上控件都有一个共同点,都有print()函数,将设置好的QPrinter传入即可,输出对应的文件。
(1)QWebView和QWebFrame
用途:作为html文件格式的载体
处理函数:
void QWebView::print ( QPrinter * printer )
void QTextDocument::print ( QPrinter * printer )
示例:
//全局的变量
QWebView *webview=0;
QPrinter *printer=0;
void printWebView(void)
{
if(webview!=0)
{
webview = new QWebView();
}
if(webview!=0)
{
printer = new QPrinter(QPrinter::PrinterResolution);
}
webview->load(QUrl(“file:///home/root/test.html”));
//因为加载会花费时间,等加载完成才能处理打印
connect(webview,SIGNAL(loadFinished(bool)),this,SLOT(loadend (bool)));
}
void loadend(bool ok)
{
webview->print(printer);//输出打印文件
}
(2)QPlainTextEdit和QTextEdit
用途:用于界面文本输入的控件
处理函数:
void QPlainTextEdit::print ( QPrinter * printer )
void QTextEdit::print ( QPrinter * printer )
示例:
void prinTextEdit(void)
{
QTextEdit *edt = new QTextEdit();
QPrinter *printer = new QPrinter(QPrinter::PrinterResolution);
edt->setText(“This is an text!”);
edt->print(printer);
delete printer;
delete edt;
}
(3)QPainter
用途:用于绘图的类
处理函数:
QPainter ( QPaintDevice * device )
示例:
void prinTextEdit(void)
{
QImage image(“/home/root/test.jpg”);
QPainter painter(printer);
QRect rect = painter.viewport();
QSize size = image.size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(),size.width(), size.height());
painter.setWindow(image.rect());
painter.drawImage(0, 0, image);
painter.drawText(10,10, ”this is image”);
}
(4)QPrintPreviewWidget
用途:专门用于打印预览的控件
处理函数:
QPrintPreviewWidget::QPrintPreviewWidget ( QPrinter * printer, QWidget * parent = 0, Qt::WindowFlags flags = 0 )
void QPrintPreviewWidget::print ()
示例:
QTextEdit edt;
void prinTextEdit(void)
{
QPrinter *printer = new QPrinter(QPrinter::PrinterResolution);
QPrintPreviewWidget *preview = new QPrintPreviewWidget (printer);
connect(previewWidget,SIGNAL(paintRequested(QPrinter*)),this,SLOT(printPreview(QPrinter *)));//关联打印预览的内容
preview ->print();
delete printer;
delete preview;
}
void printPreview(QPrinter *printer)
{
edt.setText(“This is an text!”);
edt.print(printer);
}
(5)QTextDocument
用途:文档类型的文件处理
处理函数:
void QTextDocument::print ( QPrinter * printer )
4.输出到设备
输出ps的文件格式可以作为打印机驱动的输入文件。
在qt中可以使用以下命令:
QString cmd;//cmd设置为打印的命令,需要驱动支持。
system(cmd);
5.相关控件
Qt提供了一些标准的控件。
QPrintDialog,打印对话框
QPrintPreviewDialog,打印预览对话框