Qt項(xiàng)目實(shí)戰(zhàn)之實(shí)現(xiàn)多文本編輯器
首先先來(lái)看實(shí)驗(yàn)成果圖,大概就是這么個(gè)多文檔編輯器。

首先需要在設(shè)計(jì)模式里進(jìn)行設(shè)計(jì)器的設(shè)置:

然后就是新建類(lèi)MdiChild的聲明和實(shí)現(xiàn)
mdichild.h
#ifndef MDICHILD_H
#define MDICHILD_H
#include<QTextEdit>
class MdiChild:public QTextEdit
{
Q_OBJECT
public:
explicit MdiChild(QWidget *parent = 0);
void newFile(); //新建操作
bool loadFile(const QString &fileName); //加載文件
bool save(); //保存操作
bool saveAs(); //另存為操作
bool saveFile(const QString &fileName); //保存文件
QString userFriendlyCurrentFile(); //提取文件名
QString currentFile(){return curFile;} //返回當(dāng)前文件路徑
protected:
void closeEvent(QCloseEvent *event); //關(guān)閉事件
void contextMenuEvent(QContextMenuEvent *e); //右鍵菜單事件
private slots:
void documentWasModified(); //文檔被更改時(shí),窗口顯示更改狀態(tài)標(biāo)志
private:
bool maybeSave(); //是否需要保存
void setCurrentFile(const QString &fileName); //設(shè)置當(dāng)前文件
QString curFile; //保存當(dāng)前文件路徑
bool isUntitled; //作為當(dāng)前文件是否被保存到硬盤(pán)上的標(biāo)志
};
#endif // MDICHILD_H
mdichild.cpp
#include "mdichild.h"
#include<QFile>
#include<QMessageBox>
#include<QTextStream>
#include<QApplication>
#include<QFileInfo>
#include<QFileDialog>
#include<QCloseEvent>
#include<QPushButton>
#include<QMenu>
MdiChild::MdiChild(QWidget *parent):QTextEdit (parent)
{
//設(shè)置在子窗口關(guān)閉時(shí)銷(xiāo)毀這個(gè)類(lèi)的對(duì)象
setAttribute(Qt::WA_DeleteOnClose);
//初始isUntitled為true
isUntitled = true;
}
/*
* 設(shè)置窗口編號(hào)
* 保存文件未被保存過(guò)“isUntitled = true”
* 保存文件路徑,給curFile賦初值
* 設(shè)置子窗口標(biāo)題
* 關(guān)聯(lián)文檔內(nèi)容改變信號(hào)到顯示文檔更改狀態(tài)
*/
void MdiChild::newFile()
{
//設(shè)置窗口編號(hào),因?yàn)榫幪?hào)一致被保存,所以需要使用靜態(tài)變量
static int sequenceNumber =1;
//新建的文檔沒(méi)有被保存過(guò)
isUntitled =true;
//將當(dāng)前文件命名為未命名文檔加編號(hào),編號(hào)先使用再加1
curFile = tr("未命名文檔%1.txt").arg(sequenceNumber++);
//設(shè)置窗口標(biāo)題,使用[*]可以再文檔被更改后再文件名稱(chēng)后顯示“*”號(hào)
setWindowTitle(curFile +"[*]"+tr(" - 多文檔編輯器"));
//文檔更改時(shí)發(fā)射contentsChanged()信號(hào),執(zhí)行documentWasModified()槽
connect(document(),SIGNAL(contentsChanged()),this,SLOT(documentWasModified()));
}
/*
* 打開(kāi)指定的文件,并讀取文件內(nèi)容到編輯器
* 設(shè)置當(dāng)前文件setCurrentFile(),該函數(shù)可以獲取文件路徑,完成文件和窗口狀態(tài)的設(shè)置
* 關(guān)聯(lián)文檔內(nèi)容改變信號(hào)到顯示文檔更改狀態(tài)槽documentWasModified()
*/
bool MdiChild::loadFile(const QString &fileName)
{
//新建QFile對(duì)象
QFile file(fileName);
//只讀方式打開(kāi)文件,出錯(cuò)則提示,并返回false
if(!file.open(QFile::ReadOnly|QFile::Text))
{
QMessageBox::warning(this,tr("多文檔編輯器"),tr("無(wú)法讀取文件%1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
//新建文本流對(duì)象
QTextStream in(&file);
//設(shè)置鼠標(biāo)狀態(tài)為等待狀態(tài)
QApplication::setOverrideCursor(Qt::WaitCursor);
//讀取文件的全部文本內(nèi)容,并添加到編輯器中
setPlainText(in.readAll());
//恢復(fù)鼠標(biāo)狀態(tài)
QApplication::restoreOverrideCursor();
//設(shè)置當(dāng)前文件
setCurrentFile(fileName);
connect(document(),SIGNAL(contentsChanged()),this,SLOT(documentWasChanged()));
return true;
}
bool MdiChild::save()
{
//如果文件未被保存過(guò),則執(zhí)行另存為操作,否則直接保存文件
if(isUntitled)
{
return saveAs();
}
else {
return saveFile(curFile);
}
}
bool MdiChild::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this,tr("另存為"),curFile);
//獲取文件路徑,如果為空,則返回false,否則保存文件
if(fileName.isEmpty())
return false;
return saveFile(fileName);
}
bool MdiChild::saveFile(const QString &fileName)
{
QFile file(fileName);
if(!file.open(QFile::WriteOnly|QFile::Text))
{
QMessageBox::warning(this,tr("多文檔編輯器"),tr("無(wú)法寫(xiě)入文件%1:\n%2").arg(fileName).arg(file.errorString()));
return false;
}
QTextStream out(&file);
QApplication::setOverrideCursor(Qt::WaitCursor);
//以純文本文件寫(xiě)入
out<<toPlainText();
QApplication::restoreOverrideCursor();
setCurrentFile(fileName);
}
QString MdiChild::userFriendlyCurrentFile()
{
//從文件路徑中提取文件名
return QFileInfo(curFile).fileName();
}
void MdiChild::closeEvent(QCloseEvent *event)
{
//如果maybeSave()函數(shù)返回true,則關(guān)閉窗口,否則忽略該事件
if(maybeSave())
{
event->accept();
}
else {
event->ignore();
}
}
void MdiChild::contextMenuEvent(QContextMenuEvent *e)
{
//創(chuàng)建菜單,并向其中添加動(dòng)作
QMenu *menu = new QMenu;
QAction *undo =menu->addAction(tr("撤銷(xiāo)(&U)"),this,SLOT(undo()),QKeySequence::Undo);
undo->setEnabled(document()->isUndoAvailable());
QAction *redo =menu->addAction(tr("恢復(fù)(&R)"),this,SLOT(redo()),QKeySequence::Redo);
redo->setEnabled((document()->isRedoAvailable()));
menu->addSeparator();
QAction *cut =menu->addAction(tr("剪切(&T)"),this,SLOT(cut()),QKeySequence::Cut);
cut->setEnabled(textCursor().hasSelection());
QAction *copy = menu->addAction(tr("復(fù)制(&C)"),this,SLOT(copy()),QKeySequence::Copy);
copy->setEnabled(textCursor().hasSelection());
QAction *clear = menu->addAction(tr("清空"),this,SLOT(clear()));
clear->setEnabled(!document()->isEmpty());
menu->addSeparator();
QAction *select = menu->addAction(tr("全選"),this,SLOT(selectAll()),QKeySequence::SelectAll);
select->setEnabled(!document()->isEmpty());
//獲取鼠標(biāo)的位置,然后在這個(gè)位置顯示菜單
menu->exec(e->globalPos());
//最后銷(xiāo)毀這個(gè)菜單
delete menu;
}
void MdiChild::documentWasModified()
{
//根據(jù)文檔的isModified()函數(shù)的返回值,判斷編輯器內(nèi)容是否被更改了
//如果被更改了,就要在設(shè)置[*]號(hào)的地方顯示“*”號(hào),這里會(huì)在窗口標(biāo)題中顯示
setWindowModified(document()->isModified());
}
bool MdiChild::maybeSave()
{
//如果文檔被更改過(guò)
if(document()->isModified())
{
QMessageBox box;
box.setWindowTitle(tr("多文檔編輯器"));
box.setText(tr("是否保存為“%1”的更改?").arg(userFriendlyCurrentFile()));
box.setIcon(QMessageBox::Warning);
//添加按鈕,QMessageBox::YesRole可以表明這個(gè)按鈕的行為
QPushButton *yesBtn = box.addButton(tr("是(&Y)"),QMessageBox::YesRole);
box.addButton(tr("否(&N)"),QMessageBox::NoRole);
QPushButton *cancelBtn = box.addButton(tr("取消"),QMessageBox::RejectRole);
//彈出對(duì)話框,讓用戶選擇是否保存修改,或者取消關(guān)閉操作
box.exec();
//如果用戶選擇是,則返回保存操作的結(jié)果;如果選擇取消,則返回false
if(box.clickedButton() ==yesBtn)
return save();
else if(box.clickedButton() ==cancelBtn){
return false;
}
}
//如果文檔沒(méi)有更改過(guò),則直接返回true;
return true;
}
void MdiChild::setCurrentFile(const QString &fileName)
{
//canonicalFilePath()可以除去路徑中的符號(hào)鏈接,"."和".."等符號(hào)
curFile = QFileInfo(fileName).canonicalFilePath();
//文件已經(jīng)被保存過(guò)了
isUntitled = false;
//文檔沒(méi)有被更改過(guò)
document()->setModified(false);
//窗口不顯示被更改標(biāo)志
setWindowModified(false);
//設(shè)置窗口標(biāo)題,userFriendlyCurrentFile()返回文件名
setWindowTitle(userFriendlyCurrentFile()+"[*]");
}
然后是mainwindow類(lèi)的聲明與實(shí)現(xiàn)
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QMdiSubWindow;
class MdiChild;
class QSignalMapper;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void updateMenus(); //更新菜單
MdiChild* createMdiChild(); //創(chuàng)建子窗口
void setActiveSubWindow(QWidget *window); //設(shè)置活動(dòng)子窗口
void updateWindowMenu(); //更新窗口菜單
void showTextRowAndCol(); //顯示文本的行號(hào)和列號(hào)
void on_actionNew_triggered();
void on_actionOpen_triggered();
void on_actionSave_triggered();
void on_actionSaveAs_triggered();
void on_actionUndo_triggered();
void on_actionRedo_triggered();
void on_actionCut_triggered();
void on_actionCopy_triggered();
void on_actionPaste_triggered();
void on_actionClose_triggered();
void on_actionCloseAll_triggered();
void on_actionAbout_triggered();
void on_actionAboutQt_triggered();
void on_actionExit_triggered();
private:
QMdiSubWindow *findMdiChild(const QString &fileName);//查找子窗口
void readSettings(); //讀取窗口設(shè)置
void writeSettings(); //寫(xiě)入窗口設(shè)置
void initWindow(); //初始化窗口
protected:
void closeEvent(QCloseEvent* event); //關(guān)閉事件
private:
Ui::MainWindow *ui;
QAction *actionSeparator; //間隔器
MdiChild *activeMdiChild(); //活動(dòng)窗口
QSignalMapper *windowMapper; //信號(hào)映射器
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"mdichild.h"
#include<QFileDialog>
#include<QMdiSubWindow>
#include<QSignalMapper>
#include<QMessageBox>
#include<QSettings>
#include<QCloseEvent>
#include<QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 初始化actionSeparator動(dòng)作,然后執(zhí)行更新菜單函數(shù),并關(guān)聯(lián)多文檔區(qū)域的活動(dòng)子窗口信號(hào)到更新菜單槽上
* 每當(dāng)更換子窗口時(shí),都會(huì)更新菜單狀態(tài)
*/
//創(chuàng)建間隔期動(dòng)作并在其中設(shè)置間隔期
actionSeparator = new QAction(this);
actionSeparator->setSeparator(true);
//更新菜單
updateMenus();
//當(dāng)有活動(dòng)窗口時(shí)更新菜單
connect(ui->mdiArea,SIGNAL(subWindowActivated(QMdiSubWindow*)),this,SLOT(updateMenus()));
//創(chuàng)建信號(hào)映射器
windowMapper = new QSignalMapper(this);
//映射器重新發(fā)射信號(hào),更具信號(hào)設(shè)置活動(dòng)窗口
connect(windowMapper,SIGNAL(mapped(QWidget *)),this,SLOT(setActiveSubWindow(QWidget *)));
//更新窗口菜單,并且設(shè)置當(dāng)窗口菜單將要顯示的時(shí)候更新窗口菜單
updateWindowMenu();
connect(ui->menu_W,SIGNAL(aboutToShow()),this,SLOT(updateWindowMenu()));
readSettings(); //初始窗口時(shí)讀取窗口設(shè)置信息
//初始化窗口
initWindow();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionNew_triggered()
{
//創(chuàng)建MdiChild
MdiChild *child = createMdiChild();
//新建文件
child->newFile();
//顯示子窗口
child->show();
}
/*
* 更新菜單函數(shù):根據(jù)是否有活動(dòng)子窗口設(shè)置各個(gè)菜單動(dòng)作是否可用
* 這里剪切復(fù)制操作和撤銷(xiāo)恢復(fù)操作的設(shè)置還要進(jìn)行特殊情況的判斷
*/
void MainWindow::updateMenus()
{
//根據(jù)是否有活動(dòng)窗口來(lái)設(shè)置各個(gè)動(dòng)作是否可用
bool hasMdiChild = (activeMdiChild()!= 0);
ui->actionSave->setEnabled(hasMdiChild);
ui->actionSaveAs->setEnabled(hasMdiChild);
ui->actionPaste->setEnabled(hasMdiChild);
ui->actionClose->setEnabled(hasMdiChild);
ui->actionCloseAll->setEnabled(hasMdiChild);
ui->actionTile->setEnabled(hasMdiChild);
ui->actionCascade->setEnabled(hasMdiChild);
ui->actionNext->setEnabled(hasMdiChild);
ui->actionPrevious->setEnabled(hasMdiChild);
//有活動(dòng)窗口且有被選擇的文本,剪切復(fù)制才可用
bool hasSelection =(activeMdiChild() &&activeMdiChild()->textCursor().hasSelection());
ui->actionCut->setEnabled(hasSelection);
ui->actionPaste->setEnabled(hasSelection);
//有活動(dòng)窗口且有撤銷(xiāo)操作時(shí)撤銷(xiāo)動(dòng)作可用
ui->actionUndo->setEnabled(activeMdiChild()&&activeMdiChild()->document()->isUndoAvailable());
//有活動(dòng)窗口且文檔有恢復(fù)操作時(shí)恢復(fù)動(dòng)作可用
ui->actionRedo->setEnabled(activeMdiChild()&&activeMdiChild()->document()->isRedoAvailable());
}
/*
* 這個(gè)函數(shù)中創(chuàng)建了MdiChild部件,并將它作為子窗口的中心部件,然后添加到多文檔區(qū)域。
* 下面關(guān)聯(lián)了編輯器的信號(hào)和我們的菜單動(dòng)作,讓它們可以隨著文檔的改變而改變狀態(tài)
* 最后返回了MdiChild對(duì)象指針。
* 之所以要添加這樣一個(gè)函數(shù),是因?yàn)樵谙旅娴拇蜷_(kāi)操作中還要使用到這個(gè)函數(shù)中的功能,所以將它們從新建文件菜單的觸發(fā)信號(hào)槽中提取出來(lái),另寫(xiě)了這樣一個(gè)函數(shù)
*/
MdiChild *MainWindow::createMdiChild()
{
//創(chuàng)建MdiChild部件
MdiChild *child = new MdiChild;
//向多文檔區(qū)域添加子窗口,child為中心部件
ui->mdiArea->addSubWindow(child);
//根據(jù)QTextEdit類(lèi)的是否可以復(fù)制信號(hào)設(shè)置剪切復(fù)制動(dòng)作是否可用
connect(child,SIGNAL(copyAvailable(bool)),ui->actionCut,SLOT(setEnabled(bool)));
connect(child,SIGNAL(copyAvailable(bool)),ui->actionCopy,SLOT(setEnabled(bool)));
//根據(jù)QTextDocument類(lèi)的是否可以撤銷(xiāo)恢復(fù)信號(hào)設(shè)置撤銷(xiāo)恢復(fù)動(dòng)作是否可用
connect(child->document(),SIGNAL(undoAvailable(bool)),ui->actionUndo,SLOT(setEnabled(bool)));
connect(child->document(),SIGNAL(redoAvailable(bool)),ui->actionRedo,SLOT(setEnabled(bool)));
connect(child,SIGNAL(cursorPositionChanged()),this,SLOT(showTextRowAndCol()));
return child;
}
/*
* 函數(shù)功能:將傳遞過(guò)來(lái)的窗口部件設(shè)置為活動(dòng)窗口
*/
void MainWindow::setActiveSubWindow(QWidget *window)
{
//如果傳遞了窗口部件,則將其設(shè)置為活動(dòng)窗口
if(!window)
return;
ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow*>(window));
}
void MainWindow::on_actionOpen_triggered()
{
//獲取文件路勁
QString fileName = QFileDialog::getOpenFileName(this);
//如果路徑不為空,則查看該文件是否已經(jīng)打開(kāi)
if(!fileName.isEmpty())
{
QMdiSubWindow *existing = findMdiChild(fileName);
//如果已經(jīng)存在,則將對(duì)應(yīng)的子窗口設(shè)置為活動(dòng)窗口
if(existing)
{
ui->mdiArea->setActiveSubWindow(existing);
return;
}
//如果沒(méi)有打開(kāi),則新建子窗口
MdiChild *child = createMdiChild();
if(child->loadFile(fileName))
{
ui->statusBar->showMessage(tr("打開(kāi)文件成功"),2000);
child->show();
}
else {
child->close();
}
}
}
void MainWindow::updateWindowMenu()
{
//先清空菜單,然后在添加各個(gè)菜單動(dòng)作
ui->menu_W->clear();
ui->menu_W->addAction(ui->actionClose);
ui->menu_W->addAction(ui->actionCloseAll);
ui->menu_W->addSeparator();
ui->menu_W->addAction(ui->actionTile);
ui->menu_W->addAction(ui->actionCascade);
ui->menu_W->addSeparator();
ui->menu_W->addAction(ui->actionNext);
ui->menu_W->addAction(ui->actionPrevious);
ui->menu_W->addAction(actionSeparator);
//如果有活動(dòng)窗口,則顯示間隔器
QList<QMdiSubWindow*> windows =ui->mdiArea->subWindowList();
actionSeparator->setVisible(!windows.isEmpty());
//遍歷各個(gè)子窗口
for(int i=0;i<windows.size();++i)
{
MdiChild *child = qobject_cast<MdiChild*>(windows.at(i)->widget());
QString text;
//如果窗口數(shù)小于9,則設(shè)置編號(hào)為快捷鍵
if(i<9)
{
text=tr("&%1 %2").arg(i+1).arg(child->userFriendlyCurrentFile());
}
else {
text=tr("%1 %2").arg(i+1).arg(child->userFriendlyCurrentFile());
}
//添加動(dòng)作到菜單,設(shè)置動(dòng)作可以選擇
QAction *action = ui->menu_W->addAction(text);
action->setCheckable(true);
//設(shè)置當(dāng)前活動(dòng)窗口動(dòng)作為選中狀態(tài)
action->setChecked(child ==activeMdiChild());
//關(guān)聯(lián)動(dòng)作的觸發(fā)信號(hào)到信號(hào)映射器的map()槽,這個(gè)槽會(huì)發(fā)射mapped()信號(hào)
connect(action,SIGNAL(triggered()),windowMapper,SLOT(map()));
//將動(dòng)作與相應(yīng)的窗口部件進(jìn)行映射
//在發(fā)射mappedd()信號(hào)時(shí)就會(huì)以這個(gè)窗口部件為參數(shù)
windowMapper->setMapping(action,windows.at(i));
}
}
void MainWindow::showTextRowAndCol()
{
//如果有活動(dòng)窗口,則顯示其中光標(biāo)所在的位置
if(activeMdiChild())
{
//因?yàn)楂@取的行號(hào)和列號(hào)都是從0開(kāi)始的,所以我們這里進(jìn)行了加1
int rowNum = activeMdiChild()->textCursor().blockNumber()+1;
int colNum = activeMdiChild()->textCursor().blockNumber()+1;
ui->statusBar->showMessage(tr("%1行 %2列").arg(rowNum).arg(colNum),2000);
}
}
QMdiSubWindow *MainWindow::findMdiChild(const QString &fileName)
{
QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
//利用foreach語(yǔ)句遍歷子窗口列表,如果其文件路徑和要查找的路徑相同,則返回該窗口
foreach(QMdiSubWindow* window,ui->mdiArea->subWindowList())
{
MdiChild* mdiChild = qobject_cast<MdiChild*>(window->widget());
if(mdiChild->currentFile() ==canonicalFilePath)
return window;
}
return 0;
}
void MainWindow::readSettings()
{
QSettings settings("yafeilinux","myMdi");
QPoint pos =settings.value("pos",QPoint(200,200)).toPoint();
QSize size =settings.value("size",QSize(400,200)).toSize();
move(pos);
resize(size);
}
void MainWindow::writeSettings()
{
QSettings settings("yafeilinux","myMdi");
//寫(xiě)入位置信息和大小
settings.setValue("pos",pos());
settings.setValue("size",size());
}
void MainWindow::initWindow()
{
setWindowTitle(tr("多文檔編輯器"));
//在工具欄右擊時(shí),可以關(guān)閉該工具欄
ui->mainToolBar->setWindowTitle(tr("工具欄"));
//當(dāng)多文檔區(qū)域的內(nèi)容超出可是區(qū)域后,出現(xiàn)滾動(dòng)條
ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->statusBar->showMessage(tr("歡迎使用多文檔編輯器"));
QLabel *label =new QLabel(this);
label->setFrameStyle(QFrame::Box|QFrame::Sunken);
label->setText(tr("<a href=\"http://www.yafeilinux.com\">yafeilinux.com</a>"));
//標(biāo)簽文字為富文本
label->setTextFormat(Qt::RichText);
//可以打開(kāi)外部鏈接
label->setOpenExternalLinks(true);
ui->statusBar->addPermanentWidget(label);
ui->actionNew->setStatusTip(tr("創(chuàng)建一個(gè)文件"));
ui->actionOpen->setStatusTip(tr("打開(kāi)一個(gè)文件"));
}
void MainWindow::closeEvent(QCloseEvent *event)
{
//先執(zhí)行多文檔區(qū)域的關(guān)閉操作
ui->mdiArea->closeAllSubWindows();
//如果還有窗口沒(méi)有關(guān)閉,則忽略該事件
if(ui->mdiArea->currentSubWindow())
event->ignore();
else {
//在關(guān)閉前寫(xiě)入窗口設(shè)置
writeSettings();
event->accept();
}
}
/*
* 這個(gè)函數(shù)中使用了QMdiArea類(lèi)的activeSubWindow()函數(shù)來(lái)獲得多文檔區(qū)域的活動(dòng)子窗口,
* 然后使用了T qobject_cast()函數(shù)來(lái)進(jìn)行類(lèi)型轉(zhuǎn)換。這個(gè)函數(shù)時(shí)QObject類(lèi)的函數(shù),它將object對(duì)象指針轉(zhuǎn)換為T(mén)類(lèi)型的對(duì)象指針
* 這里將活動(dòng)窗口的中心部件QWidget類(lèi)型指針轉(zhuǎn)換為MdiChild類(lèi)型的指針
* 這里的T類(lèi)型必須是直接或者間接繼承自QObject類(lèi),并且在其定義中要有Q_OBJECT宏變量
*/
MdiChild *MainWindow::activeMdiChild()
{
//如果有活動(dòng)窗口,則將其內(nèi)的中心部件轉(zhuǎn)換為MdiChild類(lèi)型,沒(méi)有則直接返回0
if(QMdiSubWindow *activeSubWindow = ui->mdiArea->activeSubWindow())
return qobject_cast<MdiChild*>(activeSubWindow->widget());
return 0;
}
void MainWindow::on_actionSave_triggered()
{
if(activeMdiChild()&&activeMdiChild()->save())
ui->statusBar->showMessage(tr("文件保存成功"),2000);
}
void MainWindow::on_actionSaveAs_triggered()
{
if(activeMdiChild()&&activeMdiChild()->saveAs())
ui->statusBar->showMessage(tr("文件保存成功"),2000);
}
void MainWindow::on_actionUndo_triggered()
{
if(activeMdiChild())
activeMdiChild()->undo();
}
void MainWindow::on_actionRedo_triggered()
{
if(activeMdiChild())
activeMdiChild()->redo();
}
void MainWindow::on_actionCut_triggered()
{
if(activeMdiChild())
activeMdiChild()->cut();
}
void MainWindow::on_actionCopy_triggered()
{
if(activeMdiChild())
activeMdiChild()->copy();
}
void MainWindow::on_actionPaste_triggered()
{
if(activeMdiChild())
activeMdiChild()->paste();
}
void MainWindow::on_actionClose_triggered()
{
ui->mdiArea->closeActiveSubWindow();
}
void MainWindow::on_actionCloseAll_triggered()
{
ui->mdiArea->closeAllSubWindows();
}
void MainWindow::on_actionAbout_triggered()
{
QMessageBox::about(this,"關(guān)于",tr("致力于多文檔編輯器普及工作"));
}
void MainWindow::on_actionAboutQt_triggered()
{
QMessageBox::about(this,"關(guān)于Qt",tr("Qt是一個(gè)1991年由Qt Company開(kāi)發(fā)的跨平臺(tái)C++圖形用戶界面應(yīng)用程序開(kāi)發(fā)框架。它既可以開(kāi)發(fā)GUI程序,也可用于開(kāi)發(fā)非GUI程序,比如控制臺(tái)工具和服務(wù)器。Qt是面向?qū)ο蟮目蚣?,使用特殊的代碼生成擴(kuò)展(稱(chēng)為元對(duì)象編譯器(Meta Object Compiler, moc))以及一些宏,Qt很容易擴(kuò)展,并且允許真正地組件編程。"));
}
void MainWindow::on_actionExit_triggered()
{
//等價(jià)于QApplication::closeAllWindows();
qApp->closeAllWindows();
}
最后是main函數(shù)
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
以上就是Qt項(xiàng)目實(shí)戰(zhàn)之實(shí)現(xiàn)多文本編輯器的詳細(xì)內(nèi)容,更多關(guān)于Qt多文本編輯器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言中的long型究竟占4個(gè)字節(jié)還是8個(gè)字節(jié)(遇到的坑)
小編在復(fù)習(xí)C語(yǔ)言的時(shí)候踩到了不少坑,糾結(jié)long類(lèi)型究竟占4個(gè)字節(jié)還是8個(gè)字節(jié)呢?好,今天通過(guò)本文給大家分享下我的詳細(xì)思路,感興趣的朋友跟隨小編一起看看吧2021-11-11
c++實(shí)現(xiàn)獲取當(dāng)前時(shí)間(精確至秒,毫秒和微妙)
這篇文章主要為大家詳細(xì)介紹了c++實(shí)現(xiàn)獲取當(dāng)前時(shí)間(可以精確至秒,毫秒和微妙)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2023-11-11
C語(yǔ)言進(jìn)度條的實(shí)現(xiàn)原理詳解
這篇文章主要介紹了C語(yǔ)言進(jìn)度條的實(shí)現(xiàn)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
C++算法計(jì)時(shí)器的實(shí)現(xiàn)示例
本文主要介紹了C++算法計(jì)時(shí)器的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的定時(shí)器
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的定時(shí)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
C++實(shí)現(xiàn)洗牌發(fā)牌排序功能的示例代碼
本篇文章主要介紹了C++實(shí)現(xiàn)洗牌發(fā)牌排序功能的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10

