QT中的QMainWindow类为用户提供了一个主窗口程序,包括一个菜单栏、多个工具栏、多个锚接部件、一个状态条以及一个中央窗体,本程序结合了代码设计布局和ui的使用,全面体现了QMainWindow窗口中所用到的功能。更主要的是解决锚接部件的神秘性,解剖它的运行过程。
(1)QMainWindow框架,如下图1所示。
(2)本程序运行效果图,如下图2所示。
void MainWindow::createCentralWidget()
{
textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
//textEdit->setReadOnly(true);
connect(textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorChanged()));
connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(slotModified()));
}
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
editMenu = menuBar()->addMenu(tr("&Edit"));
toolMenu = menuBar()->addMenu(tr("&Tool"));
fileMenu->addAction(fileNewAction);
fileMenu->addAction(fileOpenAction);
fileMenu->addAction(fileCloseAction);
fileMenu->addSeparator();
fileMenu->addAction(fileSaveAction);
fileMenu->addAction(fileSaveAsAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
editMenu->addAction(undoAction);
editMenu->addAction(redoAction);
editMenu->addSeparator();
editMenu->addAction(cutAction);
editMenu->addAction(copyAction);
editMenu->addAction(pasteAction);
editMenu->addSeparator();
editMenu->addAction(pickAllAction);
toolMenu->addAction(findAction);
toolMenu->addAction(printAction);
toolMenu->addSeparator();
toolMenu->addAction(aboutAction);
}
void MainWindow::createToolBars()
{
fileTool = addToolBar("File");
fileTool->setMovable(false);
fileTool->setOrientation(Qt::Horizontal);
fileTool->addAction(fileNewAction);
fileTool->addAction(fileOpenAction);
fileTool->addAction(fileSaveAction);
fileTool->addAction(fileSaveAsAction);
editTool = addToolBar("Edit");
editTool->setAllowedAreas(Qt::AllToolBarAreas);
editTool->setOrientation(Qt::Horizontal);
editTool->addAction(undoAction);
editTool->addAction(redoAction);
editTool->addAction(copyAction);
editTool->addAction(cutAction);
editTool->addAction(pasteAction);
}
void MainWindow::createStatusBar()
{
//QStatusBar* bar = statusBar();
//bar->setStyleSheet(QString("QStatusBar::item{border: 1px}"));
statusBar()->showMessage(tr("Begin"));
}
在程序交叉度比较大些,尽可能的把功能分开,做到高内聚、低耦合。
// 多文档实现
void MainWindow::setCurrentFile(const QString &fileName)
{
curFile = QFileInfo(fileName).canonicalFilePath();
isUntitled = false;
setWindowTitle(curFile + "[*]");
textEdit->document()->setModified(false);
setWindowModified(false);
QSettings settings("710", "main_example");
QStringList files = settings.value("recentFiles").toStringList();
files.removeAll(fileName);
files.prepend(fileName);
while (files.size() > MaxRecentFiles) {
files.removeLast();
}
settings.setValue("recentFiles", files);
//updateRecentFiles(); 单文档采用
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
MainWindow *mainWindow = qobject_cast(widget);
if (mainWindow) mainWindow->updateRecentFiles();
}
}
void MainWindow::updateRecentFiles()
{
QSettings settings("710", "main_example");
QStringList files = settings.value("recentFiles").toStringList();
int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles);
for (int i = 0; i < numRecentFiles; ++i) {
QString text = tr("&%1 %2").arg(i + 1).arg(files[i]);
recentFileActs[i]->setText(text);
recentFileActs[i]->setData(files[i]);
recentFileActs[i]->setVisible(true);
}
for (int i = numRecentFiles; i < MaxRecentFiles; ++i)
recentFileActs[i]->setVisible(false);
separatorAct->setVisible(numRecentFiles > 0);
}
void MainWindow::createCurFileMenu()
{
separatorAct = fileMenu->insertSeparator(exitAction);
separatorAct->setVisible(false);
for (int i = 0; i < MaxRecentFiles; ++i) {
recentFileActs[i] = new QAction(this);
fileMenu->insertAction(separatorAct, recentFileActs[i]);
recentFileActs[i]->setVisible(false);
connect(recentFileActs[i], SIGNAL(triggered()), this, SLOT(openRecentFile()));
}
}
利用QSettings保存最近打开的十个历史文件,并在下次程序运行是从QSettings settings("710", "main_example");中加载这个文件的绝对路径到文件菜单下,并提供triggered()的信号处理。而且每次打开一个文件及时更新该列表。
锚接部件设置,开始不浮动停靠在右侧,可以停靠在所有方位。
void MainWindow::insertDockWidget()
{
dockWidget = new QDockWidget(tr("find file"), this);
findFileForm = new CFindFileForm(dockWidget);
dockWidget->setAllowedAreas(Qt::RightDockWidgetArea);
//dockWidget->setAllowedAreas(Qt::AllDockWidgetAreas);
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
dockWidget->setFloating(false);
dockWidget->setWidget(findFileForm);
dockWidget->setVisible(true);
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
connect(findFileForm, SIGNAL(doCellClicked(int, int)), this, SLOT(slotCellClicked(int, int)));
}
锚接部件浮在主窗口之上,如下图3所示。
对于查找文件后双击列表的文件路径所在的单元格,就能打开该文件。
// 设置光标的选区,使格式作用于选区内的字符,若没有选区则作用于光标所在处的字符
void MainWindow::mergeFormat(QTextCharFormat fmt)
{
QTextCursor cursor = textEdit->textCursor();
if (!cursor.hasSelection()) {
cursor.select(QTextCursor::WordUnderCursor);
}
cursor.mergeCharFormat(fmt);
textEdit->mergeCurrentCharFormat(fmt);
}
void MainWindow::slotFont(QString type)
{
QTextCharFormat fmt;
fmt.setFontFamily(type);
mergeFormat(fmt);
}
void MainWindow::slotSize(QString size)
{
QTextCharFormat fmt;
fmt.setFontPointSize(size.toFloat());
mergeFormat(fmt);
}
void MainWindow::slotBold()
{
QTextCharFormat fmt;
fmt.setFontWeight(boldToolBtn->isChecked()? QFont::Bold : QFont::Normal);
mergeFormat(fmt);
}
void MainWindow::slotItalic()
{
QTextCharFormat fmt;
fmt.setFontItalic(italicToolBtn->isChecked());
mergeFormat(fmt);
}
void MainWindow::slotUnder()
{
QTextCharFormat fmt;
fmt.setFontUnderline(underToolBtn->isChecked());
mergeFormat(fmt);
}
void MainWindow::slotColor()
{
QColor color = QColorDialog::getColor(Qt::red,this);
if(color.isValid()) {
QTextCharFormat fmt;
fmt.setForeground(color);
mergeFormat(fmt);
}
}
void MainWindow::slotCurrentFormatChanged(const QTextCharFormat &fmt)
{
fontComboBox->setCurrentIndex(fontComboBox->findText(fmt.fontFamily()));
fontComboBox->setCurrentIndex(fontComboBox->findText(QString::number(fmt.fontPointSize())));
boldToolBtn->setChecked(fmt.font().bold());
italicToolBtn->setChecked(fmt.fontItalic());
underToolBtn->setChecked(fmt.fontUnderline());
}
效果图如下图4所示。
通过QTextCharFormat类设置光标选区文字的字体、字号、加粗、倾斜、颜色、样式和对齐方式。调用了Qt内置的字体格式和颜色对话框QColorDialog::getColor(Qt::red,this);
多文档方式打开框口,如下如5所示。
//单文档
//void CMainWindow::doNew()
//{
// maybeSave();
// isUntitled = true;
// curFile = tr("untitled");
// setWindowTitle(curFile + "[*]");
// textEdit->clear();
// textEdit->setVisible(true);
// setWindowModified(false);
//}
void MainWindow::slotNewFile()
{
MainWindow *newWin = new MainWindow;
newWin->show();
}
多文档就是打开多个独立的窗口操作,单文档是始终在一个窗口操作。注意文件关闭时的保存,还有多文档时打开菜单下历史文件名字的多窗口的更新操作。
查找文件对话框是通过ui设计的,如下如6所示。
QStringList CFindFileForm::findFiles(const QDir &dir, const QString &fileName,
const QString &txt)
{
QStringList files = dir.entryList(QStringList(fileName),
QDir::Files | QDir::NoSymLinks);
if (txt.isEmpty())
return files;
QStringList foundFiles;
Qt::CaseSensitivity sensitive = Qt::CaseInsensitive;
if(m_bSensitive)
sensitive = Qt::CaseSensitive;
for (int i = 0; i < files.size(); ++i)
{
qApp->processEvents();
if (m_bStoped)
break;
QFile file(dir.absoluteFilePath(files[i]));
if (file.open(QIODevice::ReadOnly))
{
QString line;
QTextStream in(&file);
while (!in.atEnd())
{
if (m_bStoped)
break;
line = in.readLine();
if (line.contains(txt, sensitive))
{
foundFiles << files[i];
break;
}
}
}
}
return foundFiles;
}
可以以文件名加路径查找,可以以文件包含的内容加路径查找,区分大小写和子目录的递归查找。显示查找结果,点击查找中的文件路径直接显示在左侧的中心部件中。
(1)因本代码比较多,讲解不能面面俱全,请下载源码阅读理解。
(2)源码已经打包上传到csdn上可登录下载(http://download.csdn.net/detail/taiyang1987912/7527461)。
(3)本人水平有限,错误重现,请读者及时指出,若有更好的设计建议,也可发邮件联系,在此先感谢!
邮箱地址[email protected]。
(4)所用的Qt的库Qt4.6.2,GCC4.4.6 20120305 (Red Hat 4.4.6-4) 。系统是centos6.3。
(1)当关闭中心部件时(菜单栏的关闭),再次打开文件时,文件内容不显示,修改为:增加textEdit->setVisible(true);
bool MainWindow::loadFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("read file"),
tr("can not read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
return false;
}
textEdit->setVisible(true);
//...
}