ZAARONBIN - 博客园

第五章 Qt之应用程序主窗口

5.1 主窗口框架

Qt中提供了以QMainWindow类为核心的主窗口框架,QMainWindow类拥有自己的布局如下图,包含以下组件:

graph TD A(QMainWindow)-->b1(菜单栏 QMenuBar) A-->b2(工具栏 QToolBar) A-->b3(中心部件 Central Widget) A-->b4(Dock部件 QDock Widget) A-->b5(状态栏 QStatusBar)
  • 菜单栏:有QAction动作类实现,位于窗口顶部,一个主窗口只能有一个菜单栏
  • 工具栏:可以插入其他窗口部件,且可以移动;一个主窗口可以拥有多个工具栏
  • 中心部件:应用程序的主要功能实现区域,一个主窗口只能有一个中心部件
  • Dock部件:Dock部件常被称为停靠窗口,因为可以停靠在中心部件的四周,用来放置一些部件来实现一些功能。一个主窗口可以拥有多个Dock部件
  • 状态栏:用于显示程序的一些信息,在主窗口最底部,一个主窗口只能拥有一个状态栏

5.1.1 Qt资源系统、菜单栏和工具栏

5.1.1.1 使用资源

  1. add new -> Qt -> Qt Resource File
  2. 修改Qt Resource File的相对路径前缀,存放文件时,应将文件放置在Qt Resource File的qrc文件的同级或子目录下
  3. 在资源系统中add File 并 保存
  4. 在设计师界面通过Action编辑器,双击Action可设置图标,提示和快捷键

添加的qrc文件实际时XML格式的文本文件,代码如下:

<RCC>
    <qresource prefix="/images">
        <file>images/new.png</file>
        <file>images/open.png</file>
    </qresource>
</RCC>
#之后在使用资源系统管理的文件时,可以通过“/images/images/new.png”路径进行使用;其中前缀/images表明为图片资源

5.1.1.2 编写代码方式添加菜单

QToolBar *toolBar = new QToolBar(this);                     //创建一个新的工具栏
this->addToolBar(Qt::TopToolBarArea, toolBar);  			//为当前主窗口添加一个工具栏
QMenu *FileMenu = ui->menubar->addMenu(tr("文件(&F)"));	   //为菜单栏添加一个项目卡

QAction *action_New = new QAction(QIcon(":/images/images/new.png"), tr("新建文件或项目(&N)"));	//创建一个动作
action_New->setShortcut(QKeySequence("Ctrl+N"));  //给动作设置快捷键
action_New->setToolTip("新建文件");	//动作默认的工具栏鼠标放置提示为动作的名称,可通过setToolTip函数设置为其他提示

QAction *action_Open =new QAction(QIcon(":/images/images/open.png"), tr("打开文件或项目(&O)"));
action_Open->setShortcut(QKeySequence("Ctrl+O"));

QAction *action_RecFile = new QAction(tr("最近访问的文件(&R)"));
action_RecFile->setShortcut(QKeySequence("Ctrl+R"));

QList<QAction*> action_File;		//创建一个动作列表
//添加动作至动作列表中
QAction* shuzu[] = {action_New,action_Open,action_RecFile};
for(int i=0; i<(int)(sizeof(shuzu)/sizeof(action_New))-1; i++)
       action_File.push_back(shuzu[i]);

FileMenu->addActions(action_File);		//将动作列表中的动作添加至菜单栏的FileMenu项目卡中
FileMenu->addSeparator();				//为菜单选项卡添加水平分隔线
FileMenu->addAction(action_RecFile);	//分割线后添加的Action
/*=============================================================================*/
QMenu *editMenu = ui->menubar->addMenu(tr("新建(&E)"));
QAction *action_Undo = editMenu->addAction(tr("&Undo"));
action_Undo->setShortcut(QKeySequence("Ctrl+Z"));

//    toolBar->addAction(action_New);
//    toolBar->addAction(action_Open);
toolBar->addActions({action_New, action_Open});

5.1.1.3 菜单栏

QMenu *editMenu = ui->menubar->addMenu(tr("新建(&E)"));
QAction *action_Undo = editMenu->addAction(tr("&Undo"));
action_Undo->setShortcut(QKeySequence("Ctrl+Z"));

QActionGroup *group = new QActionGroup(this);				//创建一个动作组,该动作组中只能有一个动作处于被选中状态
QAction *action_L = group->addAction(tr("左对齐(&L)"));
action_L->setCheckable(true);								//对QAction的SsetCheckable属性进行设置,使被选中时能够在选项前显示状态
QAction  *action_R = group->addAction(tr("右对齐(&R)"));
action_R->setCheckable(true);
QAction *action_C = group->addAction(tr("居中(&C)"));
action_C->setCheckable(true);
action_L->setChecked(true);									//设置action_L为默认选中状态
editMenu->addSeparator();
editMenu->addActions({action_L, action_R, action_C});
editMenu->addSeparator();

5.1.1.4 工具栏

QToolBar属性 描述
toolButtonStyle 用于设置图标和相应文本的显示及其相对位置
movable 设置状态栏是否可移动
allowedArea 用来设置允许停靠的位置
iconsize 用于设置图标的大小
floatable 用于设置是否可以悬浮
#include <QToolButton>

/*-------------------------------------设置工具栏属性--------------------------------------------*/
QToolBar *toolBar = new QToolBar(this);                                //创建一个新的工具栏
toolBar->setMovable(true);                                             //设置工具栏是否可移动
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);              //设置工具栏图标和文本的显示方式
toolBar->setAllowedAreas(Qt::TopToolBarArea|Qt::LeftToolBarArea);      //设置工具栏能够停靠的位置
toolBar->setIconSize(QSize(48,48));                                    //设置图标显示大小
this->addToolBar(Qt::TopToolBarArea, toolBar);                         //为当前主窗口添加一个工具栏
/*-------------------------------------为工具栏添加QToolButon部件--------------------------------------------*/
QToolButton *toolBtn = new QToolButton(this);							//创建一个toolButton部件,其父为当前主窗口
toolBtn->setText(tr("颜色"));											   //设置toolButton部件的显示文本
QMenu *colorMenu = new QMenu(this);										//为ToolButton创建一个菜单列表
colorMenu->addAction(tr("绿色"));										   //添加菜单动作
colorMenu->addAction(tr("红色"));										   //添加菜单动作
toolBtn->setMenu(colorMenu);											//将ToolButton与上述创建的菜单列表绑定
toolBtn->setPopupMode(QToolButton::MenuButtonPopup);					//设置ToolButton的调用属性(点击箭头显示)
toolBar->addWidget(toolBtn);											//将创建的toolButton部件加入工具栏

5.1.2 中心部件

中心部件一般为编辑器或者浏览器。支持单文档部件和多文档部件。

graph TD A(中心部件)-->b1(浏览器与编辑器支持富文本 QTextEdit) A-->b2(纯文本编辑器 QPlainEdit) A-->b3(富文本浏览器 QTextBrowser) A--显示多文档界面的区域-->b4(QMdiArea) b4--子窗口-->c1(QMdiSubWindow) c1-->d1(标题栏) c1-->d2(中心区域) d2-->其他部件
#include <QMdiSubWindow>
#include <QTextEdit>

QTextEdit *edit = new QTextEdit(this);
QMdiSubWindow *child = ui->midArea->addSubWindow(edit);
child->setWindowTitle(tr("多文档编辑子窗口"));
child->show();

5.1.3 Dock部件

QDockWiget类提供的部件可以停靠在QMainWindow中,也可以悬浮起来作为桌面顶级窗口,称为Dock部件或者停靠部件。

  • Dock部件一般用于存放一些其他部件实现特殊功能,like工具箱。
  • 可以停靠在中心部件的四周,也可以悬浮起来拖动到任意位置,同时也可被关闭和隐藏
  • Dock部件包含一个标题栏和一个内容区域
  • 可以向Dock部件中放置任何部件
#include <QDockWidget>
#include <QTextEdit>

QDockWidget *dockwidget = new QDockWidget(tr("Dock"),this);		//在当前主窗口下添加Dock部件
QTextEdit *edit = new QTextEdit();								//新建一个TextEdit部件
dockwidget->setWidget(edit);									//将TextEdit部件添加到dock部件中
dockwidget->show();												//显示dock部件

5.1.4 状态栏

graph TD A(状态栏)-->b1(临时信息--提示信息) b1-->c1(showMessage函数) c1-->默认最左边 A-->b2(正常信--显示页数和行号等) b2-->c2(addWidget函数添加QLabel) c2-->默认最左边 A-->b3(永久信息--版本号或日期等) b3-->c3(addPermanent函数) c3-->默认最右边

在状态栏的最右端有一个QSizeGrip部件,用来调整窗口的大小,可以使用setSizeGripEnabled()函数禁用它

#include <QLabel>

ui->statusbar->showMessage(tr("欢迎使用多文档编辑器"),2000);		//2000表示显示的时间单位ms
QLabel *permanent = new QLabel(this);
permanent->setFrameStyle(QFrame::Box|QFrame::Sunken);		  //因为QLabel继承了QFrame类,所以可以直接设置
permanent->setText("www.qter.org");							  //设置标签内容
ui->statusbar->addPermanentWidget(permanent);				  //添加永久信息,默认在状态栏最右边显示

5.1.5 自定义菜单

菜单中也可以使用其他的部件。该功能的实现依赖于QWidgetAction类。需新建一个类,该类继承自QWidgetAction类,并且在其中重新实现createWidget()函数。

/*实现一个菜单项:包含一个标签和一个行编辑器*/
//QWidgetAction()创建的QAction在被添加到QMenu时会调用createWidget()函数
MyAction *action = new MyAction;
QMenu *editMenu = ui->menubar->addMenu(tr("编辑(&E)"));
editMenu->addAction(action);	//此处会调用QWidgetAction::createWidget()函数

5.2 富文本处理

​ 富文本:即在文档中可以使用比如字体颜色、图片和表格等。QTextEdit支持富文本格式。关键字:Rich Text Processing

5.2.1 富文本文档结构

  • 编辑操作:基于光标实现的接口函数;基于QTextCursor类
  • 只读操作:使用只读的分层次接口函数,有利于文档的检索和输出;基于QTextDocument类
graph TD A(QTextEdit)-->b1(QTextCursor) A-->b2(QTextDocument) b1-->QTextFrameFormat b1-->QTextBlockFormat b1-->QTextTableFormat b1-->QTextListFormat b2-->QTextFrame b2-->QTextBlock b2-->QTextTable b2-->QTextList

image-20210316200948411

image-20210316210638191

TextEdit部件的结构图如图5-9所示,后续所有的文本块、表格等都添加在Root Frame中。

QTextEdit *textEdit = new QTextEdit;
QTextDocument *document = textEdit->document();		//获取textEdit的文档结构
QTextFrame *frame = document->RootFrame();	//获取文档结构的根框架

/*遍历文档结构中的所有frame框架*/
QTextFrame::iterator it;	//建立QTextFrame的迭代器
for(it = frame.begin(); !(it.atEnd); ++it)
{
    QTextFrame *childFrame = it.currentFrame();
    if(childFrame)
    	qDebug()<<"this is a frame.";
}

5.2.2 文本块

​ 文本块QTextBlock类为文本文档QTextDocument提供了一个文本片段(QTextFragment)的容器。一个文本块可以看作是一个段落,但不能使用回车换行。因为一个回车换行表示创建一个新的文本块。

  • 文本块的格式由QTextBlockFormat类处理:对齐方式、文本块四周边距、缩进等
  • 文本块中文本内容的格式由QTextCharFormat类处理:字体大小、加粗、下划线等
/*如何遍历文档结构中的所有文本块(QTextBlock)*/
QTextEdit *textEdit = new QTextEdit;
QTextDocument *document = textEdit->document();		//获取textEdit的文档结构
QTextBlock block = document->firstBlock();
for(int i=0; i<document->blockCount(); i++)			//document->blockCount()获取文档结构中所有文本块的个数
{
    qDebug()<<tr("文本块%1,文本块首行行号:%2, 长度为: %3, 内容为: ")
              .arg(i).arg(block.firstLineNumber()).arg(block.length())
           <<block.text();							//block.length()从1开始计算,最小为1
    block = block.next();
}

/*编辑文本块及其内容的格式*/
QTextCursor cursor = 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("测试字体"));

5.2.3 表格、列表和图片

  • Table:QTextTable类,其格式由QTextTableFormat类管理
  • List:QTextList类,其格式由QTextListFormat类管理
  • Image:图片没有对应的类;QTextImageFormat类对图片的格式进行管理,通过setHeight()和setWidth()设置图片的高和宽,setName(“路径”)指定图片
/*Table*/
QTextCursor cursor = textEdit->textCursor();
QTextTableFormat format;
format.setCellSpacing(2);       //表格外边白
format.setCellPadding(10);      //表格内边白
cursor.insertTable(2,2,format); //插入2行2列的表格
/*List*/
QTextCursor cursor = textEdit->textCursor();
QTextListFormat format;
format.setStyle(QTextListFormat::ListDecimal);  //设置数字编号
cursor.insertList(format);
/*image*/
QTextImageFormat format;
format.setName("C:/Users/LN/Pictures/Saved Pictures/earth01.png");
textEdit->textCursor().insertImage(format);

5.2.4 查找功能

  • QTextEdit类的find()函数
  • QTextDocument::FindBackward表示向后查找,即从输入完成开始,向左查找
/*创建查找对话框,其中对话框中包含行编辑器和查找下一个按钮*/
findDialog = new QDialog(this);
findDialog->setWindowTitle(tr("查找匹配项"));
lineEdit = new QLineEdit;
QPushButton *btn = new QPushButton;
btn->setText(tr("查找下一个"));
connect(btn, &QPushButton::clicked, this, &MainWindow::findNext);

QVBoxLayout *vblayout = new QVBoxLayout;
vblayout->addWidget(lineEdit);
vblayout->addWidget(btn);
findDialog->setLayout(vblayout);

/*创建一个动作来弹出查找对话框*/
QAction* action_textFind = new QAction(tr("查找"), this);
connect(action_textFind, &QAction::triggered, this, &MainWindow::textFind);
toolBar->addAction(action_textFind);

/*查找动作的槽函数,用于显示查找对话框*/
void MainWindow::textFind()
{
    findDialog->show();
}

/*查找下一个按钮的槽函数*/
void MainWindow::findNext()
{
    QString string = lineEdit->text();		//获取行编辑器的内容
    qDebug()<<"查找内容:"<<string;
    //使用查找功能,光标默认位置在输入内容的末端;每次查找后光标的位置会在最后一次查找的位置
    //使用查找功能;QTextDocument::FindBackward表示向后查找,默认为向前查找
    bool isfind = textEdit->find(string, QTextDocument::FindBackward);
    if(isfind)
    {
        qDebug()<<tr("行号:%1,列号:%2")
                  .arg(textEdit->textCursor().blockNumber())
                  .arg(textEdit->textCursor().columnNumber());
    }
}

5.2.5 语法高亮和HTML

​ Qt富文本处理提供了QSyntaxHighlighter类实现语法高亮,为实现该功能,需创建QSyntaxHighlighter类的子类,然后重新实现highlightBlock()函数,使用时直接将QTextDocument类对象指针作为其父部件指针,这样就可以自动调用highlightBlock()函数了。

  • QTextEdit 使用HTML语法:textEdit->append(tr("<h1><font color =red>使用HTML</font></h1>"));
/*==========mysyntaxhighlighter.h===========*/
#ifndef MYSYNTAXHIGHLIGHTER_H
#define MYSYNTAXHIGHLIGHTER_H

#include <QSyntaxHighlighter>

class mysyntaxhighlighter : public QSyntaxHighlighter
{
    Q_OBJECT
public:
    explicit mysyntaxhighlighter(QTextDocument* parent = 0);
protected:
    void highlightBlock(const QString &text);       //必须重写实现函数
};

#endif // MYSYNTAXHIGHLIGHTER_H


/*==========mysyntaxhighlighter.cpp===========*/
#include "mysyntaxhighlighter.h"

mysyntaxhighlighter::mysyntaxhighlighter(QTextDocument *parent) :
    QSyntaxHighlighter(parent)
{
}

void mysyntaxhighlighter::highlightBlock(const QString &text){
    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);     //继续匹配
    }
}
/*==========mainWindow.cpp构造函数添加内容===========*/
highlighter = new mysyntaxhighlighter(textEdit->document());
//其中需要对mainwindow类定义中,声明private: highlighter变量

5.3 拖放操作

  • 实现将文件拖入后打开的操作;具体参考Drag and Drop示例

5.3.1 使用拖放打开文件

  • 当鼠标拖拽一个数据进入主窗口时,触发dragEnterEvent()事件处理函数;该数据由QmimeData类对象处理
  • 当松开鼠标左键,将数据放入主窗口时就会触发dropEvent()事件处理函数
#include <QDragEnterEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    textEdit = new QTextEdit;
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(textEdit);
    ui->centralwidget->setLayout(layout);

    setAcceptDrops(true);
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasUrls())            //数据中是否包含URL
        event->acceptProposedAction();             //如果是则接收动作
    else
        event->ignore();
}

void MainWindow::dropEvent(QDropEvent *event)
{
    const QMimeData *mimeData = event->mimeData();              //获取MIME数据
    if(mimeData->hasUrls()){
        QList<QUrl> urlList = mimeData->urls();                 //获取URL列表
        QString fileName = urlList.at(0).toLocalFile();         //将URL列表中的第一个URL表示为本地文件路径
        if(!fileName.isEmpty()){                                //如果路径不为空
            QFile file(fileName);                               //建立QFile对象
            if(!file.open(QIODevice::ReadOnly))                 //以只读的方式打开文件
                return;
            QTextStream in(&file);                              //建立文本流数据
            textEdit->setText(in.readAll());                    //将文件中所有内容读入编辑器
        }
    }
}

5.3.2 自定义拖放操作

5.4 打印文档

posted @ 2021-03-18 10:26  BINBINBINZ  阅读(587)  评论(0)    收藏  举报