QT编程
下载QT
http://download.qt.io/official_releases/qt/5.12/5.12.0/
image-20200913175437819
下载那个exe,然后安装好.
image-20200913180336560
image-20200913180400705
新建项目
左上角文件-> 新建项目
image-20200913181029681
然后这里用Dialog
image-20200913181212608
配置链接
点那个配置链接的图标,然后从slidebar
拖拽到dial组件,就可以生成一个信号
image-20200913181812844
文档
在开始搜索assist,打开assistant MinGW 就可以打开Qt的文档
image-20200913183304138
程序发布
首先设置成release版本
image-20200913183934227
然后构建,打开构建的目录
image-20200913184027503
然后再release文件夹下面可以找到 .exe
文件
进入Qt控制台
输入 windeployqt + ".exe文件"
image-20200913184207549
然后就可以直接跑了
用qmake编译程序
快速生成makefile
生成project .pro
文件
编译
UI设计基础
窗口的种类
MainWindow
有菜单栏, 有QWidget
它包含 DockWidget: 可以拖拽,附着的窗口
Statusbar: 状态栏
Toolbar:工具栏
image-20200913192551767
只有一个QWidget
可以放大放小
Dialog
不能放大放小
模态与非模态窗口
模态窗口
只能操作当前窗口
非模态窗口
可以切换到其他窗口
半模态窗口
堵塞部分功能
信号与槽
发送某个按键的信号,响应某个槽函数
创建一个槽
选择一个组件,右键,转为槽
image-20200913193643607
1 2 3 4 void Dialog::on_pushButton_clicked () { ui->label->setText ("New Text changed" ); }
然后就可以在自动创建的这个方法里面修改别的属性
在 .h
文件中,我们可以发现,定义了一个
Q_QBJECT
的宏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Dialog : public QDialog{ Q_OBJECT public : explicit Dialog (QWidget *parent = nullptr ) ; ~Dialog (); private slots: void on_pushButton_clicked () ; private : Ui::Dialog *ui; }; #endif
手动创建信号和槽
在 .h
文件里定义自己的signal 和 slot
1 2 3 4 5 signals: void mypushButtonSignal () ; private slots: void on_pushButton_clicked () ; void mypushButtonSlot () ;
然后可以右键直接添加定义
image-20200913194654194
用 emit
可以发送自定义信号
1 2 3 4 5 void Dialog::on_pushButton_clicked () { emit mypushButtonSignal () ; }
然后用connect绑定一下
1 2 connect (this , SIGNAL (mypushButtonSignal ()), this , SLOT (mypushButtonSlot ()));
另一种connect,关闭窗口
1 connect (ui->pushButton_2, &QPushButton::clicked, this , &QMainWindow::close);
控件
setText 改变文字
setMenu 设置菜单
clicked 信号
练习1 单击按钮改变文字
在 .h
文件里面定义一个变量, 并初始化
1 2 3 4 5 6 7 8 private : Ui::MainWindow *ui; bool deviceStatus; MainWindow::MainWindow (QWidget *parent) : QMainWindow (parent), deviceStatus (false ), ui (new Ui::MainWindow)
然后加一个槽
1 2 3 4 5 6 7 8 9 10 void MainWindow::on_pushButton_clicked () { if (deviceStatus == false ) { ui->pushButton->setText ("断开" ); this ->deviceStatus = true ; } else { ui->pushButton->setText ("连接" ); this ->deviceStatus = false ; } }
改变背景图片
右键pushButton 改变样式表
添加borderimage
image-20200913225226327
然后选择自己要的图片,确定即可。
改变图标
在源代码里改:在构造函数里写这个即可
1 ui->pushButton_2->setIcon (QIcon (":/image/TypeII.png" ));
加入资源
右键项目名,Add New.. 然后选择 Qt Resource File
image-20200913220344392
ToolButton 一般放在Toolbar里面
现在菜单栏里面写几个目录,然后
在这里可以改变图标
image-20200913223847986
然后可以把这些action拖拽到工具栏上面
image-20200913223951167
这些action也可以添加槽,一般添加 triggered 槽
在 .h 文件里面添加头文件
然后就可以在控制台输出
1 2 3 4 void MainWindow::on_actionPaste_triggered () { qDebug () << "paste" ; }
改变窗口的图标
在 .pro 文件末尾加入图标路径
1 RC_ICONS += ./image/favicon.ico
就可以改变程序的图标了.
Label
调用图片
1 2 3 QPixmap mImage = QPixmap (":/image/TypeI.png" ); ui->label->setPixmap (mImage); ui->label->setScaledContents (true );
也可以直接在界面上面选择
调用GIF
添加头文件 QMovie
, 也可以右键Refactor添加
1 2 3 4 QMovie *pMovie = new QMovie (":/image/tenor.gif" ); ui->label_3->setMovie (pMovie); ui->label_3->setFixedSize (640 , 480 ); pMovie->start ();
TextEdit
富文本
image-20200914122934063
PlainTextEdit
剪贴动作
1 connect (cutAct, &QAction::triggered, textEdit, &QPlainTextEdit::cut);
纯文本
image-20200914122945591
有没有改变内容
1 textEdit->document ()->isModified ()
SpinBox
spinBox 和 double SpinBox
image-20200914123123871
accelerate 属性
可以设置加速效果
maximum, minimum 可以设置范围
singleStep 设置步长
suffix和prefix可以设置后缀和前缀
decimals设置小数点位数
DateTime
设置当前时间
1 setDateTime (QDateTime::currentDateTime ());
Dial
notchedVisible 显示精度
pageStep 是按pageUp 和PageDown的步数
LCD Number
数字时钟
1 ui->lcdNumber->display (QString ("333" ));
如果要用时间, 要加入这2个头文件
1 2 3 4 5 6 7 #include <QTime> #include <QDateTime> #include <QTimer> QTime time = QTime::currentTime (); QDateTime datetime = QDateTime::currentDateTime (); QDateTime datetimeutc = QDateTime::currentDateTimeUtc ();
输出时间的格式
1 qDebug () << time.toString ("hh:mm:ss" );
在 .h 里面放一个 private属性
然后再构造器里面设置时间
1 2 3 4 5 6 7 timer.start (1000 ); connect (&timer, &QTimer::timeout, this , &MainWindow::timeoutSlot);void MainWindow::timeoutSlot () { ui->lcdNumber->display (QTime::currentTime ().toString ("hh:mm:ss" )); }
然后就可以完成一个时钟效果
Progressbar
进度条设置进度
1 2 3 4 5 6 ui->progressBar->setValue (88 ); int total = 1666 ;int current = 666 ;ui->progressBar->setMaximum (total); ui->progressBar->setValue (current);
底部状态栏
只有mainwindow 才有状态栏
1 2 ui->statusBar->showMessage ("my message" ); ui->statusBar->showMessage ("my message" , 1000 );
把进度条加入状态栏
1 2 3 4 QProgressBar *pProgressbar = new QProgressBar (this ); ui->statusBar->addPermanentWidget (pProgressbar); pProgressbar->setValue (55 ); pProgressbar->setAlignment (Qt::AlignCenter);
里面可以添加标签页,标签页里面也可以放其他东西进去
创建menu
1 QMenu *fileMenu = menuBar () -> addMenu (tr ("&File" ));
menu加入动作
1 2 3 4 5 fileMenu->addAction (saveAsAct); QAction *exitAct = fileMenu->addAction (exitIcon, tr ("&Exit" ), this , &QWidget::close); QAction *aboutAct = helpMenu->addAction (tr ("&About" ), this , &MainWindow::about);
添加分割符
1 fileMenu->addSeparator ();
TooBar
1 QToolBar *fileToolBar = addToolBar (tr ("File" ));
Icon
第一个参数是名字,第二个参数是文件
1 const QIcon newIcon = QIcon::fromTheme ("document-new" , QIcon (":/images/new.png" ));
不定义图标
1 const QIcon saveAsIcon = QIcon::fromTheme ("document-save-as" );
Action
1 QAction *newAct = new QAction (newIcon, tr ("&New" ), this );
其他操作
1 2 3 4 5 newAct->setShortcuts (QKeySequence::New); newAct->setStatusTip (tr ("Create a new file" )); connect (newAct, &QAction::triggered, this , &MainWindow::newFile); fileMenu->addAction (newAct); fileToolBar->addAction (newAct);
文件管理
1 2 #include <QDir> #include <QFileInfo>
判断文件是否存在
1 2 QDir mDir ("D:/Fyind" ) ;qDebug () << mDir.exists ();
创建文件夹
1 2 3 4 5 6 7 8 QString url = QString ("D:/Fyind/testDir" ); QDir mDir (url) ;if (!mDir.exists ()) { mDir.mkdir (url); qDebug () << "make a new Directory" ; } else { qDebug () << "allready exists" ; }
当前运行目录
1 2 qDebug () << mDir.current ();qDebug () << mDir.currentPath ();
家目录和根目录
1 2 qDebug () << mDir.homePath ();qDebug () << mDir.rootPath ();
文件夹名字和绝对路径
1 2 qDebug () << mDir.dirName ();qDebug () << mDir.absolutePath ();
遍历文件夹
1 2 3 4 5 6 foreach (QFileInfo mItem, mDir.entryInfoList ()) { if (mItem.isDir ()) qDebug () << "Dir " << mItem.filePath (); else if (mItem.isFile ()) qDebug () << "File " << mItem.filePath (); }
使用过滤器
1 2 3 4 QStringList filters; filters << "*.java" ; mDir.setNameFilters (filters); qDebug () << mDir.entryList (filters, QDir::Files);
文件读写
打开并写入文件
1 2 3 4 5 6 7 8 9 QFile file ("afile" ) ;if (!file.open (QIODevice::WriteOnly | QIODevice::Text)) { qDebug () << file.errorString (); } else { qDebug () << "open success" ; } file.write ("hello \n This is a greeting message" ); file.close ();
读取文件内容
1 2 3 4 5 6 7 8 9 10 11 if (!file.open (QIODevice::ReadOnly | QIODevice::Text)) { qDebug () << file.errorString (); } else { qDebug () << "open success2" ; } while (!file.atEnd ()) { QByteArray line = file.readLine (); qDebug () << "read some data: " << line; } file.close ();
文件指针
1 2 3 4 5 6 7 8 9 10 11 if (!file.open (QIODevice::ReadWrite | QIODevice::Text)) { qDebug () << file.errorString (); } else { qDebug () << "open success2" ; } qDebug () << file.pos ();file.seek (9 ); file.write ("i am here" ); qDebug () << file.pos ();file.close ();
读取文件信息
获得大小
1 2 QFileInfo info ("afile" ) ;qDebug () << "size: " << info.size ();
标准对话框
MessageBox
1 2 3 4 QMessageBox::warning (this , tr ("Application" ), tr ("can write file %1:\n%2." ) .arg (QDir::toNativeSeparators (filename), file.errorString ()));
询问文件是否保存
1 2 3 4 5 6 const QMessageBox::StandardButton ret = QMessageBox::warning (this , tr ("Application" ), tr ("The document has been modified.\n" "Do you want to save your changes?" ), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
Qt数据结构
QList
Qt中的列表
1 2 #include <QAbstractTableModel> #include <QList>
深入QT
从空项目构建
新建的时候选择,其他项目,空的QT项目
image-20200923094637770
新建完之后,连pro文件都是空的,需要自己编写.
添加QT依赖
1 2 QT += widgets requires(qtConfig(filedialog))
添加源文件main.cpp
image-20200923095245507
然后添加
1 2 3 4 5 6 7 #include <QApplication> int main (int argc, char * argv[]) { QApplication app (argc, argv) ; return app.exec (); }
然后添加一个 MainWindow 的class
image-20200923095623606
然后main.cpp里再加入
1 2 MainWindow mainWin; mainWin.show ();
就可以运行生成一个最简单的app了
在 mainwindow.h里面加入
1 2 3 4 5 6 #include <QMainWindow> QT_BEGIN_NAMESPACE class QPlainTextEdit ;QT_END_NAMESPACE
就可以在下面定义QT的东西了
1 2 3 private : QPlainTextEdit *TextEdit; QString curFile;
构建GUI
TextEdit
在mainwindow.cpp里面添加
1 2 3 4 5 6 7 8 9 10 11 #include <QtWidgets> #include "mainwindow.h" MainWindow::MainWindow () : textEdit (new QPlainTextEdit) { setCentralWidget (textEdit); }
国际化字符串
QObject::tr()
使用 tr("ddd")
构建的字符串具有国际化翻译功能,
在字符串中加 &
可以定义后面的一个字为快捷键字符 Alt +
那个字符
添加菜单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 MainWindow::MainWindow () : textEdit (new QPlainTextEdit) { setCentralWidget (textEdit); createActions (); } void MainWindow::createActions () { menuBar ()->addMenu (tr ("&Open" )); QMenu *filemenu = menuBar () -> addMenu (tr ("&File" )); }
添加一个新建文件
1 2 3 4 5 6 7 8 9 QMenu *fileMenu = menuBar () -> addMenu (tr ("&File" )); QToolBar *fileToolBar = addToolBar (tr ("File" )); const QIcon newIcon = QIcon::fromTheme ("document-new" , QIcon (":/images/new.png" )); QAction *newAct = new QAction (newIcon, tr ("&New" ), this ); newAct->setShortcuts (QKeySequence::New); newAct->setStatusTip (tr ("Create a new file" )); connect (newAct, &QAction::triggered, this , &MainWindow::newFile); fileMenu->addAction (newAct); fileToolBar->addAction (newAct);
image-20200923105810030
创建状态栏
1 2 3 void MainWindow::createStatusBar () { statusBar ()->showMessage (tr ("ready" )); }
复制粘贴
控制变灰和变彩色
1 2 3 4 5 cutAct->setEnabled (false ); copyAct->setEnabled (false ); connect (textEdit, &QPlainTextEdit::copyAvailable, cutAct, &QAction::setEnabled);connect (textEdit, &QPlainTextEdit::copyAvailable, copyAct, &QAction::setEnabled);
另存为文件
1 2 3 4 5 6 7 8 9 bool MainWindow::saveAs () { QFileDialog dialog (this ) ; dialog.setWindowModality (Qt::WindowModal); dialog.setAcceptMode (QFileDialog::AcceptSave); if (dialog.exec () != QDialog::Accepted) return false ; return saveFile (dialog.selectedFiles ().first ()); }
打开文件
1 2 3 4 5 6 7 void MainWindow::open () { if (maybeSave ()) { QString filename = QFileDialog::getOpenFileName (this ); if (!filename.isEmpty ()) loadFile (filename); } }
改变内容自动加*
1 2 3 4 5 6 7 8 9 connect (textEdit->document (), &QTextDocument::contentsChanged, this , &MainWindow::documentWasModified); void MainWindow::documentWasModified () { setWindowModified (textEdit->document ()->isModified ()); }
关闭事件询问是否保存
关闭事件
1 2 protected : void closeEvent (QCloseEvent *event) override ;
自动保存配置
保存配置
1 2 3 4 5 6 void MainWindow::writeSettings () { QSettings settings (QCoreApplication::organizationName(), QCoreApplication::applicationName()) ; settings.setValue ("geometry" , saveGeometry ()); }
读取配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void MainWindow::readSettings () { QSettings settings (QCoreApplication::organizationName(), QCoreApplication::applicationName()) ; const QByteArray geometry = settings.value ("geometry" , QByteArray ()).toByteArray (); if (geometry.isEmpty ()) { const QRect availableGeometry = QApplication::desktop ()->availableGeometry (this ); resize (availableGeometry.width () / 3 , availableGeometry.height () / 2 ); move ((availableGeometry.width () - width ()) / 2 , (availableGeometry.height () - height ()) / 2 ); } else { restoreGeometry (geometry); } }
在初始化的时候读取配置就好了,在窗口结束的时候写入配置
此外,在main.cpp里面设置版本信息
1 2 3 QCoreApplication::setOrganizationName ("Fyind Inc" ); QCoreApplication::setApplicationName ("SimpleNotepad" ); QCoreApplication::setApplicationVersion ("0.0.1" );
添加终端支持
1 2 3 4 5 6 7 8 9 10 11 12 QCommandLineParser parser; parser.setApplicationDescription (QCoreApplication::applicationName ()); parser.addHelpOption (); parser.addVersionOption (); parser.addPositionalArgument ("file" , "The file to open." ); parser.process (app); MainWindow mainWin; if (!parser.positionalArguments ().isEmpty ()) mainWin.loadFile (parser.positionalArguments ().first ()); mainWin.show ();