在前面的章节中,我们讨论了 Qt 标准对话框QMessageBox
的使用。所谓标准对话框,其实也就是一个普通的对话框。因此,我们同样可以将QDialog
所提供的其它特性应用到这种标准对话框上面。今天,我们继续讨论另外一个标准对话框:QFileDialog
,也就是文件对话框。在本节中,我们将尝试编写一个简单的文本文件编辑器,我们将使用QFileDialog
来打开一个文本文件,并将修改过的文件保存到硬盘。这或许是我们在本系列中所提供的第一个带有实际功能的实例。
首先,我们需要创建一个带有文本编辑功能的窗口。借用我们前面的程序代码,应该可以很方便地完成:
openAction = new QAction(QIcon(":/images/file-open"), tr("&Open..."), this); openAction->setShortcuts(QKeySequence::Open); openAction->setStatusTip(tr("Open an existing file")); saveAction = new QAction(QIcon(":/images/file-save"), tr("&Save..."), this); saveAction->setShortcuts(QKeySequence::Save); saveAction->setStatusTip(tr("Save a new file")); QMenu *file = menuBar()->addMenu(tr("&File")); file->addAction(openAction); file->addAction(saveAction); QToolBar *toolBar = addToolBar(tr("&File")); toolBar->addAction(openAction); toolBar->addAction(saveAction); textEdit = new QTextEdit(this); setCentralWidget(textEdit);
我们在菜单和工具栏添加了两个动作:打开和保存。接下来是一个QTextEdit
类,这个类用于显示富文本文件。也就是说,它不仅仅用于显示文本,还可以显示图片、表格等等。不过,我们现在只用它显示纯文本文件。QMainWindow
有一个setCentralWidget()
函数,可以将一个组件作为窗口的中心组件,放在窗口中央显示区。显然,在一个文本编辑器中,文本编辑区就是这个中心组件,因此我们将QTextEdit
作为这种组件。
我们使用connect()
函数,为这两个QAction
对象添加响应的动作:
/// !!!Qt5 connect(openAction, &QAction::triggered, this, &MainWindow::openFile); connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile); /// !!!Qt4 connect(openAction, SIGNAL(triggered()), this, SLOT(openFile())); connect(saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
这些应该都不是问题。我们应该能够很清楚这些代码的含义。下面是最主要的openFile()
和saveFile()
这两个函数的代码:
void MainWindow::openFile() { QString path = QFileDialog::getOpenFileName(this, tr("Open File"), ".", tr("Text Files(*.txt)")); if(!path.isEmpty()) { QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Read File"), tr("Cannot open file:\n%1").arg(path)); return; } QTextStream in(&file); textEdit->setText(in.readAll()); file.close(); } else { QMessageBox::warning(this, tr("Path"), tr("You did not select any file.")); } } void MainWindow::saveFile() { QString path = QFileDialog::getSaveFileName(this, tr("Open File"), ".", tr("Text Files(*.txt)")); if(!path.isEmpty()) { QFile file(path); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(this, tr("Write File"), tr("Cannot open file:\n%1").arg(path)); return; } QTextStream out(&file); out << textEdit->toPlainText(); file.close(); } else { QMessageBox::warning(this, tr("Path"), tr("You did not select any file.")); } }
在openFile()
函数中,我们使用QFileDialog::getOpenFileName()
来获取需要打开的文件的路径。这个函数具有一个长长的签名:
QString getOpenFileName(QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0)
不过注意,它的所有参数都是可选的,因此在一定程度上说,这个函数也是简单的。这六个参数分别是:
- parent:父窗口。我们前面介绍过,Qt 的标准对话框提供静态函数,用于返回一个模态对话框(在一定程度上这就是外观模式的一种体现);
- caption:对话框标题;
- dir:对话框打开时的默认目录,“.” 代表程序运行目录,“/” 代表当前盘符的根目录(特指 Windows 平台;Linux 平台当然就是根目录),这个参数也可以是平台相关的,比如“C:\\”等;
- filter:过滤器。我们使用文件对话框可以浏览很多类型的文件,但是,很多时候我们仅希望打开特定类型的文件。比如,文本编辑器希望打开文本文件,图片浏览器希望打开图片文件。过滤器就是用于过滤特定的后缀名。如果我们使用“Image Files(*.jpg *.png)”,则只能显示后缀名是 jpg 或者 png 的文件。如果需要多个过滤器,使用“;;”分割,比如“JPEG Files(*.jpg);;PNG Files(*.png)”;
- selectedFilter:默认选择的过滤器;
- options:对话框的一些参数设定,比如只显示文件夹等等,它的取值是
enum QFileDialog::Option
,每个选项可以使用 | 运算组合起来。
QFileDialog::getOpenFileName()
返回值是选择的文件路径。我们将其赋值给 path。通过判断 path 是否为空,可以确定用户是否选择了某一文件。只有当用户选择了一个文件时,我们才执行下面的操作。在saveFile()
中使用的QFileDialog::getSaveFileName()
也是类似的。使用这种静态函数,在 Windows、Mac OS 上面都是直接调用本地对话框,但是 Linux 上则是QFileDialog
自己的模拟。这暗示了,如果你不使用这些静态函数,而是直接使用QFileDialog
进行设置,就像我们前面介绍的 QMessageBox 的设置一样,那么得到的对话框很可能与系统对话框的外观不一致。这一点是需要注意的。
首先,我们创建一个QFile
对象,将用户选择的文件路径传递给这个对象。然后我们需要打开这个文件,使用的是QFile::open()
,其参数是指定的打开方式,这里我们使用只读方式和文本方式打开这个文件(因为我们选择的是后缀名 txt 的文件,可以认为是文本文件。当然,在实际应用中,可能需要进行进一步的判断)。QFile::open()
打开成功则返回 true,由此继续进行下面的操作:使用QTextStream::readAll()
读取文件所有内容,然后将其赋值给QTextEdit
显示出来。最后不要忘记关闭文件。另外,saveFile()
函数也是类似的,只不过最后一步,我们使用<<
重定向,将QTextEdit
的内容输出到一个文件中。关于文件操作,我们会在后面的章节中进一步介绍。
这里需要注意一点:我们的代码仅仅是用于演示,很多必须的操作并没有进行。比如,我们没有检查这个文件的实际类型是不是一个文本文件。并且,我们使用了QTextStream::readAll()
直接读取文件所有内容,如果这个文件有 100M,程序会立刻死掉,这些都是实际程序必须考虑的问题。不过这些内容已经超出我们本章的介绍,也就不再详细说明。
至此,我们的代码已经介绍完毕,马上可以编译运行一下了:
本章的代码可以在这里下载:
98 评论
大哥,我还是没法编译,卡在编译资源的时候. 4.8.3, win32
mingw32-make[1]: Leaving directory `D:/Documents and Settings/lulu/qttest/QtStudyRoad-build-Unnamed_gcc-Debug'
process_begin: CreateProcess(NULL, bin\rcc.exe -name resource ..\src\resource.qrc -o debug\qrc_resource.cpp, ...) failed.
make (e=2): 系统找不到指定的文件。
mingw32-make[1]: *** [debug/qrc_resource.cpp] Error 2
mingw32-make: *** [debug] Error 2
00:30:21: 进程"C:\MinGW\bin\mingw32-make.exe"退出,退出代码 2 。
Error while building/deploying project QtStudyRoad (target: Unnamed_gcc)
When executing step 'Make'
debug\qrc_resource.cpp这个文件似乎没有被生成出来
qt库的bug,己解决
Qt 库的 bug?怎么解决的呀?
😛 我觉得是他的路径里面有空格或者中文什么的导致的
这个不大清楚了,呵呵
一个小问题,窗口忘记加statusBar了 😛
只是无伤大雅的 ;-P 因为程序中实际是用不到这一项的。
豆子,请问qt creator有没有和eclipse一样自动添加需要的头文件的功能?
目前好像没有类似的功能,并且一般也不大容易实现类似的功能:因为 Java 文件名和类名是一致的,但是 C++ 没有此要求,如果要实现类似的功能,必须扫描全部文件来找到这个类。
程序读取文本时中文出现问题。
如过我读入的是utf8的文本,中文没问题。如果是ANSI文本,中文乱码。
发现了,如果使用QTextStream类,中文就不会出现乱码。这是为什么?
QTextStream 在内部统一使用 Unicode 编码,所以用 QTextStream 写入和读取都不会有乱码。
应该是编码问题,ANSI 在中文环境下使用的是 GB2312 编码,你必须将 ANSI 文件以 GB2312 解码后才能正常读取(如果没有明确指定的话,默认读取是按照 ASCII 解码的,所以会出现乱码)。
现在又产生了一个疑问。对于UTF-8编码,区分有BOM和无BOM之分,但QT保存的文本默认是无BOM的。如何判断文件编码,选择性的设置编码类型呢?
判断文件编码没有很好的办法,一般是用某些算法去检测一段字符,来“猜测”是哪个编码。如果要自己去写类似的算法,你必须了解所有编码的格式,这在实际开发中往往是不可行的。因此类似的需求会使用某些成熟的第三方库,比如 Mozilla 提供的 chardet(http://www-archive.mozilla.org/projects/intl/chardet.html)等。
嗯,学习了。
希望豆子能弄几个界面的类的详细解说 像QWidget 和QDialog等 有些布局之类是不能用的 新手难知道。。还有QMenuBar等效果也不一样 😯
哪些布局不能使用的?这个不大清楚啊
豆子,我按照你的教程写的报了一堆错,首先,saveAction没有高亮,而且报错:saveAction' was not declared in this scope
是不是要加什么头文件啊?openAction是可以的..
textEdit也是同样的错误,was not declared in this scope,我添加了QTextEdit头文件..
void MainWindow::openFile()和saveFile()报同样的错:no 'void MainWindow::openFile()' member function declared in class 'MainWindow'
还有一个错误是我按照以前你说的写:
connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
这样会报错,但是我看帮助文件改成了:
connect(saveAction,SIGNAL(triggered()), this, SLOT(saveFile()));
就没有报错了,为什么会这样啊?
不好意思啊,问题有点多...
saveAction、textEdit 和 openFile() 是因为你没有在头文件中声明。这是 C++ 所要求的,所有变量在使用之前必须声明。至于 connect() 这段,是因为这是 Qt5 的新语法,如果你使用的不是 Qt5,就需要改成 Qt4 的语法,也就是带有 SIGNAL/SLOT 宏的那种。
我的是QT5.5版本,为啥我的connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
这样会报错,但是我看帮助文件改成了:
connect(saveAction,SIGNAL(triggered()), this, SLOT(saveFile()));
就没有报错了,为什么会这样啊?和上面一个情况!!!
有没有在 .pro 文件添加 CONFIG += c++11
QMenu *file = menuBar()->addMenu(tr("&File"));
file->addAction(openAction);
file->addAction(saveAction);
QToolBar *toolBar=addToolBar("&File");
toolBar->addAction(openAction);
toolBar->addAction(saveAction);
豆子 我的菜单怎么不显示啊,那个toolbar显示呢
不知道什么情况谢谢
我发现了 原来是因为我建立 的工程里面有// ui->setupUi(this);
这一句 哈哈 去掉就ok
你好,我测试了一下您上传的“ch17-qt5.zip”代码,结果出现许多错误。根据错误信息,我在“mainwindow.cpp”中加入
#include
#include
#include
#include
#include
#include
于是程序可以通过编译,正常运行了。
我想知道我是不是弄错了什么地方。我没有使用"Qt Creator",是手动调用qmake、make等命令编译的。(.pro文件要作修改,加上”QT += widgets“)莫非使用"Qt Creator"就不需要亲自include上面的那些文件?抑或豆子忘记添加了?对这里不太清楚~
天啊,include被吞掉了!!!
QAction
QMenuBar
QToolBar
QTextEdit
QFileDialog
QMessageBox
就是这几个。
如果需要<和>,请使用<和>转义
好给力呀,跟着豆子学,现在都水写记事本了。今天学到地十七课。留个脚印。
打开文件那一段代码,能不能用 try...catch...改写?
Qt提供了相关的异常捕获类吗?
Qt 基本不使用任何异常代码。因为 Qt 在开始开发时,异常还不被所有 Qt 所需要的编译器支持。所以,今天为了保持 API 兼容性,旧的模块也不能增加异常的代码。但是新的模块可能会增加。简答来说,Qt 现在还是很有限地使用异常:http://qt-project.org/doc/qt-5.0/qtdoc/exceptionsafety.html
hello,我最近在做ATM机的实验。在做的过程中遇到了难题(申明一下,我是一个QT新手):
我是将用户信息保存在一个txt文件中的,是卡号、密码、余额各一行这样三个一循环。
在取款时,同时必须将txt文件中某账户的余额也改变。可是我不知道怎样将游标指向txt文件中的特定行,并将它用新的余额覆盖。很急哦。。。求大神指点,现在这里谢谢了!
ATM 用 txt 存密码岂不是太不安全?建议改成数据库,这样就方便很多了。如果一定要 txt,那就一行一行地遍历找到那行数据然后修改吧。
您好 最近在学习使用QT5 这里的讲得很好 在使用示例代码使用文件对话框时 为什么只能选择一次文件 再次选择文件的时候显示You did not select any file的消息框 然后保存文件对话框也是没反映的 请问该如何解决 感谢
我这里测试是正常的,不知道哪里出了问题?
我用的vs2010 是不是和设置有关呢?另外我还加入了opencv,qT应该是兼容的?
我把opencv去掉后 就正常了 纠结 和MFC一样又是兼容性问题
请问您有没有试过QT和opencv同时使用?有解决的办法不?
没有相关经验。不过不清楚 opencv 怎么会影响到 Qt 的代码?这段代码非常简单,看上去不大会出错的。
我现在尝试把opencv重新编译成QT兼容的
问题已经解决,我把opencv用Cmake重新编译成QT版的,然后在QT Creater上运行无问题。
看来还是冲突了。一般版本不对都会不能通过编译或者运行时直接出错,像你这种运行正常、只是有小问题的还没见过。
必须一定要赞扬豆子了,谢谢你的精力,时间免费无偿的默默地服务于人们,真好
多谢支持!
豆子你好,请问在源码mainwindow.h里的class QtextEdit;
这句话是干什么用的? 另外为什么会有一个private.slot,
class QtextEdit; 是前置声明,这是基础 C++ 的语法,建议看看相关教程。private slot 是私有槽函数,可以认为是一种能够与信号连接的私有函数。
那为何QAction不用类前置声明呢?
看到这里有些不解,希望能够解惑
头文件中可以使用前置声明,但是如果在源代码文件中,因为需要使用这个类的函数,所以比如完全 include 进来
不加slot可以吗?我记得你之前说slot函数可以看做普通的member函数
如果是 Qt 5,使用新语法可以连接到任意函数;对于 Qt 4 则不可以。“slot函数可以看做普通的member函数”的含义是在进行普通的函数调用时,而不是作为 slot 使用时。
博主文章写得清晰明了易懂,感谢
大赞博主!最近一直在看您的文章,收益颇多,谢谢!
豆子老师,你这个fileSave函数到最后没有把textEdit中的内容写到所打开的文件中啊,只是把它给了out这个变量。是不是呢?
out
是一个QTextStream
类型的对象,<< 做了输出重定向,实际上是将文本内容输出到QTextStream
,由QTextStream
写入豆子老师,为什么我按照上面的程序写法写出来进行保存操作后,再打开保存的文件,发现里面的内容并不是textedit里面的内容呢?
豆子老师您好!非常感谢您的教程!
想请教一个问题,您说在这个演示中没有检查这个文件的实际类型是不是一个文本文件。想请教您能否简单讲解一下要怎样做这个检查?
这个没有标准的办法检查,一般是尝试看是不是这种类型的文件,例如使用 MINE 这样的媒体类型库。
豆子我要给你生猴子,另外问一下函数声明写在private和private slots有什么区别吗
private 是 C++ 关键字,表示私有函数;slots 是 Qt 的关键字,表示一个槽函数;private slots 就是一个私有的槽函数。
把那个open和save写在private里面好像也可以当槽函数使用。
为什么用QT creator是这样的
Starting C:\Users\Administrator\Desktop\workspace\filedialog-qt5\build-QtStudyRoad-Desktop_Qt_5_5_1_MSVC2013_32bit-Debug\debug\QtStudyRoad.exe...
程序异常结束。
C:\Users\Administrator\Desktop\workspace\filedialog-qt5\build-QtStudyRoad-Desktop_Qt_5_5_1_MSVC2013_32bit-Debug\debug\QtStudyRoad.exe crashed
而用VS2013是无法启动该程序,因为计算机丢失icuin51.dll。尝试重新安装该程序以解决问题
我一直使用 Qt Creator,没有任何问题;感觉好像是路径不对,icuin51.dll 原本应该是在 bin 目录下的,使用 Qt Creator 应该是没有问题的
重启电脑后用VS2013居然好了,Qt creator变成了没有加调试器,加了debugging tools也好了,重启果然是修电脑的大神器。。。。
豆子老师你好,照着你的代码自己敲进去,发现ICON的图片显示不出来,但是路径正确,资源也是有。
然后下载了你的源码导入发现可以显示,于是我对比了一下每个文件,也确定没有错误,不知道什么原因图片还是显示不出来。
是路径问题,加“:/”。我的是这样解决的。
加在哪?怎么加?貌似本来路径就有那个了
https://www.devbean.net/2012/08/qt-study-road-2-resource-files/
参考豆子之前的文章.
豆子的代码里qrc文件里指定了别名.
https://www.devbean.net/2012/08/qt-study-road-2-resource-files/
参考这里, 豆子的代码里qrc文件里指定了别名,而你手敲的代码这里没有指定别名.
要么指定别名, 要么路径填写完整
选择了文件打开后程序就会异常结束是因为什么呢?save操作也有这样的问题
Starting C:\lxj\Qt\build-mainwindow-Desktop_Qt_5_5_1_MSVC2010_32bit-Debug\debug\mainwindow.exe...
程序异常结束。
C:\lxj\Qt\build-mainwindow-Desktop_Qt_5_5_1_MSVC2010_32bit-Debug\debug\mainwindow.exe crashed
程序异常结束一般是因为内存的问题,可能是前面会有哪里有错误,这个需要仔细查看的
为什么我的打开和保存图标没有显示出来?检查了代码和资源链接都没问题啊
图片资源是png格式的吗?
找到原因了,我忘了在.pro文件添加 “RESOURCES = **.qrc” 这句代码了。
重新运行一下 qmake,或者重新构建一下试试
豆老师您好,这个打开txt 文件没问题,但若是打开mda 或 dat 等二进制文件则显示乱码??若想将二进制文件打开并用字符串显示在textEdit中的话程序该怎么改动??(Qt刚学两天。。)
二进制文件不能直接显示,如果你想以 0、1 显示二进制文件,需要自己一个位一个位的读取(或者读取四个位,按照十六进制显示),然后将其显示出来。
豆子大哥
请问怎么可以将文件保存到指定目录下呢
就是不需要对话框的这种
我在编码时指定目录
查了好久也没找到该怎么去弄
请指教
不要用户选择的话,你只需要直接设置 QFile 的路径就可以了。
豆子老师你好,我想问一下如何在头文件中声明textEdit,就是格式是什么样子。谢谢。
在 class 声明中添加
QTextEdit *textEdit;
就可以了不好意思提一个比较弱鸡的问题,为什么这里的connect函数不需要域QObject::connect?
确切的说,这并不是“域”(C++ 里面好像并没有这个名词),QObject::connect 是调用了 QObject 类的 static 函数。因为这里的类都是 QObject 的子类,继承了这些 static 函数,所以就不需要 QObject 前缀了
豆老师,为什么用QPushputton 和 QAction 的时候可以在class中直接声明,使用QTextEditde时候直接声明会报错,加上类的前置声明才可以用
这可能是因为在其它头文件中,比如 QFileDialog 中已经有过 QPushButton 的声明,所以不需要额外再次声明
豆老师,请教一下菜单栏的问题。我在design里面加上菜单栏以后,auto file = &(UI->menubarfile),file->addaction(actionname).然后就开始报错,说ui里面没有这些object,连之后的textedit也识别不了了。请问这是什么问题?如果我直接写,不在designer里面画就完全没问题。
而且我这个项目里面就算没有引用ui->menubar,在designer里面画了,在mainwindow也不显示。
有没有调用 setupUi() 函数?或者应该在这个函数之后再使用组件?
豆子老师真是育人不倦啊!致敬!
老师您好:mainwindow.cpp里面有一句:“textEdit = new QTextEdit(this);”
如果在textEdit前面加上一个:Qtext Edit *
就会在我选择了要打开的文件之后直接显示程序异常结束呢?
textEdit = new QTextEdit(this); 是初始化了作为成员变量的 textEdit,以便在后面打开文件时使用这个变量。如果你改为 QTextEdit *textEdit = new QTextEdit(this);,则是在构造函数里面创建了一个新的变量 textEdit,虽然名字一样,但这个变量的作用域是构造函数,在构造函数以外,是无法使用 textEdit 这个名字的。因此,当你选择要打开的文件的时候,代码还是使用的成员变量 textEdit,但此时,这个成员变量并没有初始化,也就是说,成员变量 textEdit 是一个野指针,所以程序会异常结束
getOpenFileName和getSaveFileName看起来是一样的,为何要做成两个函数呢?原来getOpenFileName只能选择已经存在的文件,而getSaveFileName可以自己输入一个文件名用来保存。我觉得可以加上这部分内容,以免读者看的时候疑惑。
刚开始学习Qt,为啥下载不了源代码?/:笑哭
我这里测试是可以下载的
初学Qt,希望答主能写一章关于ui_mainwindow的介绍,现在创建文件好像自带这个。
ui_mainwindow 是 Qt Desinger 生成的文件,用于记录界面设计的,只要在 Qt Creator 中拖放就可以了。这个文件是自动生成的,以 XML 格式描述界面用的
请教个问题,用 file_name = QFileDialog::getOpenFileName(this,
tr("选择烧录文件"),
QCoreApplication::applicationDirPath(),
tr("Bin File (*.bin)"));
第一次打开的时候特别慢(后面再去打开的话速度就是正常的),button按下去后差不多要5秒才跳出来选择文件的对话框,请帮忙看看是否有需要特别设置的地方。
QT版本5.14.1, 编译器是mingw32.
这个应该没有特殊设置,不知道是什么原因。会不会因为文件夹内文件过多?
豆子老师,为什么用openfile打开的文件不仅内容没显示出来,而且文件内容也没了
不管是先用saveopen保存的还是提前写在txt里面的内容都是的
下面的源代码。下载不了了。 豆子 hxd更新一下呀
我这里是可以下载的